001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.hbtop.screen.top;
019
020import static org.apache.hadoop.hbase.hbtop.Record.entry;
021import static org.mockito.ArgumentMatchers.any;
022import static org.mockito.ArgumentMatchers.argThat;
023import static org.mockito.Mockito.inOrder;
024import static org.mockito.Mockito.verify;
025import static org.mockito.Mockito.when;
026
027import java.util.Arrays;
028import java.util.List;
029import java.util.stream.Collectors;
030import org.apache.hadoop.hbase.HBaseClassTestRule;
031import org.apache.hadoop.hbase.hbtop.Record;
032import org.apache.hadoop.hbase.hbtop.field.Field;
033import org.apache.hadoop.hbase.hbtop.field.FieldInfo;
034import org.apache.hadoop.hbase.hbtop.terminal.TerminalSize;
035import org.apache.hadoop.hbase.testclassification.SmallTests;
036import org.junit.Before;
037import org.junit.ClassRule;
038import org.junit.Test;
039import org.junit.experimental.categories.Category;
040import org.junit.runner.RunWith;
041import org.mockito.InOrder;
042import org.mockito.Mock;
043import org.mockito.runners.MockitoJUnitRunner;
044
045@Category(SmallTests.class)
046@RunWith(MockitoJUnitRunner.class)
047public class TestTopScreenPresenter {
048
049  @ClassRule
050  public static final HBaseClassTestRule CLASS_RULE =
051    HBaseClassTestRule.forClass(TestTopScreenPresenter.class);
052
053  private static final List<FieldInfo> TEST_FIELD_INFOS = Arrays.asList(
054    new FieldInfo(Field.REGION, 10, true), new FieldInfo(Field.REQUEST_COUNT_PER_SECOND, 10, true),
055    new FieldInfo(Field.LOCALITY, 10, true));
056
057  private static final List<Record> TEST_RECORDS = Arrays.asList(
058    Record.ofEntries(entry(Field.REGION, "region1"), entry(Field.REQUEST_COUNT_PER_SECOND, 1L),
059      entry(Field.LOCALITY, 0.3f)),
060    Record.ofEntries(entry(Field.REGION, "region2"), entry(Field.REQUEST_COUNT_PER_SECOND, 2L),
061      entry(Field.LOCALITY, 0.2f)),
062    Record.ofEntries(entry(Field.REGION, "region3"), entry(Field.REQUEST_COUNT_PER_SECOND, 3L),
063      entry(Field.LOCALITY, 0.1f)));
064
065  private static final Summary TEST_SUMMARY = new Summary("00:00:01", "3.0.0-SNAPSHOT",
066    "01234567-89ab-cdef-0123-456789abcdef", 3, 2, 1, 6, 1, 3.0, 300);
067
068  @Mock
069  private TopScreenView topScreenView;
070
071  @Mock
072  private TopScreenModel topScreenModel;
073
074  private TopScreenPresenter topScreenPresenter;
075
076  @Before
077  public void setup() {
078    when(topScreenView.getTerminalSize()).thenReturn(new TerminalSize(100, 100));
079    when(topScreenView.getPageSize()).thenReturn(100);
080
081    when(topScreenModel.getFieldInfos()).thenReturn(TEST_FIELD_INFOS);
082    when(topScreenModel.getFields())
083      .thenReturn(TEST_FIELD_INFOS.stream().map(FieldInfo::getField).collect(Collectors.toList()));
084    when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS);
085    when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY);
086
087    topScreenPresenter =
088      new TopScreenPresenter(topScreenView, 3000, topScreenModel, null, Long.MAX_VALUE);
089  }
090
091  @Test
092  public void testRefresh() {
093    topScreenPresenter.init();
094    topScreenPresenter.refresh(true);
095
096    verify(topScreenView).showTopScreen(argThat(this::assertSummary), argThat(this::assertHeaders),
097      argThat(this::assertRecords),
098      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, 0)));
099  }
100
101  @Test
102  public void testVerticalScrolling() {
103    topScreenPresenter.init();
104    topScreenPresenter.refresh(true);
105
106    topScreenPresenter.arrowDown();
107    topScreenPresenter.arrowDown();
108    topScreenPresenter.arrowDown();
109
110    topScreenPresenter.arrowDown();
111    topScreenPresenter.arrowDown();
112    topScreenPresenter.arrowDown();
113
114    topScreenPresenter.arrowUp();
115    topScreenPresenter.arrowUp();
116    topScreenPresenter.arrowUp();
117
118    topScreenPresenter.pageDown();
119    topScreenPresenter.pageDown();
120
121    topScreenPresenter.pageUp();
122    topScreenPresenter.pageUp();
123
124    InOrder inOrder = inOrder(topScreenView);
125    verifyVerticalScrolling(inOrder, 0);
126
127    verifyVerticalScrolling(inOrder, 1);
128    verifyVerticalScrolling(inOrder, 2);
129    verifyVerticalScrolling(inOrder, 2);
130
131    verifyVerticalScrolling(inOrder, 1);
132    verifyVerticalScrolling(inOrder, 0);
133    verifyVerticalScrolling(inOrder, 0);
134
135    verifyVerticalScrolling(inOrder, 2);
136    verifyVerticalScrolling(inOrder, 2);
137
138    verifyVerticalScrolling(inOrder, 0);
139    verifyVerticalScrolling(inOrder, 0);
140  }
141
142  private void verifyVerticalScrolling(InOrder inOrder, int expectedSelectedRecodeIndex) {
143    inOrder.verify(topScreenView).showTopScreen(any(), any(), any(),
144      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, expectedSelectedRecodeIndex)));
145  }
146
147  @Test
148  public void testHorizontalScrolling() {
149    topScreenPresenter.init();
150    topScreenPresenter.refresh(true);
151
152    topScreenPresenter.arrowRight();
153    topScreenPresenter.arrowRight();
154    topScreenPresenter.arrowRight();
155
156    topScreenPresenter.arrowLeft();
157    topScreenPresenter.arrowLeft();
158    topScreenPresenter.arrowLeft();
159
160    topScreenPresenter.end();
161    topScreenPresenter.end();
162
163    topScreenPresenter.home();
164    topScreenPresenter.home();
165
166    InOrder inOrder = inOrder(topScreenView);
167    verifyHorizontalScrolling(inOrder, 3);
168
169    verifyHorizontalScrolling(inOrder, 2);
170    verifyHorizontalScrolling(inOrder, 1);
171    verifyHorizontalScrolling(inOrder, 1);
172
173    verifyHorizontalScrolling(inOrder, 2);
174    verifyHorizontalScrolling(inOrder, 3);
175    verifyHorizontalScrolling(inOrder, 3);
176
177    verifyHorizontalScrolling(inOrder, 1);
178    verifyHorizontalScrolling(inOrder, 1);
179
180    verifyHorizontalScrolling(inOrder, 3);
181    verifyHorizontalScrolling(inOrder, 3);
182  }
183
184  private void verifyHorizontalScrolling(InOrder inOrder, int expectedHeaderCount) {
185    inOrder.verify(topScreenView).showTopScreen(any(),
186      argThat(headers -> headers.size() == expectedHeaderCount), any(), any());
187  }
188
189  private boolean assertSummary(Summary actual) {
190    return actual.getCurrentTime().equals(TEST_SUMMARY.getCurrentTime())
191      && actual.getVersion().equals(TEST_SUMMARY.getVersion())
192      && actual.getClusterId().equals(TEST_SUMMARY.getClusterId())
193      && actual.getServers() == TEST_SUMMARY.getServers()
194      && actual.getLiveServers() == TEST_SUMMARY.getLiveServers()
195      && actual.getDeadServers() == TEST_SUMMARY.getDeadServers()
196      && actual.getRegionCount() == TEST_SUMMARY.getRegionCount()
197      && actual.getRitCount() == TEST_SUMMARY.getRitCount()
198      && actual.getAverageLoad() == TEST_SUMMARY.getAverageLoad()
199      && actual.getAggregateRequestPerSecond() == TEST_SUMMARY.getAggregateRequestPerSecond();
200  }
201
202  private boolean assertHeaders(List<Header> actual) {
203    List<Header> expected = TEST_FIELD_INFOS.stream()
204      .map(fi -> new Header(fi.getField(), fi.getDefaultLength())).collect(Collectors.toList());
205
206    if (actual.size() != expected.size()) {
207      return false;
208    }
209
210    for (int i = 0; i < actual.size(); i++) {
211      if (actual.get(i).getField() != expected.get(i).getField()) {
212        return false;
213      }
214      if (actual.get(i).getLength() != expected.get(i).getLength()) {
215        return false;
216      }
217    }
218
219    return true;
220  }
221
222  private boolean assertRecords(List<Record> actual) {
223    if (actual.size() != TEST_RECORDS.size()) {
224      return false;
225    }
226
227    for (int i = 0; i < actual.size(); i++) {
228      if (!assertRecord(actual.get(i), TEST_RECORDS.get(i))) {
229        return false;
230      }
231    }
232
233    return true;
234  }
235
236  private boolean assertSelectedRecord(Record actual, int expectedSelectedRecodeIndex) {
237    return assertRecord(actual, TEST_RECORDS.get(expectedSelectedRecodeIndex));
238  }
239
240  private boolean assertRecord(Record actual, Record expected) {
241    return actual.get(Field.REGION).equals(expected.get(Field.REGION))
242      && actual.get(Field.REQUEST_COUNT_PER_SECOND)
243        .equals(expected.get(Field.REQUEST_COUNT_PER_SECOND))
244      && actual.get(Field.LOCALITY).equals(expected.get(Field.LOCALITY));
245  }
246}