1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20 package org.apache.hadoop.hbase.tool;
21
22 import org.apache.hadoop.hbase.HBaseTestingUtility;
23 import org.apache.hadoop.hbase.HColumnDescriptor;
24 import org.apache.hadoop.hbase.HConstants;
25 import org.apache.hadoop.hbase.HRegionInfo;
26 import org.apache.hadoop.hbase.ServerName;
27 import org.apache.hadoop.hbase.TableName;
28 import org.apache.hadoop.hbase.client.HTable;
29 import org.apache.hadoop.hbase.client.Put;
30 import org.apache.hadoop.hbase.client.Table;
31 import org.apache.hadoop.hbase.testclassification.MediumTests;
32 import org.apache.hadoop.hbase.util.Bytes;
33 import org.apache.hadoop.util.ToolRunner;
34 import org.apache.log4j.Appender;
35 import org.apache.log4j.LogManager;
36 import org.apache.log4j.spi.LoggingEvent;
37 import com.google.common.collect.Iterables;
38 import org.junit.After;
39 import org.junit.Before;
40 import org.junit.Ignore;
41 import org.junit.Test;
42 import org.junit.experimental.categories.Category;
43 import org.junit.runner.RunWith;
44 import org.mockito.ArgumentMatcher;
45 import org.mockito.Mock;
46 import org.mockito.runners.MockitoJUnitRunner;
47
48 import java.util.concurrent.ExecutorService;
49 import java.util.concurrent.ScheduledThreadPoolExecutor;
50
51 import static org.junit.Assert.assertNotEquals;
52 import static org.mockito.Matchers.anyLong;
53 import static org.mockito.Matchers.eq;
54 import static org.mockito.Matchers.isA;
55 import static org.mockito.Matchers.argThat;
56 import static org.junit.Assert.assertEquals;
57 import static org.mockito.Mockito.*;
58
59 @RunWith(MockitoJUnitRunner.class)
60 @Category({MediumTests.class})
61 public class TestCanaryTool {
62
63 private HBaseTestingUtility testingUtility;
64 private static final byte[] FAMILY = Bytes.toBytes("f");
65 private static final byte[] COLUMN = Bytes.toBytes("col");
66
67 @Before
68 public void setUp() throws Exception {
69 testingUtility = new HBaseTestingUtility();
70 testingUtility.startMiniCluster();
71 LogManager.getRootLogger().addAppender(mockAppender);
72 }
73
74 @After
75 public void tearDown() throws Exception {
76 testingUtility.shutdownMiniCluster();
77 LogManager.getRootLogger().removeAppender(mockAppender);
78 }
79
80 @Mock
81 Appender mockAppender;
82
83 @Test
84 public void testBasicZookeeperCanaryWorks() throws Exception {
85 final String[] args = { "-t", "10000", "-zookeeper" };
86 testZookeeperCanaryWithArgs(args);
87 }
88
89 @Test
90 public void testZookeeperCanaryPermittedFailuresArgumentWorks() throws Exception {
91 final String[] args = { "-t", "10000", "-zookeeper", "-treatFailureAsError", "-permittedZookeeperFailures", "1" };
92 testZookeeperCanaryWithArgs(args);
93 }
94
95 @Test
96 public void testBasicCanaryWorks() throws Exception {
97 TableName tableName = TableName.valueOf("testTable");
98 HTable table = testingUtility.createTable(tableName, new byte[][] { FAMILY });
99
100 for (int i=0; i<1000; i++) {
101 byte[] iBytes = Bytes.toBytes(i);
102 Put p = new Put(iBytes);
103 p.addColumn(FAMILY, COLUMN, iBytes);
104 table.put(p);
105 }
106 ExecutorService executor = new ScheduledThreadPoolExecutor(1);
107 Canary.RegionStdOutSink sink = spy(new Canary.RegionStdOutSink());
108 Canary canary = new Canary(executor, sink);
109 String[] args = { "-writeSniffing", "-t", "10000", "testTable" };
110 assertEquals(0, ToolRunner.run(testingUtility.getConfiguration(), canary, args));
111 assertEquals("verify no read error count", 0, canary.getReadFailures().size());
112 assertEquals("verify no write error count", 0, canary.getWriteFailures().size());
113 verify(sink, atLeastOnce()).publishReadTiming(isA(ServerName.class), isA(HRegionInfo.class), isA(HColumnDescriptor.class), anyLong());
114 }
115
116 @Test
117 @Ignore("Intermittent argument matching failures, see HBASE-18813")
118 public void testReadTableTimeouts() throws Exception {
119 final TableName [] tableNames = new TableName[2];
120 tableNames[0] = TableName.valueOf("testReadTableTimeouts1");
121 tableNames[1] = TableName.valueOf("testReadTableTimeouts2");
122
123 for (int j = 0; j<2; j++) {
124 Table table = testingUtility.createTable(tableNames[j], new byte[][] { FAMILY });
125
126 for (int i=0; i<1000; i++) {
127 byte[] iBytes = Bytes.toBytes(i + j);
128 Put p = new Put(iBytes);
129 p.addColumn(FAMILY, COLUMN, iBytes);
130 table.put(p);
131 }
132 }
133 ExecutorService executor = new ScheduledThreadPoolExecutor(1);
134 Canary.RegionStdOutSink sink = spy(new Canary.RegionStdOutSink());
135 Canary canary = new Canary(executor, sink);
136 String configuredTimeoutStr = tableNames[0].getNameAsString() + "=" + Long.MAX_VALUE + "," +
137 tableNames[1].getNameAsString() + "=0";
138 String[] args = { "-readTableTimeouts", configuredTimeoutStr, tableNames[0].getNameAsString(), tableNames[1].getNameAsString()};
139 assertEquals(0, ToolRunner.run(testingUtility.getConfiguration(), canary, args));
140 verify(sink, times(tableNames.length)).initializeAndGetReadLatencyForTable(isA(String.class));
141 for (int i=0; i<2; i++) {
142 assertNotEquals("verify non-null read latency", null, sink.getReadLatencyMap().get(tableNames[i].getNameAsString()));
143 assertNotEquals("verify non-zero read latency", 0L, sink.getReadLatencyMap().get(tableNames[i].getNameAsString()));
144 }
145
146 verify(mockAppender, times(1)).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
147 @Override
148 public boolean matches(Object argument) {
149 return ((LoggingEvent) argument).getRenderedMessage().contains("exceeded the configured read timeout.");
150 }
151 }));
152 verify(mockAppender, times(2)).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
153 @Override
154 public boolean matches(Object argument) {
155 return ((LoggingEvent) argument).getRenderedMessage().contains("The configured read timeout was");
156 }
157 }));
158 }
159
160 @Test
161 @Ignore("Intermittent argument matching failures, see HBASE-18813")
162 public void testWriteTableTimeout() throws Exception {
163 ExecutorService executor = new ScheduledThreadPoolExecutor(1);
164 Canary.RegionStdOutSink sink = spy(new Canary.RegionStdOutSink());
165 Canary canary = new Canary(executor, sink);
166 String[] args = { "-writeSniffing", "-writeTableTimeout", String.valueOf(Long.MAX_VALUE)};
167 assertEquals(0, ToolRunner.run(testingUtility.getConfiguration(), canary, args));
168 assertNotEquals("verify non-null write latency", null, sink.getWriteLatency());
169 assertNotEquals("verify non-zero write latency", 0L, sink.getWriteLatency());
170 verify(mockAppender, times(1)).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
171 @Override
172 public boolean matches(Object argument) {
173 return ((LoggingEvent) argument).getRenderedMessage().contains("The configured write timeout was");
174 }
175 }));
176 }
177
178
179 @Test
180 public void testRegionserverNoRegions() throws Exception {
181 runRegionserverCanary();
182 verify(mockAppender).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
183 @Override
184 public boolean matches(Object argument) {
185 return ((LoggingEvent) argument).getRenderedMessage().contains("Regionserver not serving any regions");
186 }
187 }));
188 }
189
190
191 @Test
192 public void testRegionserverWithRegions() throws Exception {
193 TableName tableName = TableName.valueOf("testTable");
194 testingUtility.createTable(tableName, new byte[][] { FAMILY });
195 runRegionserverCanary();
196 verify(mockAppender, never()).doAppend(argThat(new ArgumentMatcher<LoggingEvent>() {
197 @Override
198 public boolean matches(Object argument) {
199 return ((LoggingEvent) argument).getRenderedMessage().contains("Regionserver not serving any regions");
200 }
201 }));
202 }
203
204 @Test
205 public void testRawScanConfig() throws Exception {
206 TableName tableName = TableName.valueOf("testTableRawScan");
207 Table table = testingUtility.createTable(tableName, new byte[][] { FAMILY });
208
209 for (int i=0; i<1000; i++) {
210 byte[] iBytes = Bytes.toBytes(i);
211 Put p = new Put(iBytes);
212 p.addColumn(FAMILY, COLUMN, iBytes);
213 table.put(p);
214 }
215 ExecutorService executor = new ScheduledThreadPoolExecutor(1);
216 Canary.RegionStdOutSink sink = spy(new Canary.RegionStdOutSink());
217 Canary canary = new Canary(executor, sink);
218 String[] args = { "-t", "10000", "testTableRawScan" };
219 org.apache.hadoop.conf.Configuration conf = new org.apache.hadoop.conf.Configuration(testingUtility.getConfiguration());
220 conf.setBoolean(HConstants.HBASE_CANARY_READ_RAW_SCAN_KEY, true);
221 assertEquals(0, ToolRunner.run(conf, canary, args));
222 verify(sink, atLeastOnce())
223 .publishReadTiming(isA(ServerName.class), isA(HRegionInfo.class), isA(HColumnDescriptor.class), anyLong());
224 assertEquals("verify no read error count", 0, canary.getReadFailures().size());
225 }
226
227 private void runRegionserverCanary() throws Exception {
228 ExecutorService executor = new ScheduledThreadPoolExecutor(1);
229 Canary canary = new Canary(executor, new Canary.RegionServerStdOutSink());
230 String[] args = { "-t", "10000", "-regionserver"};
231 assertEquals(0, ToolRunner.run(testingUtility.getConfiguration(), canary, args));
232 assertEquals("verify no read error count", 0, canary.getReadFailures().size());
233 }
234
235 private void testZookeeperCanaryWithArgs(String[] args) throws Exception {
236 Integer port =
237 Iterables.getOnlyElement(testingUtility.getZkCluster().getClientPortList(), null);
238 testingUtility.getConfiguration().set(HConstants.ZOOKEEPER_QUORUM,
239 "localhost:" + port + "/hbase");
240 ExecutorService executor = new ScheduledThreadPoolExecutor(2);
241 Canary.ZookeeperStdOutSink sink = spy(new Canary.ZookeeperStdOutSink());
242 Canary canary = new Canary(executor, sink);
243 assertEquals(0, ToolRunner.run(testingUtility.getConfiguration(), canary, args));
244
245 String baseZnode = testingUtility.getConfiguration()
246 .get(HConstants.ZOOKEEPER_ZNODE_PARENT, HConstants.DEFAULT_ZOOKEEPER_ZNODE_PARENT);
247 verify(sink, atLeastOnce())
248 .publishReadTiming(eq(baseZnode), eq("localhost:" + port), anyLong());
249 }
250 }