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