View Javadoc

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