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