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
046@Category(SmallTests.class)
047@RunWith(MockitoJUnitRunner.class)
048public class TopScreenPresenterTest {
049
050  @ClassRule
051  public static final HBaseClassTestRule CLASS_RULE =
052    HBaseClassTestRule.forClass(TopScreenPresenterTest.class);
053
054  private static final List<FieldInfo> TEST_FIELD_INFOS = Arrays.asList(
055    new FieldInfo(Field.REGION, 10, true),
056    new FieldInfo(Field.REQUEST_COUNT_PER_SECOND, 10, true),
057    new FieldInfo(Field.LOCALITY, 10, true)
058  );
059
060  private static final List<Record> TEST_RECORDS = Arrays.asList(
061    Record.ofEntries(
062      entry(Field.REGION, "region1"),
063      entry(Field.REQUEST_COUNT_PER_SECOND, 1L),
064      entry(Field.LOCALITY, 0.3f)),
065    Record.ofEntries(
066      entry(Field.REGION, "region2"),
067      entry(Field.REQUEST_COUNT_PER_SECOND, 2L),
068      entry(Field.LOCALITY, 0.2f)),
069    Record.ofEntries(
070      entry(Field.REGION, "region3"),
071      entry(Field.REQUEST_COUNT_PER_SECOND, 3L),
072      entry(Field.LOCALITY, 0.1f))
073  );
074
075  private static final Summary TEST_SUMMARY = new Summary(
076    "00:00:01", "3.0.0-SNAPSHOT", "01234567-89ab-cdef-0123-456789abcdef",
077    3, 2, 1, 6, 1, 3.0, 300);
078
079  @Mock
080  private TopScreenView topScreenView;
081
082  @Mock
083  private TopScreenModel topScreenModel;
084
085  private TopScreenPresenter topScreenPresenter;
086
087  @Before
088  public void setup() {
089    when(topScreenView.getTerminalSize()).thenReturn(new TerminalSize(100, 100));
090    when(topScreenView.getPageSize()).thenReturn(100);
091
092    when(topScreenModel.getFieldInfos()).thenReturn(TEST_FIELD_INFOS);
093    when(topScreenModel.getFields()).thenReturn(TEST_FIELD_INFOS.stream()
094      .map(FieldInfo::getField).collect(Collectors.toList()));
095    when(topScreenModel.getRecords()).thenReturn(TEST_RECORDS);
096    when(topScreenModel.getSummary()).thenReturn(TEST_SUMMARY);
097
098    topScreenPresenter = new TopScreenPresenter(topScreenView, 3000, topScreenModel);
099  }
100
101  @Test
102  public void testRefresh() {
103    topScreenPresenter.init();
104    topScreenPresenter.refresh(true);
105
106    verify(topScreenView).showTopScreen(argThat(this::assertSummary),
107      argThat(this::assertHeaders), argThat(this::assertRecords),
108      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, 0)));
109  }
110
111  @Test
112  public void testVerticalScrolling() {
113    topScreenPresenter.init();
114    topScreenPresenter.refresh(true);
115
116    topScreenPresenter.arrowDown();
117    topScreenPresenter.arrowDown();
118    topScreenPresenter.arrowDown();
119
120    topScreenPresenter.arrowDown();
121    topScreenPresenter.arrowDown();
122    topScreenPresenter.arrowDown();
123
124    topScreenPresenter.arrowUp();
125    topScreenPresenter.arrowUp();
126    topScreenPresenter.arrowUp();
127
128    topScreenPresenter.pageDown();
129    topScreenPresenter.pageDown();
130
131    topScreenPresenter.pageUp();
132    topScreenPresenter.pageUp();
133
134    InOrder inOrder = inOrder(topScreenView);
135    verifyVerticalScrolling(inOrder, 0);
136
137    verifyVerticalScrolling(inOrder, 1);
138    verifyVerticalScrolling(inOrder, 2);
139    verifyVerticalScrolling(inOrder, 2);
140
141    verifyVerticalScrolling(inOrder, 1);
142    verifyVerticalScrolling(inOrder, 0);
143    verifyVerticalScrolling(inOrder, 0);
144
145    verifyVerticalScrolling(inOrder, 2);
146    verifyVerticalScrolling(inOrder, 2);
147
148    verifyVerticalScrolling(inOrder, 0);
149    verifyVerticalScrolling(inOrder, 0);
150  }
151
152  private void verifyVerticalScrolling(InOrder inOrder, int expectedSelectedRecodeIndex) {
153    inOrder.verify(topScreenView).showTopScreen(any(), any(), any(),
154      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, expectedSelectedRecodeIndex)));
155  }
156
157  @Test
158  public void testHorizontalScrolling() {
159    topScreenPresenter.init();
160    topScreenPresenter.refresh(true);
161
162    topScreenPresenter.arrowRight();
163    topScreenPresenter.arrowRight();
164    topScreenPresenter.arrowRight();
165
166    topScreenPresenter.arrowLeft();
167    topScreenPresenter.arrowLeft();
168    topScreenPresenter.arrowLeft();
169
170    topScreenPresenter.end();
171    topScreenPresenter.end();
172
173    topScreenPresenter.home();
174    topScreenPresenter.home();
175
176    InOrder inOrder = inOrder(topScreenView);
177    verifyHorizontalScrolling(inOrder, 3);
178
179    verifyHorizontalScrolling(inOrder, 2);
180    verifyHorizontalScrolling(inOrder, 1);
181    verifyHorizontalScrolling(inOrder, 1);
182
183    verifyHorizontalScrolling(inOrder, 2);
184    verifyHorizontalScrolling(inOrder, 3);
185    verifyHorizontalScrolling(inOrder, 3);
186
187    verifyHorizontalScrolling(inOrder, 1);
188    verifyHorizontalScrolling(inOrder, 1);
189
190    verifyHorizontalScrolling(inOrder, 3);
191    verifyHorizontalScrolling(inOrder, 3);
192  }
193
194  private void verifyHorizontalScrolling(InOrder inOrder, int expectedHeaderCount) {
195    inOrder.verify(topScreenView).showTopScreen(any(),
196      argThat(headers -> headers.size() == expectedHeaderCount), any(), any());
197  }
198
199  private boolean assertSummary(Summary actual) {
200    return actual.getCurrentTime().equals(TEST_SUMMARY.getCurrentTime())
201      && actual.getVersion().equals(TEST_SUMMARY.getVersion())
202      && actual.getClusterId().equals(TEST_SUMMARY.getClusterId())
203      && actual.getServers() == TEST_SUMMARY.getServers()
204      && actual.getLiveServers() == TEST_SUMMARY.getLiveServers()
205      && actual.getDeadServers() == TEST_SUMMARY.getDeadServers()
206      && actual.getRegionCount() == TEST_SUMMARY.getRegionCount()
207      && actual.getRitCount() == TEST_SUMMARY.getRitCount()
208      && actual.getAverageLoad() == TEST_SUMMARY.getAverageLoad()
209      && actual.getAggregateRequestPerSecond() == TEST_SUMMARY.getAggregateRequestPerSecond();
210  }
211
212  private boolean assertHeaders(List<Header> actual) {
213    List<Header> expected =
214      TEST_FIELD_INFOS.stream().map(fi -> new Header(fi.getField(), fi.getDefaultLength()))
215        .collect(Collectors.toList());
216
217    if (actual.size() != expected.size()) {
218      return false;
219    }
220
221    for (int i = 0; i < actual.size(); i++) {
222      if (actual.get(i).getField() != expected.get(i).getField()) {
223        return false;
224      }
225      if (actual.get(i).getLength() != expected.get(i).getLength()) {
226        return false;
227      }
228    }
229
230    return true;
231  }
232
233  private boolean assertRecords(List<Record> actual) {
234    if (actual.size() != TEST_RECORDS.size()) {
235      return false;
236    }
237
238    for (int i = 0; i < actual.size(); i++) {
239      if (!assertRecord(actual.get(i), TEST_RECORDS.get(i))) {
240        return false;
241      }
242    }
243
244    return true;
245  }
246
247  private boolean assertSelectedRecord(Record actual, int expectedSelectedRecodeIndex) {
248    return assertRecord(actual, TEST_RECORDS.get(expectedSelectedRecodeIndex));
249  }
250
251  private boolean assertRecord(Record actual, Record expected) {
252    return actual.get(Field.REGION).equals(expected.get(Field.REGION)) && actual
253      .get(Field.REQUEST_COUNT_PER_SECOND).equals(expected.get(Field.REQUEST_COUNT_PER_SECOND))
254      && actual.get(Field.LOCALITY).equals(expected.get(Field.LOCALITY));
255  }
256}