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 TestTopScreenPresenter {
049
050  @ClassRule
051  public static final HBaseClassTestRule CLASS_RULE =
052    HBaseClassTestRule.forClass(TestTopScreenPresenter.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      null, Long.MAX_VALUE);
100  }
101
102  @Test
103  public void testRefresh() {
104    topScreenPresenter.init();
105    topScreenPresenter.refresh(true);
106
107    verify(topScreenView).showTopScreen(argThat(this::assertSummary),
108      argThat(this::assertHeaders), argThat(this::assertRecords),
109      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, 0)));
110  }
111
112  @Test
113  public void testVerticalScrolling() {
114    topScreenPresenter.init();
115    topScreenPresenter.refresh(true);
116
117    topScreenPresenter.arrowDown();
118    topScreenPresenter.arrowDown();
119    topScreenPresenter.arrowDown();
120
121    topScreenPresenter.arrowDown();
122    topScreenPresenter.arrowDown();
123    topScreenPresenter.arrowDown();
124
125    topScreenPresenter.arrowUp();
126    topScreenPresenter.arrowUp();
127    topScreenPresenter.arrowUp();
128
129    topScreenPresenter.pageDown();
130    topScreenPresenter.pageDown();
131
132    topScreenPresenter.pageUp();
133    topScreenPresenter.pageUp();
134
135    InOrder inOrder = inOrder(topScreenView);
136    verifyVerticalScrolling(inOrder, 0);
137
138    verifyVerticalScrolling(inOrder, 1);
139    verifyVerticalScrolling(inOrder, 2);
140    verifyVerticalScrolling(inOrder, 2);
141
142    verifyVerticalScrolling(inOrder, 1);
143    verifyVerticalScrolling(inOrder, 0);
144    verifyVerticalScrolling(inOrder, 0);
145
146    verifyVerticalScrolling(inOrder, 2);
147    verifyVerticalScrolling(inOrder, 2);
148
149    verifyVerticalScrolling(inOrder, 0);
150    verifyVerticalScrolling(inOrder, 0);
151  }
152
153  private void verifyVerticalScrolling(InOrder inOrder, int expectedSelectedRecodeIndex) {
154    inOrder.verify(topScreenView).showTopScreen(any(), any(), any(),
155      argThat(selectedRecord -> assertSelectedRecord(selectedRecord, expectedSelectedRecodeIndex)));
156  }
157
158  @Test
159  public void testHorizontalScrolling() {
160    topScreenPresenter.init();
161    topScreenPresenter.refresh(true);
162
163    topScreenPresenter.arrowRight();
164    topScreenPresenter.arrowRight();
165    topScreenPresenter.arrowRight();
166
167    topScreenPresenter.arrowLeft();
168    topScreenPresenter.arrowLeft();
169    topScreenPresenter.arrowLeft();
170
171    topScreenPresenter.end();
172    topScreenPresenter.end();
173
174    topScreenPresenter.home();
175    topScreenPresenter.home();
176
177    InOrder inOrder = inOrder(topScreenView);
178    verifyHorizontalScrolling(inOrder, 3);
179
180    verifyHorizontalScrolling(inOrder, 2);
181    verifyHorizontalScrolling(inOrder, 1);
182    verifyHorizontalScrolling(inOrder, 1);
183
184    verifyHorizontalScrolling(inOrder, 2);
185    verifyHorizontalScrolling(inOrder, 3);
186    verifyHorizontalScrolling(inOrder, 3);
187
188    verifyHorizontalScrolling(inOrder, 1);
189    verifyHorizontalScrolling(inOrder, 1);
190
191    verifyHorizontalScrolling(inOrder, 3);
192    verifyHorizontalScrolling(inOrder, 3);
193  }
194
195  private void verifyHorizontalScrolling(InOrder inOrder, int expectedHeaderCount) {
196    inOrder.verify(topScreenView).showTopScreen(any(),
197      argThat(headers -> headers.size() == expectedHeaderCount), any(), any());
198  }
199
200  private boolean assertSummary(Summary actual) {
201    return actual.getCurrentTime().equals(TEST_SUMMARY.getCurrentTime())
202      && actual.getVersion().equals(TEST_SUMMARY.getVersion())
203      && actual.getClusterId().equals(TEST_SUMMARY.getClusterId())
204      && actual.getServers() == TEST_SUMMARY.getServers()
205      && actual.getLiveServers() == TEST_SUMMARY.getLiveServers()
206      && actual.getDeadServers() == TEST_SUMMARY.getDeadServers()
207      && actual.getRegionCount() == TEST_SUMMARY.getRegionCount()
208      && actual.getRitCount() == TEST_SUMMARY.getRitCount()
209      && actual.getAverageLoad() == TEST_SUMMARY.getAverageLoad()
210      && actual.getAggregateRequestPerSecond() == TEST_SUMMARY.getAggregateRequestPerSecond();
211  }
212
213  private boolean assertHeaders(List<Header> actual) {
214    List<Header> expected =
215      TEST_FIELD_INFOS.stream().map(fi -> new Header(fi.getField(), fi.getDefaultLength()))
216        .collect(Collectors.toList());
217
218    if (actual.size() != expected.size()) {
219      return false;
220    }
221
222    for (int i = 0; i < actual.size(); i++) {
223      if (actual.get(i).getField() != expected.get(i).getField()) {
224        return false;
225      }
226      if (actual.get(i).getLength() != expected.get(i).getLength()) {
227        return false;
228      }
229    }
230
231    return true;
232  }
233
234  private boolean assertRecords(List<Record> actual) {
235    if (actual.size() != TEST_RECORDS.size()) {
236      return false;
237    }
238
239    for (int i = 0; i < actual.size(); i++) {
240      if (!assertRecord(actual.get(i), TEST_RECORDS.get(i))) {
241        return false;
242      }
243    }
244
245    return true;
246  }
247
248  private boolean assertSelectedRecord(Record actual, int expectedSelectedRecodeIndex) {
249    return assertRecord(actual, TEST_RECORDS.get(expectedSelectedRecodeIndex));
250  }
251
252  private boolean assertRecord(Record actual, Record expected) {
253    return actual.get(Field.REGION).equals(expected.get(Field.REGION)) && actual
254      .get(Field.REQUEST_COUNT_PER_SECOND).equals(expected.get(Field.REQUEST_COUNT_PER_SECOND))
255      && actual.get(Field.LOCALITY).equals(expected.get(Field.LOCALITY));
256  }
257}