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