View Javadoc

1   /*
2    *
3    * Licensed to the Apache Software Foundation (ASF) under one
4    * or more contributor license agreements.  See the NOTICE file
5    * distributed with this work for additional information
6    * regarding copyright ownership.  The ASF licenses this file
7    * to you under the Apache License, Version 2.0 (the
8    * "License"); you may not use this file except in compliance
9    * with the License.  You may obtain a copy of the License at
10   *
11   * http://www.apache.org/licenses/LICENSE-2.0
12   *
13   * Unless required by applicable law or agreed to in writing, software
14   * distributed under the License is distributed on an "AS IS" BASIS,
15   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16   * See the License for the specific language governing permissions and
17   * limitations under the License.
18   */
19  
20  package org.apache.hadoop.hbase.coprocessor;
21  
22  import static org.junit.Assert.assertFalse;
23  import static org.junit.Assert.assertNotNull;
24  import static org.junit.Assert.assertNull;
25  import static org.junit.Assert.assertTrue;
26  
27  import java.io.IOException;
28  import java.util.Arrays;
29  import java.util.Collection;
30  import java.util.List;
31  import java.util.Map;
32  import java.util.NavigableMap;
33  import java.util.concurrent.CountDownLatch;
34  
35  import org.apache.commons.logging.Log;
36  import org.apache.commons.logging.LogFactory;
37  import org.apache.hadoop.conf.Configuration;
38  import org.apache.hadoop.hbase.CoprocessorEnvironment;
39  import org.apache.hadoop.hbase.HBaseTestingUtility;
40  import org.apache.hadoop.hbase.HColumnDescriptor;
41  import org.apache.hadoop.hbase.HRegionInfo;
42  import org.apache.hadoop.hbase.HRegionLocation;
43  import org.apache.hadoop.hbase.HTableDescriptor;
44  import org.apache.hadoop.hbase.MiniHBaseCluster;
45  import org.apache.hadoop.hbase.NamespaceDescriptor;
46  import org.apache.hadoop.hbase.ProcedureInfo;
47  import org.apache.hadoop.hbase.ServerName;
48  import org.apache.hadoop.hbase.TableName;
49  import org.apache.hadoop.hbase.client.Admin;
50  import org.apache.hadoop.hbase.client.Connection;
51  import org.apache.hadoop.hbase.client.ConnectionFactory;
52  import org.apache.hadoop.hbase.client.HTable;
53  import org.apache.hadoop.hbase.client.RegionLocator;
54  import org.apache.hadoop.hbase.master.HMaster;
55  import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
56  import org.apache.hadoop.hbase.master.RegionPlan;
57  import org.apache.hadoop.hbase.master.procedure.MasterProcedureEnv;
58  import org.apache.hadoop.hbase.procedure2.ProcedureExecutor;
59  import org.apache.hadoop.hbase.protobuf.ProtobufUtil;
60  import org.apache.hadoop.hbase.protobuf.RequestConverter;
61  import org.apache.hadoop.hbase.protobuf.generated.HBaseProtos.SnapshotDescription;
62  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
63  import org.apache.hadoop.hbase.protobuf.generated.MasterProtos.GetTableNamesRequest;
64  import org.apache.hadoop.hbase.protobuf.generated.QuotaProtos.Quotas;
65  import org.apache.hadoop.hbase.regionserver.HRegionServer;
66  import org.apache.hadoop.hbase.testclassification.MediumTests;
67  import org.apache.hadoop.hbase.util.Bytes;
68  import org.apache.hadoop.hbase.util.Threads;
69  import org.junit.AfterClass;
70  import org.junit.BeforeClass;
71  import org.junit.Rule;
72  import org.junit.Test;
73  import org.junit.experimental.categories.Category;
74  import org.junit.rules.TestName;
75  
76  /**
77   * Tests invocation of the {@link org.apache.hadoop.hbase.coprocessor.MasterObserver}
78   * interface hooks at all appropriate times during normal HMaster operations.
79   */
80  @Category(MediumTests.class)
81  public class TestMasterObserver {
82    private static final Log LOG = LogFactory.getLog(TestMasterObserver.class);
83  
84    public static CountDownLatch tableCreationLatch = new CountDownLatch(1);
85    public static CountDownLatch tableDeletionLatch = new CountDownLatch(1);
86  
87    public static class CPMasterObserver implements MasterObserver {
88  
89      private boolean bypass = false;
90      private boolean preCreateTableCalled;
91      private boolean postCreateTableCalled;
92      private boolean preDeleteTableCalled;
93      private boolean postDeleteTableCalled;
94      private boolean preTruncateTableCalled;
95      private boolean postTruncateTableCalled;
96      private boolean preModifyTableCalled;
97      private boolean postModifyTableCalled;
98      private boolean preCreateNamespaceCalled;
99      private boolean postCreateNamespaceCalled;
100     private boolean preDeleteNamespaceCalled;
101     private boolean postDeleteNamespaceCalled;
102     private boolean preModifyNamespaceCalled;
103     private boolean postModifyNamespaceCalled;
104     private boolean preGetNamespaceDescriptorCalled;
105     private boolean postGetNamespaceDescriptorCalled;
106     private boolean preListNamespaceDescriptorsCalled;
107     private boolean postListNamespaceDescriptorsCalled;
108     private boolean preAddColumnCalled;
109     private boolean postAddColumnCalled;
110     private boolean preModifyColumnCalled;
111     private boolean postModifyColumnCalled;
112     private boolean preDeleteColumnCalled;
113     private boolean postDeleteColumnCalled;
114     private boolean preEnableTableCalled;
115     private boolean postEnableTableCalled;
116     private boolean preDisableTableCalled;
117     private boolean postDisableTableCalled;
118     private boolean preMoveCalled;
119     private boolean postMoveCalled;
120     private boolean preAssignCalled;
121     private boolean postAssignCalled;
122     private boolean preUnassignCalled;
123     private boolean postUnassignCalled;
124     private boolean preRegionOfflineCalled;
125     private boolean postRegionOfflineCalled;
126     private boolean preBalanceCalled;
127     private boolean postBalanceCalled;
128     private boolean preBalanceSwitchCalled;
129     private boolean postBalanceSwitchCalled;
130     private boolean preShutdownCalled;
131     private boolean preStopMasterCalled;
132     private boolean preMasterInitializationCalled;
133     private boolean postStartMasterCalled;
134     private boolean startCalled;
135     private boolean stopCalled;
136     private boolean preSnapshotCalled;
137     private boolean postSnapshotCalled;
138     private boolean preListSnapshotCalled;
139     private boolean postListSnapshotCalled;
140     private boolean preCloneSnapshotCalled;
141     private boolean postCloneSnapshotCalled;
142     private boolean preRestoreSnapshotCalled;
143     private boolean postRestoreSnapshotCalled;
144     private boolean preDeleteSnapshotCalled;
145     private boolean postDeleteSnapshotCalled;
146     private boolean preCreateTableHandlerCalled;
147     private boolean postCreateTableHandlerCalled;
148     private boolean preDeleteTableHandlerCalled;
149     private boolean postDeleteTableHandlerCalled;
150     private boolean preTruncateTableHandlerCalled;
151     private boolean postTruncateTableHandlerCalled;
152     private boolean preAddColumnHandlerCalled;
153     private boolean postAddColumnHandlerCalled;
154     private boolean preModifyColumnHandlerCalled;
155     private boolean postModifyColumnHandlerCalled;
156     private boolean preDeleteColumnHandlerCalled;
157     private boolean postDeleteColumnHandlerCalled;
158     private boolean preEnableTableHandlerCalled;
159     private boolean postEnableTableHandlerCalled;
160     private boolean preDisableTableHandlerCalled;
161     private boolean postDisableTableHandlerCalled;
162     private boolean preModifyTableHandlerCalled;
163     private boolean postModifyTableHandlerCalled;
164     private boolean preAbortProcedureCalled;
165     private boolean postAbortProcedureCalled;
166     private boolean preListProceduresCalled;
167     private boolean postListProceduresCalled;
168     private boolean preGetTableDescriptorsCalled;
169     private boolean postGetTableDescriptorsCalled;
170     private boolean postGetTableNamesCalled;
171     private boolean preGetTableNamesCalled;
172     private boolean preDispatchMergeCalled;
173     private boolean postDispatchMergeCalled;
174 
175     public void enableBypass(boolean bypass) {
176       this.bypass = bypass;
177     }
178 
179     public void resetStates() {
180       preCreateTableCalled = false;
181       postCreateTableCalled = false;
182       preDeleteTableCalled = false;
183       postDeleteTableCalled = false;
184       preTruncateTableCalled = false;
185       postTruncateTableCalled = false;
186       preModifyTableCalled = false;
187       postModifyTableCalled = false;
188       preCreateNamespaceCalled = false;
189       postCreateNamespaceCalled = false;
190       preDeleteNamespaceCalled = false;
191       postDeleteNamespaceCalled = false;
192       preModifyNamespaceCalled = false;
193       postModifyNamespaceCalled = false;
194       preGetNamespaceDescriptorCalled = false;
195       postGetNamespaceDescriptorCalled = false;
196       preListNamespaceDescriptorsCalled = false;
197       postListNamespaceDescriptorsCalled = false;
198       preAddColumnCalled = false;
199       postAddColumnCalled = false;
200       preModifyColumnCalled = false;
201       postModifyColumnCalled = false;
202       preDeleteColumnCalled = false;
203       postDeleteColumnCalled = false;
204       preEnableTableCalled = false;
205       postEnableTableCalled = false;
206       preDisableTableCalled = false;
207       postDisableTableCalled = false;
208       preAbortProcedureCalled = false;
209       postAbortProcedureCalled = false;
210       preListProceduresCalled = false;
211       postListProceduresCalled = false;
212       preMoveCalled= false;
213       postMoveCalled = false;
214       preAssignCalled = false;
215       postAssignCalled = false;
216       preUnassignCalled = false;
217       postUnassignCalled = false;
218       preRegionOfflineCalled = false;
219       postRegionOfflineCalled = false;
220       preBalanceCalled = false;
221       postBalanceCalled = false;
222       preBalanceSwitchCalled = false;
223       postBalanceSwitchCalled = false;
224       preSnapshotCalled = false;
225       postSnapshotCalled = false;
226       preListSnapshotCalled = false;
227       postListSnapshotCalled = false;
228       preCloneSnapshotCalled = false;
229       postCloneSnapshotCalled = false;
230       preRestoreSnapshotCalled = false;
231       postRestoreSnapshotCalled = false;
232       preDeleteSnapshotCalled = false;
233       postDeleteSnapshotCalled = false;
234       preCreateTableHandlerCalled = false;
235       postCreateTableHandlerCalled = false;
236       preDeleteTableHandlerCalled = false;
237       postDeleteTableHandlerCalled = false;
238       preTruncateTableHandlerCalled = false;
239       postTruncateTableHandlerCalled = false;
240       preModifyTableHandlerCalled = false;
241       postModifyTableHandlerCalled = false;
242       preAddColumnHandlerCalled = false;
243       postAddColumnHandlerCalled = false;
244       preModifyColumnHandlerCalled = false;
245       postModifyColumnHandlerCalled = false;
246       preDeleteColumnHandlerCalled = false;
247       postDeleteColumnHandlerCalled = false;
248       preEnableTableHandlerCalled = false;
249       postEnableTableHandlerCalled = false;
250       preDisableTableHandlerCalled = false;
251       postDisableTableHandlerCalled = false;
252       preGetTableDescriptorsCalled = false;
253       postGetTableDescriptorsCalled = false;
254       postGetTableNamesCalled = false;
255       preGetTableNamesCalled = false;
256       preDispatchMergeCalled = false;
257       postDispatchMergeCalled = false;
258     }
259 
260     @Override
261     public void preDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
262         HRegionInfo regionA, HRegionInfo regionB) throws IOException {
263       preDispatchMergeCalled = true;
264     }
265 
266     @Override
267     public void postDispatchMerge(final ObserverContext<MasterCoprocessorEnvironment> ctx,
268         HRegionInfo regionA, HRegionInfo regionB) throws IOException {
269       postDispatchMergeCalled = true;
270     }
271 
272     public boolean wasDispatchMergeCalled() {
273       return preDispatchMergeCalled && postDispatchMergeCalled;
274     }
275 
276     @Override
277     public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
278         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
279       if (bypass) {
280         env.bypass();
281       }
282       preCreateTableCalled = true;
283     }
284 
285     @Override
286     public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
287         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
288       postCreateTableCalled = true;
289     }
290 
291     public boolean wasCreateTableCalled() {
292       return preCreateTableCalled && postCreateTableCalled;
293     }
294 
295     public boolean preCreateTableCalledOnly() {
296       return preCreateTableCalled && !postCreateTableCalled;
297     }
298 
299     @Override
300     public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
301         TableName tableName) throws IOException {
302       if (bypass) {
303         env.bypass();
304       }
305       preDeleteTableCalled = true;
306     }
307 
308     @Override
309     public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
310         TableName tableName) throws IOException {
311       postDeleteTableCalled = true;
312     }
313 
314     public boolean wasDeleteTableCalled() {
315       return preDeleteTableCalled && postDeleteTableCalled;
316     }
317 
318     public boolean preDeleteTableCalledOnly() {
319       return preDeleteTableCalled && !postDeleteTableCalled;
320     }
321 
322     @Override
323     public void preTruncateTable(ObserverContext<MasterCoprocessorEnvironment> env,
324         TableName tableName) throws IOException {
325       if (bypass) {
326         env.bypass();
327       }
328       preTruncateTableCalled = true;
329     }
330 
331     @Override
332     public void postTruncateTable(ObserverContext<MasterCoprocessorEnvironment> env,
333         TableName tableName) throws IOException {
334       postTruncateTableCalled = true;
335     }
336 
337     public boolean wasTruncateTableCalled() {
338       return preTruncateTableCalled && postTruncateTableCalled;
339     }
340 
341     public boolean preTruncateTableCalledOnly() {
342       return preTruncateTableCalled && !postTruncateTableCalled;
343     }
344 
345     @Override
346     public boolean preSetSplitOrMergeEnabled(final ObserverContext<MasterCoprocessorEnvironment> ctx,
347         final boolean newValue, final Admin.MasterSwitchType switchType) throws IOException {
348       return false;
349     }
350 
351     @Override
352     public void postSetSplitOrMergeEnabled(final ObserverContext<MasterCoprocessorEnvironment> ctx,
353         final boolean newValue, final Admin.MasterSwitchType switchType) throws IOException {
354     }
355 
356     @Override
357     public void preModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
358         TableName tableName, HTableDescriptor htd) throws IOException {
359       if (bypass) {
360         env.bypass();
361       }else{
362         env.shouldBypass();
363       }
364       preModifyTableCalled = true;
365     }
366 
367     @Override
368     public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
369         TableName tableName, HTableDescriptor htd) throws IOException {
370       postModifyTableCalled = true;
371     }
372 
373     public boolean wasModifyTableCalled() {
374       return preModifyTableCalled && postModifyTableCalled;
375     }
376 
377     public boolean preModifyTableCalledOnly() {
378       return preModifyTableCalled && !postModifyTableCalled;
379     }
380 
381     @Override
382     public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
383         NamespaceDescriptor ns) throws IOException {
384       if (bypass) {
385         env.bypass();
386       }
387       preCreateNamespaceCalled = true;
388     }
389 
390     @Override
391     public void postCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
392         NamespaceDescriptor ns) throws IOException {
393       postCreateNamespaceCalled = true;
394     }
395 
396     public boolean wasCreateNamespaceCalled() {
397       return preCreateNamespaceCalled && postCreateNamespaceCalled;
398     }
399 
400     public boolean preCreateNamespaceCalledOnly() {
401       return preCreateNamespaceCalled && !postCreateNamespaceCalled;
402     }
403 
404     @Override
405     public void preDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
406         String name) throws IOException {
407       if (bypass) {
408         env.bypass();
409       }
410       preDeleteNamespaceCalled = true;
411     }
412 
413     @Override
414     public void postDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
415         String name) throws IOException {
416       postDeleteNamespaceCalled = true;
417     }
418 
419     public boolean wasDeleteNamespaceCalled() {
420       return preDeleteNamespaceCalled && postDeleteNamespaceCalled;
421     }
422 
423     public boolean preDeleteNamespaceCalledOnly() {
424       return preDeleteNamespaceCalled && !postDeleteNamespaceCalled;
425     }
426 
427     @Override
428     public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
429         NamespaceDescriptor ns) throws IOException {
430       if (bypass) {
431         env.bypass();
432       }
433       preModifyNamespaceCalled = true;
434     }
435 
436     @Override
437     public void postModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
438         NamespaceDescriptor ns) throws IOException {
439       postModifyNamespaceCalled = true;
440     }
441 
442     public boolean wasModifyNamespaceCalled() {
443       return preModifyNamespaceCalled && postModifyNamespaceCalled;
444     }
445 
446     public boolean preModifyNamespaceCalledOnly() {
447       return preModifyNamespaceCalled && !postModifyNamespaceCalled;
448     }
449 
450 
451     @Override
452     public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
453         String namespace) throws IOException {
454       preGetNamespaceDescriptorCalled = true;
455     }
456 
457     @Override
458     public void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
459         NamespaceDescriptor ns) throws IOException {
460       postGetNamespaceDescriptorCalled = true;
461     }
462 
463     public boolean wasGetNamespaceDescriptorCalled() {
464       return preGetNamespaceDescriptorCalled && postGetNamespaceDescriptorCalled;
465     }
466 
467     @Override
468     public void preListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> env,
469         List<NamespaceDescriptor> descriptors) throws IOException {
470       if (bypass) {
471         env.bypass();
472       }
473       preListNamespaceDescriptorsCalled = true;
474     }
475 
476     @Override
477     public void postListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> env,
478         List<NamespaceDescriptor> descriptors) throws IOException {
479       postListNamespaceDescriptorsCalled = true;
480     }
481 
482     public boolean wasListNamespaceDescriptorsCalled() {
483       return preListNamespaceDescriptorsCalled && postListNamespaceDescriptorsCalled;
484     }
485 
486     public boolean preListNamespaceDescriptorsCalledOnly() {
487       return preListNamespaceDescriptorsCalled && !postListNamespaceDescriptorsCalled;
488     }
489 
490     @Override
491     public void preAddColumn(ObserverContext<MasterCoprocessorEnvironment> env,
492         TableName tableName, HColumnDescriptor column) throws IOException {
493       if (bypass) {
494         env.bypass();
495       }else{
496         env.shouldBypass();
497       }
498 
499       preAddColumnCalled = true;
500     }
501 
502     @Override
503     public void postAddColumn(ObserverContext<MasterCoprocessorEnvironment> env,
504         TableName tableName, HColumnDescriptor column) throws IOException {
505       postAddColumnCalled = true;
506     }
507 
508     public boolean wasAddColumnCalled() {
509       return preAddColumnCalled && postAddColumnCalled;
510     }
511 
512     public boolean preAddColumnCalledOnly() {
513       return preAddColumnCalled && !postAddColumnCalled;
514     }
515 
516     @Override
517     public void preModifyColumn(ObserverContext<MasterCoprocessorEnvironment> env,
518         TableName tableName, HColumnDescriptor descriptor) throws IOException {
519       if (bypass) {
520         env.bypass();
521       }
522       preModifyColumnCalled = true;
523     }
524 
525     @Override
526     public void postModifyColumn(ObserverContext<MasterCoprocessorEnvironment> env,
527         TableName tableName, HColumnDescriptor descriptor) throws IOException {
528       postModifyColumnCalled = true;
529     }
530 
531     public boolean wasModifyColumnCalled() {
532       return preModifyColumnCalled && postModifyColumnCalled;
533     }
534 
535     public boolean preModifyColumnCalledOnly() {
536       return preModifyColumnCalled && !postModifyColumnCalled;
537     }
538 
539     @Override
540     public void preDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> env,
541         TableName tableName, byte[] c) throws IOException {
542       if (bypass) {
543         env.bypass();
544       }
545       preDeleteColumnCalled = true;
546     }
547 
548     @Override
549     public void postDeleteColumn(ObserverContext<MasterCoprocessorEnvironment> env,
550         TableName tableName, byte[] c) throws IOException {
551       postDeleteColumnCalled = true;
552     }
553 
554     public boolean wasDeleteColumnCalled() {
555       return preDeleteColumnCalled && postDeleteColumnCalled;
556     }
557 
558     public boolean preDeleteColumnCalledOnly() {
559       return preDeleteColumnCalled && !postDeleteColumnCalled;
560     }
561 
562     @Override
563     public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
564         TableName tableName) throws IOException {
565       if (bypass) {
566         env.bypass();
567       }
568       preEnableTableCalled = true;
569     }
570 
571     @Override
572     public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
573         TableName tableName) throws IOException {
574       postEnableTableCalled = true;
575     }
576 
577     public boolean wasEnableTableCalled() {
578       return preEnableTableCalled && postEnableTableCalled;
579     }
580 
581     public boolean preEnableTableCalledOnly() {
582       return preEnableTableCalled && !postEnableTableCalled;
583     }
584 
585     @Override
586     public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
587         TableName tableName) throws IOException {
588       if (bypass) {
589         env.bypass();
590       }
591       preDisableTableCalled = true;
592     }
593 
594     @Override
595     public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
596         TableName tableName) throws IOException {
597       postDisableTableCalled = true;
598     }
599 
600     public boolean wasDisableTableCalled() {
601       return preDisableTableCalled && postDisableTableCalled;
602     }
603 
604     public boolean preDisableTableCalledOnly() {
605       return preDisableTableCalled && !postDisableTableCalled;
606     }
607 
608     @Override
609     public void preAbortProcedure(
610         ObserverContext<MasterCoprocessorEnvironment> ctx,
611         final ProcedureExecutor<MasterProcedureEnv> procEnv,
612         final long procId) throws IOException {
613       preAbortProcedureCalled = true;
614     }
615 
616     @Override
617     public void postAbortProcedure(
618         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
619       postAbortProcedureCalled = true;
620     }
621 
622     public boolean wasAbortProcedureCalled() {
623       return preAbortProcedureCalled && postAbortProcedureCalled;
624     }
625 
626     public boolean wasPreAbortProcedureCalledOnly() {
627       return preAbortProcedureCalled && !postAbortProcedureCalled;
628     }
629 
630     @Override
631     public void preListProcedures(
632         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
633       preListProceduresCalled = true;
634     }
635 
636     @Override
637     public void postListProcedures(
638         ObserverContext<MasterCoprocessorEnvironment> ctx,
639         List<ProcedureInfo> procInfoList) throws IOException {
640       postListProceduresCalled = true;
641     }
642 
643     public boolean wasListProceduresCalled() {
644       return preListProceduresCalled && postListProceduresCalled;
645     }
646 
647     public boolean wasPreListProceduresCalledOnly() {
648       return preListProceduresCalled && !postListProceduresCalled;
649     }
650 
651     @Override
652     public void preMove(ObserverContext<MasterCoprocessorEnvironment> env,
653         HRegionInfo region, ServerName srcServer, ServerName destServer)
654     throws IOException {
655       if (bypass) {
656         env.bypass();
657       }
658       preMoveCalled = true;
659     }
660 
661     @Override
662     public void postMove(ObserverContext<MasterCoprocessorEnvironment> env, HRegionInfo region,
663         ServerName srcServer, ServerName destServer)
664     throws IOException {
665       postMoveCalled = true;
666     }
667 
668     public boolean wasMoveCalled() {
669       return preMoveCalled && postMoveCalled;
670     }
671 
672     public boolean preMoveCalledOnly() {
673       return preMoveCalled && !postMoveCalled;
674     }
675 
676     @Override
677     public void preAssign(ObserverContext<MasterCoprocessorEnvironment> env,
678         final HRegionInfo regionInfo) throws IOException {
679       if (bypass) {
680         env.bypass();
681       }
682       preAssignCalled = true;
683     }
684 
685     @Override
686     public void postAssign(ObserverContext<MasterCoprocessorEnvironment> env,
687         final HRegionInfo regionInfo) throws IOException {
688       postAssignCalled = true;
689     }
690 
691     public boolean wasAssignCalled() {
692       return preAssignCalled && postAssignCalled;
693     }
694 
695     public boolean preAssignCalledOnly() {
696       return preAssignCalled && !postAssignCalled;
697     }
698 
699     @Override
700     public void preUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
701         final HRegionInfo regionInfo, final boolean force) throws IOException {
702       if (bypass) {
703         env.bypass();
704       }
705       preUnassignCalled = true;
706     }
707 
708     @Override
709     public void postUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
710         final HRegionInfo regionInfo, final boolean force) throws IOException {
711       postUnassignCalled = true;
712     }
713 
714     public boolean wasUnassignCalled() {
715       return preUnassignCalled && postUnassignCalled;
716     }
717 
718     public boolean preUnassignCalledOnly() {
719       return preUnassignCalled && !postUnassignCalled;
720     }
721 
722     @Override
723     public void preRegionOffline(ObserverContext<MasterCoprocessorEnvironment> env,
724         final HRegionInfo regionInfo) throws IOException {
725       preRegionOfflineCalled = true;
726     }
727 
728     @Override
729     public void postRegionOffline(ObserverContext<MasterCoprocessorEnvironment> env,
730         final HRegionInfo regionInfo) throws IOException {
731       postRegionOfflineCalled = true;
732     }
733 
734     public boolean wasRegionOfflineCalled() {
735       return preRegionOfflineCalled && postRegionOfflineCalled;
736     }
737 
738     public boolean preRegionOfflineCalledOnly() {
739       return preRegionOfflineCalled && !postRegionOfflineCalled;
740     }
741 
742     @Override
743     public void preBalance(ObserverContext<MasterCoprocessorEnvironment> env)
744         throws IOException {
745       if (bypass) {
746         env.bypass();
747       }
748       preBalanceCalled = true;
749     }
750 
751     @Override
752     public void postBalance(ObserverContext<MasterCoprocessorEnvironment> env,
753         List<RegionPlan> plans) throws IOException {
754       postBalanceCalled = true;
755     }
756 
757     public boolean wasBalanceCalled() {
758       return preBalanceCalled && postBalanceCalled;
759     }
760 
761     public boolean preBalanceCalledOnly() {
762       return preBalanceCalled && !postBalanceCalled;
763     }
764 
765     @Override
766     public boolean preBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env, boolean b)
767         throws IOException {
768       if (bypass) {
769         env.bypass();
770       }
771       preBalanceSwitchCalled = true;
772       return b;
773     }
774 
775     @Override
776     public void postBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env,
777         boolean oldValue, boolean newValue) throws IOException {
778       postBalanceSwitchCalled = true;
779     }
780 
781     public boolean wasBalanceSwitchCalled() {
782       return preBalanceSwitchCalled && postBalanceSwitchCalled;
783     }
784 
785     public boolean preBalanceSwitchCalledOnly() {
786       return preBalanceSwitchCalled && !postBalanceSwitchCalled;
787     }
788 
789     @Override
790     public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> env)
791         throws IOException {
792       preShutdownCalled = true;
793     }
794 
795     @Override
796     public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> env)
797         throws IOException {
798       preStopMasterCalled = true;
799     }
800 
801     @Override
802     public void preMasterInitialization(
803         ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
804       preMasterInitializationCalled = true;
805     }
806 
807     public boolean wasMasterInitializationCalled(){
808       return preMasterInitializationCalled;
809     }
810 
811     @Override
812     public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
813         throws IOException {
814       postStartMasterCalled = true;
815     }
816 
817     public boolean wasStartMasterCalled() {
818       return postStartMasterCalled;
819     }
820 
821     @Override
822     public void start(CoprocessorEnvironment env) throws IOException {
823       startCalled = true;
824     }
825 
826     @Override
827     public void stop(CoprocessorEnvironment env) throws IOException {
828       stopCalled = true;
829     }
830 
831     public boolean wasStarted() { return startCalled; }
832 
833     public boolean wasStopped() { return stopCalled; }
834 
835     @Override
836     public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
837         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
838         throws IOException {
839       preSnapshotCalled = true;
840     }
841 
842     @Override
843     public void postSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
844         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
845         throws IOException {
846       postSnapshotCalled = true;
847     }
848 
849     public boolean wasSnapshotCalled() {
850       return preSnapshotCalled && postSnapshotCalled;
851     }
852     
853     @Override
854     public void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
855         final SnapshotDescription snapshot) throws IOException {
856       preListSnapshotCalled = true;
857     }
858 
859     @Override
860     public void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
861         final SnapshotDescription snapshot) throws IOException {
862       postListSnapshotCalled = true;
863     }
864 
865     public boolean wasListSnapshotCalled() {
866       return preListSnapshotCalled && postListSnapshotCalled;
867     }
868 
869     @Override
870     public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
871         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
872         throws IOException {
873       preCloneSnapshotCalled = true;
874     }
875 
876     @Override
877     public void postCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
878         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
879         throws IOException {
880       postCloneSnapshotCalled = true;
881     }
882 
883     public boolean wasCloneSnapshotCalled() {
884       return preCloneSnapshotCalled && postCloneSnapshotCalled;
885     }
886 
887     @Override
888     public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
889         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
890         throws IOException {
891       preRestoreSnapshotCalled = true;
892     }
893 
894     @Override
895     public void postRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
896         final SnapshotDescription snapshot, final HTableDescriptor hTableDescriptor)
897         throws IOException {
898       postRestoreSnapshotCalled = true;
899     }
900 
901     public boolean wasRestoreSnapshotCalled() {
902       return preRestoreSnapshotCalled && postRestoreSnapshotCalled;
903     }
904 
905     @Override
906     public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
907         final SnapshotDescription snapshot) throws IOException {
908       preDeleteSnapshotCalled = true;
909     }
910 
911     @Override
912     public void postDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
913         final SnapshotDescription snapshot) throws IOException {
914       postDeleteSnapshotCalled = true;
915     }
916 
917     public boolean wasDeleteSnapshotCalled() {
918       return preDeleteSnapshotCalled && postDeleteSnapshotCalled;
919     }
920 
921     @Override
922     public void preCreateTableHandler(
923         ObserverContext<MasterCoprocessorEnvironment> env,
924         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
925       if (bypass) {
926         env.bypass();
927       }
928       preCreateTableHandlerCalled = true;
929     }
930 
931     @Override
932     public void postCreateTableHandler(
933         ObserverContext<MasterCoprocessorEnvironment> ctx,
934         HTableDescriptor desc, HRegionInfo[] regions) throws IOException {
935       postCreateTableHandlerCalled = true;
936       tableCreationLatch.countDown();
937     }
938 
939     public boolean wasPreCreateTableHandlerCalled(){
940       return preCreateTableHandlerCalled;
941     }
942     public boolean wasCreateTableHandlerCalled() {
943       return preCreateTableHandlerCalled && postCreateTableHandlerCalled;
944     }
945 
946     public boolean wasCreateTableHandlerCalledOnly() {
947       return preCreateTableHandlerCalled && !postCreateTableHandlerCalled;
948     }
949 
950     @Override
951     public void preDeleteTableHandler(
952         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName)
953         throws IOException {
954       if (bypass) {
955         env.bypass();
956       }
957       preDeleteTableHandlerCalled = true;
958     }
959 
960     @Override
961     public void postDeleteTableHandler(
962         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
963         throws IOException {
964       postDeleteTableHandlerCalled = true;
965       tableDeletionLatch.countDown();
966     }
967 
968     public boolean wasDeleteTableHandlerCalled() {
969       return preDeleteTableHandlerCalled && postDeleteTableHandlerCalled;
970     }
971 
972     public boolean wasDeleteTableHandlerCalledOnly() {
973       return preDeleteTableHandlerCalled && !postDeleteTableHandlerCalled;
974     }
975 
976     @Override
977     public void preTruncateTableHandler(
978         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName)
979         throws IOException {
980       if (bypass) {
981         env.bypass();
982       }
983       preTruncateTableHandlerCalled = true;
984     }
985 
986     @Override
987     public void postTruncateTableHandler(
988         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
989         throws IOException {
990       postTruncateTableHandlerCalled = true;
991     }
992 
993     public boolean wasTruncateTableHandlerCalled() {
994       return preTruncateTableHandlerCalled && postTruncateTableHandlerCalled;
995     }
996 
997     public boolean wasTruncateTableHandlerCalledOnly() {
998       return preTruncateTableHandlerCalled && !postTruncateTableHandlerCalled;
999     }
1000 
1001     @Override
1002     public void preModifyTableHandler(
1003         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName,
1004         HTableDescriptor htd) throws IOException {
1005       if (bypass) {
1006         env.bypass();
1007       }
1008       preModifyTableHandlerCalled = true;
1009     }
1010 
1011     @Override
1012     public void postModifyTableHandler(
1013         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName,
1014         HTableDescriptor htd) throws IOException {
1015       postModifyTableHandlerCalled = true;
1016     }
1017 
1018     public boolean wasModifyTableHandlerCalled() {
1019       return preModifyColumnHandlerCalled && postModifyColumnHandlerCalled;
1020     }
1021 
1022     public boolean wasModifyTableHandlerCalledOnly() {
1023       return preModifyColumnHandlerCalled && !postModifyColumnHandlerCalled;
1024     }
1025 
1026     @Override
1027     public void preAddColumnHandler(
1028         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName,
1029         HColumnDescriptor column) throws IOException {
1030       if (bypass) {
1031         env.bypass();
1032       }
1033       preAddColumnHandlerCalled = true;
1034     }
1035 
1036     @Override
1037     public void postAddColumnHandler(
1038         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName,
1039         HColumnDescriptor column) throws IOException {
1040       postAddColumnHandlerCalled = true;
1041     }
1042     public boolean wasAddColumnHandlerCalled() {
1043       return preAddColumnHandlerCalled && postAddColumnHandlerCalled;
1044     }
1045 
1046     public boolean preAddColumnHandlerCalledOnly() {
1047       return preAddColumnHandlerCalled && !postAddColumnHandlerCalled;
1048     }
1049 
1050     @Override
1051     public void preModifyColumnHandler(
1052         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName,
1053         HColumnDescriptor descriptor) throws IOException {
1054       if (bypass) {
1055         env.bypass();
1056       }
1057       preModifyColumnHandlerCalled = true;
1058     }
1059 
1060     @Override
1061     public void postModifyColumnHandler(
1062         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName,
1063         HColumnDescriptor descriptor) throws IOException {
1064       postModifyColumnHandlerCalled = true;
1065     }
1066 
1067     public boolean wasModifyColumnHandlerCalled() {
1068       return preModifyColumnHandlerCalled && postModifyColumnHandlerCalled;
1069     }
1070 
1071     public boolean preModifyColumnHandlerCalledOnly() {
1072       return preModifyColumnHandlerCalled && !postModifyColumnHandlerCalled;
1073     }
1074     @Override
1075     public void preDeleteColumnHandler(
1076         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName,
1077         byte[] c) throws IOException {
1078       if (bypass) {
1079         env.bypass();
1080       }
1081       preDeleteColumnHandlerCalled = true;
1082     }
1083 
1084     @Override
1085     public void postDeleteColumnHandler(
1086         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName,
1087         byte[] c) throws IOException {
1088       postDeleteColumnHandlerCalled = true;
1089     }
1090 
1091     public boolean wasDeleteColumnHandlerCalled() {
1092       return preDeleteColumnHandlerCalled && postDeleteColumnHandlerCalled;
1093     }
1094 
1095     public boolean preDeleteColumnHandlerCalledOnly() {
1096       return preDeleteColumnHandlerCalled && !postDeleteColumnHandlerCalled;
1097     }
1098 
1099     @Override
1100     public void preEnableTableHandler(
1101         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName)
1102         throws IOException {
1103       if (bypass) {
1104         env.bypass();
1105       }
1106       preEnableTableHandlerCalled = true;
1107     }
1108 
1109     @Override
1110     public void postEnableTableHandler(
1111         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
1112         throws IOException {
1113       postEnableTableHandlerCalled = true;
1114     }
1115 
1116     public boolean wasEnableTableHandlerCalled() {
1117       return preEnableTableHandlerCalled && postEnableTableHandlerCalled;
1118     }
1119 
1120     public boolean preEnableTableHandlerCalledOnly() {
1121       return preEnableTableHandlerCalled && !postEnableTableHandlerCalled;
1122     }
1123 
1124     @Override
1125     public void preDisableTableHandler(
1126         ObserverContext<MasterCoprocessorEnvironment> env, TableName tableName)
1127         throws IOException {
1128       if (bypass) {
1129         env.bypass();
1130       }
1131       preDisableTableHandlerCalled = true;
1132     }
1133 
1134     @Override
1135     public void postDisableTableHandler(
1136         ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tableName)
1137         throws IOException {
1138       postDisableTableHandlerCalled = true;
1139     }
1140 
1141     public boolean wasDisableTableHandlerCalled() {
1142       return preDisableTableHandlerCalled && postDisableTableHandlerCalled;
1143     }
1144 
1145     public boolean preDisableTableHandlerCalledOnly() {
1146       return preDisableTableHandlerCalled && !postDisableTableHandlerCalled;
1147     }
1148 
1149     @Override
1150     public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1151         List<TableName> tableNamesList, List<HTableDescriptor> descriptors) throws IOException {
1152     }
1153 
1154     @Override
1155     public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1156         List<HTableDescriptor> descriptors) throws IOException {
1157     }
1158 
1159     @Override
1160     public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1161         List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
1162         String regex) throws IOException {
1163       preGetTableDescriptorsCalled = true;
1164     }
1165 
1166     @Override
1167     public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1168         List<TableName> tableNamesList, List<HTableDescriptor> descriptors,
1169         String regex) throws IOException {
1170       postGetTableDescriptorsCalled = true;
1171     }
1172 
1173     public boolean wasGetTableDescriptorsCalled() {
1174       return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
1175     }
1176 
1177     @Override
1178     public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
1179         List<HTableDescriptor> descriptors, String regex) throws IOException {
1180       preGetTableNamesCalled = true;
1181     }
1182 
1183     @Override
1184     public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
1185         List<HTableDescriptor> descriptors, String regex) throws IOException {
1186       postGetTableNamesCalled = true;
1187     }
1188 
1189     public boolean wasGetTableNamesCalled() {
1190       return preGetTableNamesCalled && postGetTableNamesCalled;
1191     }
1192 
1193     @Override
1194     public void preTableFlush(ObserverContext<MasterCoprocessorEnvironment> ctx,
1195         TableName tableName) throws IOException {
1196     }
1197 
1198     @Override
1199     public void postTableFlush(ObserverContext<MasterCoprocessorEnvironment> ctx,
1200         TableName tableName) throws IOException {
1201     }
1202     
1203     @Override
1204     public void preSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1205         final String userName, final Quotas quotas) throws IOException {
1206     }
1207 
1208     @Override
1209     public void postSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1210         final String userName, final Quotas quotas) throws IOException {
1211     }
1212 
1213     @Override
1214     public void preSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1215         final String userName, final TableName tableName, final Quotas quotas) throws IOException {
1216     }
1217 
1218     @Override
1219     public void postSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1220         final String userName, final TableName tableName, final Quotas quotas) throws IOException {
1221     }
1222 
1223     @Override
1224     public void preSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1225         final String userName, final String namespace, final Quotas quotas) throws IOException {
1226     }
1227 
1228     @Override
1229     public void postSetUserQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1230         final String userName, final String namespace, final Quotas quotas) throws IOException {
1231     }
1232 
1233     @Override
1234     public void preSetTableQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1235         final TableName tableName, final Quotas quotas) throws IOException {
1236     }
1237 
1238     @Override
1239     public void postSetTableQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1240         final TableName tableName, final Quotas quotas) throws IOException {
1241     }
1242 
1243     @Override
1244     public void preSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1245         final String namespace, final Quotas quotas) throws IOException {
1246     }
1247 
1248     @Override
1249     public void postSetNamespaceQuota(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1250         final String namespace, final Quotas quotas) throws IOException {
1251     }
1252   }
1253 
1254   private static HBaseTestingUtility UTIL = new HBaseTestingUtility();
1255   private static byte[] TEST_SNAPSHOT = Bytes.toBytes("observed_snapshot");
1256   private static TableName TEST_CLONE = TableName.valueOf("observed_clone");
1257   private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
1258   private static byte[] TEST_FAMILY2 = Bytes.toBytes("fam2");
1259   @Rule public TestName name = new TestName();
1260 
1261   @BeforeClass
1262   public static void setupBeforeClass() throws Exception {
1263     Configuration conf = UTIL.getConfiguration();
1264     conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY,
1265         CPMasterObserver.class.getName());
1266     // We need more than one data server on this test
1267     UTIL.startMiniCluster(2);
1268   }
1269 
1270   @AfterClass
1271   public static void tearDownAfterClass() throws Exception {
1272     UTIL.shutdownMiniCluster();
1273   }
1274 
1275   @Test (timeout=180000)
1276   public void testStarted() throws Exception {
1277     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1278 
1279     HMaster master = cluster.getMaster();
1280     assertTrue("Master should be active", master.isActiveMaster());
1281     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1282     assertNotNull("CoprocessorHost should not be null", host);
1283     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1284         CPMasterObserver.class.getName());
1285     assertNotNull("CPMasterObserver coprocessor not found or not installed!", cp);
1286 
1287     // check basic lifecycle
1288     assertTrue("MasterObserver should have been started", cp.wasStarted());
1289     assertTrue("preMasterInitialization() hook should have been called",
1290         cp.wasMasterInitializationCalled());
1291     assertTrue("postStartMaster() hook should have been called",
1292         cp.wasStartMasterCalled());
1293   }
1294 
1295   @Test (timeout=180000)
1296   public void testTableOperations() throws Exception {
1297     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1298     final TableName tableName = TableName.valueOf(name.getMethodName());
1299     HMaster master = cluster.getMaster();
1300     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1301     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1302         CPMasterObserver.class.getName());
1303     cp.enableBypass(true);
1304     cp.resetStates();
1305     assertFalse("No table created yet", cp.wasCreateTableCalled());
1306 
1307     // create a table
1308     HTableDescriptor htd = new HTableDescriptor(tableName);
1309     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
1310     try(Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
1311         Admin admin = connection.getAdmin()) {
1312       tableCreationLatch = new CountDownLatch(1);
1313       admin.createTable(htd, Arrays.copyOfRange(HBaseTestingUtility.KEYS,
1314         1, HBaseTestingUtility.KEYS.length));
1315 
1316       // preCreateTable can't bypass default action.
1317       assertTrue("Test table should be created", cp.wasCreateTableCalled());
1318       tableCreationLatch.await();
1319       assertTrue("Table pre create handler called.", cp
1320         .wasPreCreateTableHandlerCalled());
1321       assertTrue("Table create handler should be called.",
1322         cp.wasCreateTableHandlerCalled());
1323 
1324       RegionLocator regionLocator = connection.getRegionLocator(htd.getTableName());
1325       List<HRegionLocation> regions = regionLocator.getAllRegionLocations();
1326 
1327       admin.mergeRegions(regions.get(0).getRegionInfo().getEncodedNameAsBytes(),
1328         regions.get(1).getRegionInfo().getEncodedNameAsBytes(), true);
1329       assertTrue("Coprocessor should have been called on region merge",
1330         cp.wasDispatchMergeCalled());
1331 
1332       tableCreationLatch = new CountDownLatch(1);
1333       admin.disableTable(tableName);
1334       assertTrue(admin.isTableDisabled(tableName));
1335       // preDisableTable can't bypass default action.
1336       assertTrue("Coprocessor should have been called on table disable",
1337         cp.wasDisableTableCalled());
1338       assertTrue("Disable table handler should be called.",
1339         cp.wasDisableTableHandlerCalled());
1340 
1341       // enable
1342       assertFalse(cp.wasEnableTableCalled());
1343       admin.enableTable(tableName);
1344       assertTrue(admin.isTableEnabled(tableName));
1345       // preEnableTable can't bypass default action.
1346       assertTrue("Coprocessor should have been called on table enable",
1347         cp.wasEnableTableCalled());
1348       assertTrue("Enable table handler should be called.",
1349         cp.wasEnableTableHandlerCalled());
1350 
1351       admin.disableTable(tableName);
1352       assertTrue(admin.isTableDisabled(tableName));
1353 
1354       // modify table
1355       htd.setMaxFileSize(512 * 1024 * 1024);
1356       modifyTableSync(admin, tableName, htd);
1357       // preModifyTable can't bypass default action.
1358       assertTrue("Test table should have been modified",
1359         cp.wasModifyTableCalled());
1360 
1361       // add a column family
1362       admin.addColumn(tableName, new HColumnDescriptor(TEST_FAMILY2));
1363       assertTrue("New column family shouldn't have been added to test table",
1364         cp.preAddColumnCalledOnly());
1365 
1366       // modify a column family
1367       HColumnDescriptor hcd1 = new HColumnDescriptor(TEST_FAMILY2);
1368       hcd1.setMaxVersions(25);
1369       admin.modifyColumn(tableName, hcd1);
1370       assertTrue("Second column family should be modified",
1371         cp.preModifyColumnCalledOnly());
1372 
1373       // truncate table
1374       admin.truncateTable(tableName, false);
1375 
1376       // delete table
1377       admin.disableTable(tableName);
1378       assertTrue(admin.isTableDisabled(tableName));
1379       deleteTable(admin, tableName);
1380       assertFalse("Test table should have been deleted",
1381         admin.tableExists(tableName));
1382       // preDeleteTable can't bypass default action.
1383       assertTrue("Coprocessor should have been called on table delete",
1384         cp.wasDeleteTableCalled());
1385       assertTrue("Delete table handler should be called.",
1386         cp.wasDeleteTableHandlerCalled());
1387 
1388       // turn off bypass, run the tests again
1389       cp.enableBypass(false);
1390       cp.resetStates();
1391 
1392       admin.createTable(htd);
1393       assertTrue("Test table should be created", cp.wasCreateTableCalled());
1394       tableCreationLatch.await();
1395       assertTrue("Table pre create handler called.", cp
1396         .wasPreCreateTableHandlerCalled());
1397       assertTrue("Table create handler should be called.",
1398         cp.wasCreateTableHandlerCalled());
1399 
1400       // disable
1401       assertFalse(cp.wasDisableTableCalled());
1402       assertFalse(cp.wasDisableTableHandlerCalled());
1403       admin.disableTable(tableName);
1404       assertTrue(admin.isTableDisabled(tableName));
1405       assertTrue("Coprocessor should have been called on table disable",
1406         cp.wasDisableTableCalled());
1407       assertTrue("Disable table handler should be called.",
1408         cp.wasDisableTableHandlerCalled());
1409 
1410       // modify table
1411       htd.setMaxFileSize(512 * 1024 * 1024);
1412       modifyTableSync(admin, tableName, htd);
1413       assertTrue("Test table should have been modified",
1414         cp.wasModifyTableCalled());
1415       // add a column family
1416       admin.addColumn(tableName, new HColumnDescriptor(TEST_FAMILY2));
1417       assertTrue("New column family should have been added to test table",
1418         cp.wasAddColumnCalled());
1419       assertTrue("Add column handler should be called.",
1420         cp.wasAddColumnHandlerCalled());
1421 
1422       // modify a column family
1423       HColumnDescriptor hcd = new HColumnDescriptor(TEST_FAMILY2);
1424       hcd.setMaxVersions(25);
1425       admin.modifyColumn(tableName, hcd);
1426       assertTrue("Second column family should be modified",
1427         cp.wasModifyColumnCalled());
1428       assertTrue("Modify table handler should be called.",
1429         cp.wasModifyColumnHandlerCalled());
1430 
1431       // enable
1432       assertFalse(cp.wasEnableTableCalled());
1433       assertFalse(cp.wasEnableTableHandlerCalled());
1434       admin.enableTable(tableName);
1435       assertTrue(admin.isTableEnabled(tableName));
1436       assertTrue("Coprocessor should have been called on table enable",
1437         cp.wasEnableTableCalled());
1438       assertTrue("Enable table handler should be called.",
1439         cp.wasEnableTableHandlerCalled());
1440 
1441       // disable again
1442       admin.disableTable(tableName);
1443       assertTrue(admin.isTableDisabled(tableName));
1444 
1445       // delete column
1446       assertFalse("No column family deleted yet", cp.wasDeleteColumnCalled());
1447       assertFalse("Delete table column handler should not be called.",
1448         cp.wasDeleteColumnHandlerCalled());
1449       admin.deleteColumn(tableName, TEST_FAMILY2);
1450       HTableDescriptor tableDesc = admin.getTableDescriptor(tableName);
1451       assertNull("'"+Bytes.toString(TEST_FAMILY2)+"' should have been removed",
1452         tableDesc.getFamily(TEST_FAMILY2));
1453       assertTrue("Coprocessor should have been called on column delete",
1454         cp.wasDeleteColumnCalled());
1455       assertTrue("Delete table column handler should be called.",
1456         cp.wasDeleteColumnHandlerCalled());
1457 
1458       // delete table
1459       assertFalse("No table deleted yet", cp.wasDeleteTableCalled());
1460       assertFalse("Delete table handler should not be called.",
1461         cp.wasDeleteTableHandlerCalled());
1462       deleteTable(admin, tableName);
1463       assertFalse("Test table should have been deleted",
1464         admin.tableExists(tableName));
1465       assertTrue("Coprocessor should have been called on table delete",
1466         cp.wasDeleteTableCalled());
1467       assertTrue("Delete table handler should be called.",
1468         cp.wasDeleteTableHandlerCalled());
1469     }
1470   }
1471 
1472   @Test (timeout=180000)
1473   public void testSnapshotOperations() throws Exception {
1474     final TableName tableName = TableName.valueOf(name.getMethodName());
1475     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1476     HMaster master = cluster.getMaster();
1477     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1478     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1479         CPMasterObserver.class.getName());
1480     cp.resetStates();
1481 
1482     // create a table
1483     HTableDescriptor htd = new HTableDescriptor(tableName);
1484     htd.addFamily(new HColumnDescriptor(TEST_FAMILY));
1485     Admin admin = UTIL.getHBaseAdmin();
1486 
1487     tableCreationLatch = new CountDownLatch(1);
1488     admin.createTable(htd);
1489     tableCreationLatch.await();
1490     tableCreationLatch = new CountDownLatch(1);
1491 
1492     admin.disableTable(tableName);
1493     assertTrue(admin.isTableDisabled(tableName));
1494 
1495     try {
1496       // Test snapshot operation
1497       assertFalse("Coprocessor should not have been called yet",
1498         cp.wasSnapshotCalled());
1499       admin.snapshot(TEST_SNAPSHOT, tableName);
1500       assertTrue("Coprocessor should have been called on snapshot",
1501         cp.wasSnapshotCalled());
1502       
1503       //Test list operation
1504       admin.listSnapshots();
1505       assertTrue("Coprocessor should have been called on snapshot list",
1506         cp.wasListSnapshotCalled());
1507 
1508       // Test clone operation
1509       admin.cloneSnapshot(TEST_SNAPSHOT, TEST_CLONE);
1510       assertTrue("Coprocessor should have been called on snapshot clone",
1511         cp.wasCloneSnapshotCalled());
1512       assertFalse("Coprocessor restore should not have been called on snapshot clone",
1513         cp.wasRestoreSnapshotCalled());
1514       admin.disableTable(TEST_CLONE);
1515       assertTrue(admin.isTableDisabled(tableName));
1516       deleteTable(admin, TEST_CLONE);
1517 
1518       // Test restore operation
1519       cp.resetStates();
1520       admin.restoreSnapshot(TEST_SNAPSHOT);
1521       assertTrue("Coprocessor should have been called on snapshot restore",
1522         cp.wasRestoreSnapshotCalled());
1523       assertFalse("Coprocessor clone should not have been called on snapshot restore",
1524         cp.wasCloneSnapshotCalled());
1525 
1526       admin.deleteSnapshot(TEST_SNAPSHOT);
1527       assertTrue("Coprocessor should have been called on snapshot delete",
1528         cp.wasDeleteSnapshotCalled());
1529     } finally {
1530       deleteTable(admin, tableName);
1531     }
1532   }
1533 
1534   @Test (timeout=180000)
1535   public void testNamespaceOperations() throws Exception {
1536     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1537     String testNamespace = "observed_ns";
1538     HMaster master = cluster.getMaster();
1539     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1540     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1541         CPMasterObserver.class.getName());
1542 
1543     cp.enableBypass(false);
1544     cp.resetStates();
1545 
1546 
1547     // create a table
1548     Admin admin = UTIL.getHBaseAdmin();
1549     admin.createNamespace(NamespaceDescriptor.create(testNamespace).build());
1550     assertTrue("Test namespace should be created", cp.wasCreateNamespaceCalled());
1551 
1552     assertNotNull(admin.getNamespaceDescriptor(testNamespace));
1553     assertTrue("Test namespace descriptor should have been called",
1554         cp.wasGetNamespaceDescriptorCalled());
1555 
1556     // turn off bypass, run the tests again
1557     cp.enableBypass(true);
1558     cp.resetStates();
1559 
1560     admin.modifyNamespace(NamespaceDescriptor.create(testNamespace).build());
1561     assertTrue("Test namespace should not have been modified",
1562         cp.preModifyNamespaceCalledOnly());
1563 
1564     assertNotNull(admin.getNamespaceDescriptor(testNamespace));
1565     assertTrue("Test namespace descriptor should have been called",
1566         cp.wasGetNamespaceDescriptorCalled());
1567 
1568     admin.deleteNamespace(testNamespace);
1569     assertTrue("Test namespace should not have been deleted", cp.preDeleteNamespaceCalledOnly());
1570 
1571     assertNotNull(admin.getNamespaceDescriptor(testNamespace));
1572     assertTrue("Test namespace descriptor should have been called",
1573         cp.wasGetNamespaceDescriptorCalled());
1574 
1575     cp.enableBypass(false);
1576     cp.resetStates();
1577 
1578     // delete table
1579     admin.modifyNamespace(NamespaceDescriptor.create(testNamespace).build());
1580     assertTrue("Test namespace should have been modified", cp.wasModifyNamespaceCalled());
1581 
1582     admin.deleteNamespace(testNamespace);
1583     assertTrue("Test namespace should have been deleted", cp.wasDeleteNamespaceCalled());
1584 
1585     cp.enableBypass(true);
1586     cp.resetStates();
1587 
1588     admin.createNamespace(NamespaceDescriptor.create(testNamespace).build());
1589     assertTrue("Test namespace should not be created", cp.preCreateNamespaceCalledOnly());
1590 
1591     // turn on bypass, run the test
1592     cp.enableBypass(true);
1593     cp.resetStates();
1594 
1595     admin.listNamespaceDescriptors();
1596     assertTrue("post listNamespace should not have been called",
1597                cp.preListNamespaceDescriptorsCalledOnly());
1598 
1599     // turn off bypass, run the tests again
1600     cp.enableBypass(false);
1601     cp.resetStates();
1602 
1603     admin.listNamespaceDescriptors();
1604     assertTrue("post listNamespace should have been called",
1605                cp.wasListNamespaceDescriptorsCalled());
1606   }
1607 
1608   private void modifyTableSync(Admin admin, TableName tableName, HTableDescriptor htd)
1609       throws IOException {
1610     admin.modifyTable(tableName, htd);
1611     //wait until modify table finishes
1612     for (int t = 0; t < 100; t++) { //10 sec timeout
1613       HTableDescriptor td = admin.getTableDescriptor(htd.getTableName());
1614       if (td.equals(htd)) {
1615         break;
1616       }
1617       Threads.sleep(100);
1618     }
1619   }
1620 
1621   @Test (timeout=180000)
1622   public void testRegionTransitionOperations() throws Exception {
1623     final TableName tableName = TableName.valueOf(name.getMethodName());
1624     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1625 
1626     HMaster master = cluster.getMaster();
1627     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1628     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1629         CPMasterObserver.class.getName());
1630     cp.enableBypass(false);
1631     cp.resetStates();
1632 
1633     HTable table = UTIL.createMultiRegionTable(tableName, TEST_FAMILY);
1634 
1635     try {
1636       UTIL.waitUntilAllRegionsAssigned(tableName);
1637 
1638       NavigableMap<HRegionInfo, ServerName> regions = table.getRegionLocations();
1639       Map.Entry<HRegionInfo, ServerName> firstGoodPair = null;
1640       for (Map.Entry<HRegionInfo, ServerName> e: regions.entrySet()) {
1641         if (e.getValue() != null) {
1642           firstGoodPair = e;
1643           break;
1644         }
1645       }
1646       assertNotNull("Found a non-null entry", firstGoodPair);
1647       LOG.info("Found " + firstGoodPair.toString());
1648       // Try to force a move
1649       Collection<ServerName> servers = master.getClusterStatus().getServers();
1650       String destName = null;
1651       String serverNameForFirstRegion = firstGoodPair.getValue().toString();
1652       LOG.info("serverNameForFirstRegion=" + serverNameForFirstRegion);
1653       ServerName masterServerName = master.getServerName();
1654       boolean found = false;
1655       // Find server that is NOT carrying the first region
1656       for (ServerName info : servers) {
1657         LOG.info("ServerName=" + info);
1658         if (!serverNameForFirstRegion.equals(info.getServerName())
1659             && !masterServerName.equals(info)) {
1660           destName = info.toString();
1661           found = true;
1662           break;
1663         }
1664       }
1665       assertTrue("Found server", found);
1666       LOG.info("Found " + destName);
1667       master.getMasterRpcServices().moveRegion(null, RequestConverter.buildMoveRegionRequest(
1668           firstGoodPair.getKey().getEncodedNameAsBytes(),Bytes.toBytes(destName)));
1669       assertTrue("Coprocessor should have been called on region move",
1670         cp.wasMoveCalled());
1671 
1672       // make sure balancer is on
1673       master.balanceSwitch(true);
1674       assertTrue("Coprocessor should have been called on balance switch",
1675           cp.wasBalanceSwitchCalled());
1676 
1677       // turn balancer off
1678       master.balanceSwitch(false);
1679 
1680       // wait for assignments to finish, if any
1681       UTIL.waitUntilNoRegionsInTransition();
1682 
1683       // move half the open regions from RS 0 to RS 1
1684       HRegionServer rs = cluster.getRegionServer(0);
1685       byte[] destRS = Bytes.toBytes(cluster.getRegionServer(1).getServerName().toString());
1686       //Make sure no regions are in transition now
1687       UTIL.waitUntilNoRegionsInTransition();
1688       List<HRegionInfo> openRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
1689       int moveCnt = openRegions.size()/2;
1690       for (int i=0; i<moveCnt; i++) {
1691         HRegionInfo info = openRegions.get(i);
1692         if (!info.isMetaTable()) {
1693           master.getMasterRpcServices().moveRegion(null, RequestConverter.buildMoveRegionRequest(
1694               openRegions.get(i).getEncodedNameAsBytes(), destRS));
1695         }
1696       }
1697       //Make sure no regions are in transition now
1698       UTIL.waitUntilNoRegionsInTransition();
1699       // now trigger a balance
1700       master.balanceSwitch(true);
1701       boolean balanceRun = master.balance();
1702       assertTrue("Coprocessor should be called on region rebalancing",
1703           cp.wasBalanceCalled());
1704     } finally {
1705       Admin admin = UTIL.getHBaseAdmin();
1706       admin.disableTable(tableName);
1707       deleteTable(admin, tableName);
1708     }
1709   }
1710 
1711   @Test (timeout=180000)
1712   public void testTableDescriptorsEnumeration() throws Exception {
1713     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1714 
1715     HMaster master = cluster.getMaster();
1716     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1717     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1718         CPMasterObserver.class.getName());
1719     cp.resetStates();
1720 
1721     GetTableDescriptorsRequest req =
1722         RequestConverter.buildGetTableDescriptorsRequest((List<TableName>)null);
1723     master.getMasterRpcServices().getTableDescriptors(null, req);
1724 
1725     assertTrue("Coprocessor should be called on table descriptors request",
1726       cp.wasGetTableDescriptorsCalled());
1727   }
1728 
1729   @Test (timeout=180000)
1730   public void testTableNamesEnumeration() throws Exception {
1731     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1732 
1733     HMaster master = cluster.getMaster();
1734     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1735     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1736         CPMasterObserver.class.getName());
1737     cp.resetStates();
1738 
1739     master.getMasterRpcServices().getTableNames(null,
1740         GetTableNamesRequest.newBuilder().build());
1741     assertTrue("Coprocessor should be called on table names request",
1742       cp.wasGetTableNamesCalled());
1743   }
1744 
1745   @Test (timeout=180000)
1746   public void testAbortProcedureOperation() throws Exception {
1747     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1748 
1749     HMaster master = cluster.getMaster();
1750     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1751     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1752         CPMasterObserver.class.getName());
1753     cp.resetStates();
1754 
1755     master.abortProcedure(1, true);
1756     assertTrue(
1757       "Coprocessor should be called on abort procedure request",
1758       cp.wasAbortProcedureCalled());
1759   }
1760 
1761   @Test (timeout=180000)
1762   public void testListProceduresOperation() throws Exception {
1763     MiniHBaseCluster cluster = UTIL.getHBaseCluster();
1764 
1765     HMaster master = cluster.getMaster();
1766     MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1767     CPMasterObserver cp = (CPMasterObserver)host.findCoprocessor(
1768         CPMasterObserver.class.getName());
1769     cp.resetStates();
1770 
1771     master.listProcedures();
1772     assertTrue(
1773       "Coprocessor should be called on list procedures request",
1774       cp.wasListProceduresCalled());
1775   }
1776 
1777   private void deleteTable(Admin admin, TableName tableName) throws Exception {
1778     // NOTE: We need a latch because admin is not sync,
1779     // so the postOp coprocessor method may be called after the admin operation returned.
1780     tableDeletionLatch = new CountDownLatch(1);
1781     admin.deleteTable(tableName);
1782     tableDeletionLatch.await();
1783     tableDeletionLatch = new CountDownLatch(1);
1784   }
1785 }