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