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