001/*
002 * Licensed to the Apache Software Foundation (ASF) under one
003 * or more contributor license agreements.  See the NOTICE file
004 * distributed with this work for additional information
005 * regarding copyright ownership.  The ASF licenses this file
006 * to you under the Apache License, Version 2.0 (the
007 * "License"); you may not use this file except in compliance
008 * with the License.  You may obtain a copy of the License at
009 *
010 *     http://www.apache.org/licenses/LICENSE-2.0
011 *
012 * Unless required by applicable law or agreed to in writing, software
013 * distributed under the License is distributed on an "AS IS" BASIS,
014 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
015 * See the License for the specific language governing permissions and
016 * limitations under the License.
017 */
018package org.apache.hadoop.hbase.coprocessor;
019
020import static org.junit.Assert.assertFalse;
021import static org.junit.Assert.assertNotNull;
022import static org.junit.Assert.assertTrue;
023
024import java.io.IOException;
025import java.util.Arrays;
026import java.util.Collection;
027import java.util.List;
028import java.util.Optional;
029import java.util.concurrent.CountDownLatch;
030import org.apache.hadoop.conf.Configuration;
031import org.apache.hadoop.hbase.CoprocessorEnvironment;
032import org.apache.hadoop.hbase.HBaseClassTestRule;
033import org.apache.hadoop.hbase.HBaseTestingUtil;
034import org.apache.hadoop.hbase.HRegionLocation;
035import org.apache.hadoop.hbase.NamespaceDescriptor;
036import org.apache.hadoop.hbase.ServerName;
037import org.apache.hadoop.hbase.SingleProcessHBaseCluster;
038import org.apache.hadoop.hbase.TableName;
039import org.apache.hadoop.hbase.client.Admin;
040import org.apache.hadoop.hbase.client.BalanceRequest;
041import org.apache.hadoop.hbase.client.ColumnFamilyDescriptorBuilder;
042import org.apache.hadoop.hbase.client.Connection;
043import org.apache.hadoop.hbase.client.ConnectionFactory;
044import org.apache.hadoop.hbase.client.Mutation;
045import org.apache.hadoop.hbase.client.RegionInfo;
046import org.apache.hadoop.hbase.client.RegionLocator;
047import org.apache.hadoop.hbase.client.SnapshotDescription;
048import org.apache.hadoop.hbase.client.Table;
049import org.apache.hadoop.hbase.client.TableDescriptor;
050import org.apache.hadoop.hbase.client.TableDescriptorBuilder;
051import org.apache.hadoop.hbase.master.HMaster;
052import org.apache.hadoop.hbase.master.MasterCoprocessorHost;
053import org.apache.hadoop.hbase.master.RegionPlan;
054import org.apache.hadoop.hbase.procedure2.LockType;
055import org.apache.hadoop.hbase.procedure2.ProcedureTestingUtility;
056import org.apache.hadoop.hbase.regionserver.HRegionServer;
057import org.apache.hadoop.hbase.testclassification.CoprocessorTests;
058import org.apache.hadoop.hbase.testclassification.MediumTests;
059import org.apache.hadoop.hbase.util.Bytes;
060import org.apache.hadoop.hbase.util.Threads;
061import org.junit.AfterClass;
062import org.junit.BeforeClass;
063import org.junit.ClassRule;
064import org.junit.Rule;
065import org.junit.Test;
066import org.junit.experimental.categories.Category;
067import org.junit.rules.TestName;
068import org.slf4j.Logger;
069import org.slf4j.LoggerFactory;
070
071import org.apache.hadoop.hbase.shaded.protobuf.ProtobufUtil;
072import org.apache.hadoop.hbase.shaded.protobuf.RequestConverter;
073import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableDescriptorsRequest;
074import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.GetTableNamesRequest;
075
076/**
077 * Tests invocation of the {@link org.apache.hadoop.hbase.coprocessor.MasterObserver} interface
078 * hooks at all appropriate times during normal HMaster operations.
079 */
080@Category({ CoprocessorTests.class, MediumTests.class })
081public class TestMasterObserver {
082
083  @ClassRule
084  public static final HBaseClassTestRule CLASS_RULE =
085    HBaseClassTestRule.forClass(TestMasterObserver.class);
086
087  private static final Logger LOG = LoggerFactory.getLogger(TestMasterObserver.class);
088
089  public static CountDownLatch tableCreationLatch = new CountDownLatch(1);
090  public static CountDownLatch tableDeletionLatch = new CountDownLatch(1);
091
092  public static class CPMasterObserver implements MasterCoprocessor, MasterObserver {
093
094    private boolean preCreateTableRegionInfosCalled;
095    private boolean preCreateTableCalled;
096    private boolean postCreateTableCalled;
097    private boolean preDeleteTableCalled;
098    private boolean postDeleteTableCalled;
099    private boolean preTruncateTableCalled;
100    private boolean postTruncateTableCalled;
101    private boolean preModifyTableCalled;
102    private boolean postModifyTableCalled;
103    private boolean preCreateNamespaceCalled;
104    private boolean postCreateNamespaceCalled;
105    private boolean preDeleteNamespaceCalled;
106    private boolean postDeleteNamespaceCalled;
107    private boolean preModifyNamespaceCalled;
108    private boolean postModifyNamespaceCalled;
109    private boolean preGetNamespaceDescriptorCalled;
110    private boolean postGetNamespaceDescriptorCalled;
111    private boolean preListNamespacesCalled;
112    private boolean postListNamespacesCalled;
113    private boolean preListNamespaceDescriptorsCalled;
114    private boolean postListNamespaceDescriptorsCalled;
115    private boolean preAddColumnCalled;
116    private boolean postAddColumnCalled;
117    private boolean preModifyColumnCalled;
118    private boolean postModifyColumnCalled;
119    private boolean preDeleteColumnCalled;
120    private boolean postDeleteColumnCalled;
121    private boolean preEnableTableCalled;
122    private boolean postEnableTableCalled;
123    private boolean preDisableTableCalled;
124    private boolean postDisableTableCalled;
125    private boolean preAbortProcedureCalled;
126    private boolean postAbortProcedureCalled;
127    private boolean preGetProceduresCalled;
128    private boolean postGetProceduresCalled;
129    private boolean preGetLocksCalled;
130    private boolean postGetLocksCalled;
131    private boolean preMoveCalled;
132    private boolean postMoveCalled;
133    private boolean preAssignCalled;
134    private boolean postAssignCalled;
135    private boolean preUnassignCalled;
136    private boolean postUnassignCalled;
137    private boolean preRegionOfflineCalled;
138    private boolean postRegionOfflineCalled;
139    private boolean preBalanceCalled;
140    private boolean postBalanceCalled;
141    private boolean preBalanceSwitchCalled;
142    private boolean postBalanceSwitchCalled;
143    private boolean preShutdownCalled;
144    private boolean preStopMasterCalled;
145    private boolean preMasterInitializationCalled;
146    private boolean postStartMasterCalled;
147    private boolean startCalled;
148    private boolean stopCalled;
149    private boolean preSnapshotCalled;
150    private boolean postSnapshotCalled;
151    private boolean preListSnapshotCalled;
152    private boolean postListSnapshotCalled;
153    private boolean preCloneSnapshotCalled;
154    private boolean postCloneSnapshotCalled;
155    private boolean preRestoreSnapshotCalled;
156    private boolean postRestoreSnapshotCalled;
157    private boolean preDeleteSnapshotCalled;
158    private boolean postDeleteSnapshotCalled;
159    private boolean preCreateTableActionCalled;
160    private boolean postCompletedCreateTableActionCalled;
161    private boolean preDeleteTableActionCalled;
162    private boolean postCompletedDeleteTableActionCalled;
163    private boolean preTruncateTableActionCalled;
164    private boolean postCompletedTruncateTableActionCalled;
165    private boolean preAddColumnFamilyActionCalled;
166    private boolean postCompletedAddColumnFamilyActionCalled;
167    private boolean preModifyColumnFamilyActionCalled;
168    private boolean postCompletedModifyColumnFamilyActionCalled;
169    private boolean preDeleteColumnFamilyActionCalled;
170    private boolean postCompletedDeleteColumnFamilyActionCalled;
171    private boolean preEnableTableActionCalled;
172    private boolean postCompletedEnableTableActionCalled;
173    private boolean preDisableTableActionCalled;
174    private boolean postCompletedDisableTableActionCalled;
175    private boolean preModifyTableActionCalled;
176    private boolean postCompletedModifyTableActionCalled;
177    private boolean preGetTableDescriptorsCalled;
178    private boolean postGetTableDescriptorsCalled;
179    private boolean postGetTableNamesCalled;
180    private boolean preGetTableNamesCalled;
181    private boolean preMergeRegionsCalled;
182    private boolean postMergeRegionsCalled;
183    private boolean preRequestLockCalled;
184    private boolean postRequestLockCalled;
185    private boolean preLockHeartbeatCalled;
186    private boolean postLockHeartbeatCalled;
187    private boolean preMasterStoreFlushCalled;
188    private boolean postMasterStoreFlushCalled;
189    private boolean preUpdateMasterConfigurationCalled;
190    private boolean postUpdateMasterConfigurationCalled;
191
192    public void resetStates() {
193      preCreateTableRegionInfosCalled = false;
194      preCreateTableCalled = false;
195      postCreateTableCalled = false;
196      preDeleteTableCalled = false;
197      postDeleteTableCalled = false;
198      preTruncateTableCalled = false;
199      postTruncateTableCalled = false;
200      preModifyTableCalled = false;
201      postModifyTableCalled = false;
202      preCreateNamespaceCalled = false;
203      postCreateNamespaceCalled = false;
204      preDeleteNamespaceCalled = false;
205      postDeleteNamespaceCalled = false;
206      preModifyNamespaceCalled = false;
207      postModifyNamespaceCalled = false;
208      preGetNamespaceDescriptorCalled = false;
209      postGetNamespaceDescriptorCalled = false;
210      preListNamespacesCalled = false;
211      postListNamespacesCalled = false;
212      preListNamespaceDescriptorsCalled = false;
213      postListNamespaceDescriptorsCalled = false;
214      preAddColumnCalled = false;
215      postAddColumnCalled = false;
216      preModifyColumnCalled = false;
217      postModifyColumnCalled = false;
218      preDeleteColumnCalled = false;
219      postDeleteColumnCalled = false;
220      preEnableTableCalled = false;
221      postEnableTableCalled = false;
222      preDisableTableCalled = false;
223      postDisableTableCalled = false;
224      preAbortProcedureCalled = false;
225      postAbortProcedureCalled = false;
226      preGetProceduresCalled = false;
227      postGetProceduresCalled = false;
228      preGetLocksCalled = false;
229      postGetLocksCalled = false;
230      preMoveCalled = false;
231      postMoveCalled = false;
232      preAssignCalled = false;
233      postAssignCalled = false;
234      preUnassignCalled = false;
235      postUnassignCalled = false;
236      preRegionOfflineCalled = false;
237      postRegionOfflineCalled = false;
238      preBalanceCalled = false;
239      postBalanceCalled = false;
240      preBalanceSwitchCalled = false;
241      postBalanceSwitchCalled = false;
242      preShutdownCalled = false;
243      preStopMasterCalled = false;
244      preSnapshotCalled = false;
245      postSnapshotCalled = false;
246      preListSnapshotCalled = false;
247      postListSnapshotCalled = false;
248      preCloneSnapshotCalled = false;
249      postCloneSnapshotCalled = false;
250      preRestoreSnapshotCalled = false;
251      postRestoreSnapshotCalled = false;
252      preDeleteSnapshotCalled = false;
253      postDeleteSnapshotCalled = false;
254      preCreateTableActionCalled = false;
255      postCompletedCreateTableActionCalled = false;
256      preDeleteTableActionCalled = false;
257      postCompletedDeleteTableActionCalled = false;
258      preTruncateTableActionCalled = false;
259      postCompletedTruncateTableActionCalled = false;
260      preModifyTableActionCalled = false;
261      postCompletedModifyTableActionCalled = false;
262      preAddColumnFamilyActionCalled = false;
263      postCompletedAddColumnFamilyActionCalled = false;
264      preModifyColumnFamilyActionCalled = false;
265      postCompletedModifyColumnFamilyActionCalled = false;
266      preDeleteColumnFamilyActionCalled = false;
267      postCompletedDeleteColumnFamilyActionCalled = false;
268      preEnableTableActionCalled = false;
269      postCompletedEnableTableActionCalled = false;
270      preDisableTableActionCalled = false;
271      postCompletedDisableTableActionCalled = false;
272      preGetTableDescriptorsCalled = false;
273      postGetTableDescriptorsCalled = false;
274      postGetTableNamesCalled = false;
275      preGetTableNamesCalled = false;
276      preMergeRegionsCalled = false;
277      postMergeRegionsCalled = false;
278      preRequestLockCalled = false;
279      postRequestLockCalled = false;
280      preLockHeartbeatCalled = false;
281      postLockHeartbeatCalled = false;
282      preMasterStoreFlushCalled = false;
283      postMasterStoreFlushCalled = false;
284      preUpdateMasterConfigurationCalled = false;
285      postUpdateMasterConfigurationCalled = false;
286    }
287
288    @Override
289    public Optional<MasterObserver> getMasterObserver() {
290      return Optional.of(this);
291    }
292
293    @Override
294    public void preMergeRegions(final ObserverContext<MasterCoprocessorEnvironment> ctx,
295      final RegionInfo[] regionsToMerge) throws IOException {
296      preMergeRegionsCalled = true;
297    }
298
299    @Override
300    public void postMergeRegions(final ObserverContext<MasterCoprocessorEnvironment> ctx,
301      final RegionInfo[] regionsToMerge) throws IOException {
302      postMergeRegionsCalled = true;
303    }
304
305    public boolean wasMergeRegionsCalled() {
306      return preMergeRegionsCalled && postMergeRegionsCalled;
307    }
308
309    @Override
310    public TableDescriptor preCreateTableRegionsInfos(
311      ObserverContext<MasterCoprocessorEnvironment> ctx, TableDescriptor desc) throws IOException {
312      preCreateTableRegionInfosCalled = true;
313      return desc;
314    }
315
316    @Override
317    public void preCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
318      TableDescriptor desc, RegionInfo[] regions) throws IOException {
319      preCreateTableCalled = true;
320    }
321
322    @Override
323    public void postCreateTable(ObserverContext<MasterCoprocessorEnvironment> env,
324      TableDescriptor desc, RegionInfo[] regions) throws IOException {
325      postCreateTableCalled = true;
326    }
327
328    public boolean wasCreateTableCalled() {
329      return preCreateTableRegionInfosCalled && preCreateTableCalled && postCreateTableCalled;
330    }
331
332    public boolean preCreateTableCalledOnly() {
333      return preCreateTableRegionInfosCalled && preCreateTableCalled && !postCreateTableCalled;
334    }
335
336    @Override
337    public void preDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
338      TableName tableName) throws IOException {
339      preDeleteTableCalled = true;
340    }
341
342    @Override
343    public void postDeleteTable(ObserverContext<MasterCoprocessorEnvironment> env,
344      TableName tableName) throws IOException {
345      postDeleteTableCalled = true;
346    }
347
348    public boolean wasDeleteTableCalled() {
349      return preDeleteTableCalled && postDeleteTableCalled;
350    }
351
352    public boolean preDeleteTableCalledOnly() {
353      return preDeleteTableCalled && !postDeleteTableCalled;
354    }
355
356    @Override
357    public void preTruncateTable(ObserverContext<MasterCoprocessorEnvironment> env,
358      TableName tableName) throws IOException {
359      preTruncateTableCalled = true;
360    }
361
362    @Override
363    public void postTruncateTable(ObserverContext<MasterCoprocessorEnvironment> env,
364      TableName tableName) throws IOException {
365      postTruncateTableCalled = true;
366    }
367
368    public boolean wasTruncateTableCalled() {
369      return preTruncateTableCalled && postTruncateTableCalled;
370    }
371
372    public boolean preTruncateTableCalledOnly() {
373      return preTruncateTableCalled && !postTruncateTableCalled;
374    }
375
376    @Override
377    public TableDescriptor preModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
378      TableName tableName, final TableDescriptor currentDescriptor,
379      final TableDescriptor newDescriptor) throws IOException {
380      preModifyTableCalled = true;
381      return newDescriptor;
382    }
383
384    @Override
385    public void postModifyTable(ObserverContext<MasterCoprocessorEnvironment> env,
386      TableName tableName, final TableDescriptor oldDescriptor,
387      final TableDescriptor currentDescriptor) throws IOException {
388      postModifyTableCalled = true;
389    }
390
391    public boolean wasModifyTableCalled() {
392      return preModifyTableCalled && postModifyTableCalled;
393    }
394
395    public boolean preModifyTableCalledOnly() {
396      return preModifyTableCalled && !postModifyTableCalled;
397    }
398
399    @Override
400    public void preCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
401      NamespaceDescriptor ns) throws IOException {
402      preCreateNamespaceCalled = true;
403    }
404
405    @Override
406    public void postCreateNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
407      NamespaceDescriptor ns) throws IOException {
408      postCreateNamespaceCalled = true;
409    }
410
411    public boolean wasCreateNamespaceCalled() {
412      return preCreateNamespaceCalled && postCreateNamespaceCalled;
413    }
414
415    public boolean preCreateNamespaceCalledOnly() {
416      return preCreateNamespaceCalled && !postCreateNamespaceCalled;
417    }
418
419    @Override
420    public void preDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> env, String name)
421      throws IOException {
422      preDeleteNamespaceCalled = true;
423    }
424
425    @Override
426    public void postDeleteNamespace(ObserverContext<MasterCoprocessorEnvironment> env, String name)
427      throws IOException {
428      postDeleteNamespaceCalled = true;
429    }
430
431    public boolean wasDeleteNamespaceCalled() {
432      return preDeleteNamespaceCalled && postDeleteNamespaceCalled;
433    }
434
435    public boolean preDeleteNamespaceCalledOnly() {
436      return preDeleteNamespaceCalled && !postDeleteNamespaceCalled;
437    }
438
439    @Override
440    public void preModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
441      NamespaceDescriptor currentNsDesc, NamespaceDescriptor newNsDesc) throws IOException {
442      preModifyNamespaceCalled = true;
443    }
444
445    @Override
446    public void postModifyNamespace(ObserverContext<MasterCoprocessorEnvironment> env,
447      NamespaceDescriptor oldNsDesc, NamespaceDescriptor currentNsDesc) throws IOException {
448      postModifyNamespaceCalled = true;
449    }
450
451    public boolean wasModifyNamespaceCalled() {
452      return preModifyNamespaceCalled && postModifyNamespaceCalled;
453    }
454
455    public boolean preModifyNamespaceCalledOnly() {
456      return preModifyNamespaceCalled && !postModifyNamespaceCalled;
457    }
458
459    @Override
460    public void preGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
461      String namespace) throws IOException {
462      preGetNamespaceDescriptorCalled = true;
463    }
464
465    @Override
466    public void postGetNamespaceDescriptor(ObserverContext<MasterCoprocessorEnvironment> ctx,
467      NamespaceDescriptor ns) throws IOException {
468      postGetNamespaceDescriptorCalled = true;
469    }
470
471    public boolean wasGetNamespaceDescriptorCalled() {
472      return preGetNamespaceDescriptorCalled && postGetNamespaceDescriptorCalled;
473    }
474
475    @Override
476    public void preListNamespaces(ObserverContext<MasterCoprocessorEnvironment> ctx,
477      List<String> namespaces) {
478      preListNamespacesCalled = true;
479    }
480
481    @Override
482    public void postListNamespaces(ObserverContext<MasterCoprocessorEnvironment> ctx,
483      List<String> namespaces) {
484      postListNamespacesCalled = true;
485    }
486
487    @Override
488    public void preListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> env,
489      List<NamespaceDescriptor> descriptors) throws IOException {
490      preListNamespaceDescriptorsCalled = true;
491    }
492
493    @Override
494    public void postListNamespaceDescriptors(ObserverContext<MasterCoprocessorEnvironment> env,
495      List<NamespaceDescriptor> descriptors) throws IOException {
496      postListNamespaceDescriptorsCalled = true;
497    }
498
499    public boolean wasListNamespaceDescriptorsCalled() {
500      return preListNamespaceDescriptorsCalled && postListNamespaceDescriptorsCalled;
501    }
502
503    public boolean preListNamespaceDescriptorsCalledOnly() {
504      return preListNamespaceDescriptorsCalled && !postListNamespaceDescriptorsCalled;
505    }
506
507    @Override
508    public void preEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
509      TableName tableName) throws IOException {
510      preEnableTableCalled = true;
511    }
512
513    @Override
514    public void postEnableTable(ObserverContext<MasterCoprocessorEnvironment> env,
515      TableName tableName) throws IOException {
516      postEnableTableCalled = true;
517    }
518
519    public boolean wasEnableTableCalled() {
520      return preEnableTableCalled && postEnableTableCalled;
521    }
522
523    public boolean preEnableTableCalledOnly() {
524      return preEnableTableCalled && !postEnableTableCalled;
525    }
526
527    @Override
528    public void preDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
529      TableName tableName) throws IOException {
530      preDisableTableCalled = true;
531    }
532
533    @Override
534    public void postDisableTable(ObserverContext<MasterCoprocessorEnvironment> env,
535      TableName tableName) throws IOException {
536      postDisableTableCalled = true;
537    }
538
539    public boolean wasDisableTableCalled() {
540      return preDisableTableCalled && postDisableTableCalled;
541    }
542
543    public boolean preDisableTableCalledOnly() {
544      return preDisableTableCalled && !postDisableTableCalled;
545    }
546
547    @Override
548    public void preAbortProcedure(ObserverContext<MasterCoprocessorEnvironment> ctx,
549      final long procId) throws IOException {
550      preAbortProcedureCalled = true;
551    }
552
553    @Override
554    public void postAbortProcedure(ObserverContext<MasterCoprocessorEnvironment> ctx)
555      throws IOException {
556      postAbortProcedureCalled = true;
557    }
558
559    public boolean wasAbortProcedureCalled() {
560      return preAbortProcedureCalled && postAbortProcedureCalled;
561    }
562
563    public boolean wasPreAbortProcedureCalledOnly() {
564      return preAbortProcedureCalled && !postAbortProcedureCalled;
565    }
566
567    @Override
568    public void preGetProcedures(ObserverContext<MasterCoprocessorEnvironment> ctx)
569      throws IOException {
570      preGetProceduresCalled = true;
571    }
572
573    @Override
574    public void postGetProcedures(ObserverContext<MasterCoprocessorEnvironment> ctx)
575      throws IOException {
576      postGetProceduresCalled = true;
577    }
578
579    public boolean wasGetProceduresCalled() {
580      return preGetProceduresCalled && postGetProceduresCalled;
581    }
582
583    public boolean wasPreGetProceduresCalledOnly() {
584      return preGetProceduresCalled && !postGetProceduresCalled;
585    }
586
587    @Override
588    public void preGetLocks(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
589      preGetLocksCalled = true;
590    }
591
592    @Override
593    public void postGetLocks(ObserverContext<MasterCoprocessorEnvironment> ctx) throws IOException {
594      postGetLocksCalled = true;
595    }
596
597    public boolean wasGetLocksCalled() {
598      return preGetLocksCalled && postGetLocksCalled;
599    }
600
601    public boolean wasPreGetLocksCalledOnly() {
602      return preGetLocksCalled && !postGetLocksCalled;
603    }
604
605    @Override
606    public void preMove(ObserverContext<MasterCoprocessorEnvironment> env, RegionInfo region,
607      ServerName srcServer, ServerName destServer) throws IOException {
608      preMoveCalled = true;
609    }
610
611    @Override
612    public void postMove(ObserverContext<MasterCoprocessorEnvironment> env, RegionInfo region,
613      ServerName srcServer, ServerName destServer) throws IOException {
614      postMoveCalled = true;
615    }
616
617    public boolean wasMoveCalled() {
618      return preMoveCalled && postMoveCalled;
619    }
620
621    public boolean preMoveCalledOnly() {
622      return preMoveCalled && !postMoveCalled;
623    }
624
625    @Override
626    public void preAssign(ObserverContext<MasterCoprocessorEnvironment> env,
627      final RegionInfo regionInfo) throws IOException {
628      preAssignCalled = true;
629    }
630
631    @Override
632    public void postAssign(ObserverContext<MasterCoprocessorEnvironment> env,
633      final RegionInfo regionInfo) throws IOException {
634      postAssignCalled = true;
635    }
636
637    public boolean wasAssignCalled() {
638      return preAssignCalled && postAssignCalled;
639    }
640
641    public boolean preAssignCalledOnly() {
642      return preAssignCalled && !postAssignCalled;
643    }
644
645    @Override
646    public void preUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
647      final RegionInfo regionInfo) throws IOException {
648      preUnassignCalled = true;
649    }
650
651    @Override
652    public void postUnassign(ObserverContext<MasterCoprocessorEnvironment> env,
653      final RegionInfo regionInfo) throws IOException {
654      postUnassignCalled = true;
655    }
656
657    public boolean wasUnassignCalled() {
658      return preUnassignCalled && postUnassignCalled;
659    }
660
661    public boolean preUnassignCalledOnly() {
662      return preUnassignCalled && !postUnassignCalled;
663    }
664
665    @Override
666    public void preRegionOffline(ObserverContext<MasterCoprocessorEnvironment> env,
667      final RegionInfo regionInfo) throws IOException {
668      preRegionOfflineCalled = true;
669    }
670
671    @Override
672    public void postRegionOffline(ObserverContext<MasterCoprocessorEnvironment> env,
673      final RegionInfo regionInfo) throws IOException {
674      postRegionOfflineCalled = true;
675    }
676
677    public boolean wasRegionOfflineCalled() {
678      return preRegionOfflineCalled && postRegionOfflineCalled;
679    }
680
681    public boolean preRegionOfflineCalledOnly() {
682      return preRegionOfflineCalled && !postRegionOfflineCalled;
683    }
684
685    @Override
686    public void preBalance(ObserverContext<MasterCoprocessorEnvironment> env,
687      BalanceRequest request) throws IOException {
688      preBalanceCalled = true;
689    }
690
691    @Override
692    public void postBalance(ObserverContext<MasterCoprocessorEnvironment> env,
693      BalanceRequest request, List<RegionPlan> plans) throws IOException {
694      postBalanceCalled = true;
695    }
696
697    public boolean wasBalanceCalled() {
698      return preBalanceCalled && postBalanceCalled;
699    }
700
701    public boolean preBalanceCalledOnly() {
702      return preBalanceCalled && !postBalanceCalled;
703    }
704
705    @Override
706    public void preBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env, boolean b)
707      throws IOException {
708      preBalanceSwitchCalled = true;
709    }
710
711    @Override
712    public void postBalanceSwitch(ObserverContext<MasterCoprocessorEnvironment> env,
713      boolean oldValue, boolean newValue) throws IOException {
714      postBalanceSwitchCalled = true;
715    }
716
717    public boolean wasBalanceSwitchCalled() {
718      return preBalanceSwitchCalled && postBalanceSwitchCalled;
719    }
720
721    public boolean preBalanceSwitchCalledOnly() {
722      return preBalanceSwitchCalled && !postBalanceSwitchCalled;
723    }
724
725    @Override
726    public void preShutdown(ObserverContext<MasterCoprocessorEnvironment> env) throws IOException {
727      preShutdownCalled = true;
728    }
729
730    public boolean wasShutdownCalled() {
731      return preShutdownCalled;
732    }
733
734    @Override
735    public void preStopMaster(ObserverContext<MasterCoprocessorEnvironment> env)
736      throws IOException {
737      preStopMasterCalled = true;
738    }
739
740    public boolean wasStopMasterCalled() {
741      return preStopMasterCalled;
742    }
743
744    @Override
745    public void preMasterInitialization(ObserverContext<MasterCoprocessorEnvironment> ctx)
746      throws IOException {
747      preMasterInitializationCalled = true;
748    }
749
750    public boolean wasMasterInitializationCalled() {
751      return preMasterInitializationCalled;
752    }
753
754    @Override
755    public void postStartMaster(ObserverContext<MasterCoprocessorEnvironment> ctx)
756      throws IOException {
757      postStartMasterCalled = true;
758    }
759
760    public boolean wasStartMasterCalled() {
761      return postStartMasterCalled;
762    }
763
764    @Override
765    public void start(CoprocessorEnvironment env) throws IOException {
766      startCalled = true;
767    }
768
769    @Override
770    public void stop(CoprocessorEnvironment env) throws IOException {
771      stopCalled = true;
772    }
773
774    public boolean wasStarted() {
775      return startCalled;
776    }
777
778    public boolean wasStopped() {
779      return stopCalled;
780    }
781
782    @Override
783    public void preSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
784      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
785      throws IOException {
786      preSnapshotCalled = true;
787    }
788
789    @Override
790    public void postSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
791      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
792      throws IOException {
793      postSnapshotCalled = true;
794    }
795
796    public boolean wasSnapshotCalled() {
797      return preSnapshotCalled && postSnapshotCalled;
798    }
799
800    @Override
801    public void preListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
802      final SnapshotDescription snapshot) throws IOException {
803      preListSnapshotCalled = true;
804    }
805
806    @Override
807    public void postListSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
808      final SnapshotDescription snapshot) throws IOException {
809      postListSnapshotCalled = true;
810    }
811
812    public boolean wasListSnapshotCalled() {
813      return preListSnapshotCalled && postListSnapshotCalled;
814    }
815
816    @Override
817    public void preCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
818      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
819      throws IOException {
820      preCloneSnapshotCalled = true;
821    }
822
823    @Override
824    public void postCloneSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
825      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
826      throws IOException {
827      postCloneSnapshotCalled = true;
828    }
829
830    public boolean wasCloneSnapshotCalled() {
831      return preCloneSnapshotCalled && postCloneSnapshotCalled;
832    }
833
834    @Override
835    public void preRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
836      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
837      throws IOException {
838      preRestoreSnapshotCalled = true;
839    }
840
841    @Override
842    public void postRestoreSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
843      final SnapshotDescription snapshot, final TableDescriptor hTableDescriptor)
844      throws IOException {
845      postRestoreSnapshotCalled = true;
846    }
847
848    public boolean wasRestoreSnapshotCalled() {
849      return preRestoreSnapshotCalled && postRestoreSnapshotCalled;
850    }
851
852    @Override
853    public void preDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
854      final SnapshotDescription snapshot) throws IOException {
855      preDeleteSnapshotCalled = true;
856    }
857
858    @Override
859    public void postDeleteSnapshot(final ObserverContext<MasterCoprocessorEnvironment> ctx,
860      final SnapshotDescription snapshot) throws IOException {
861      postDeleteSnapshotCalled = true;
862    }
863
864    public boolean wasDeleteSnapshotCalled() {
865      return preDeleteSnapshotCalled && postDeleteSnapshotCalled;
866    }
867
868    @Override
869    public void preCreateTableAction(final ObserverContext<MasterCoprocessorEnvironment> env,
870      final TableDescriptor desc, final RegionInfo[] regions) throws IOException {
871      preCreateTableActionCalled = true;
872    }
873
874    @Override
875    public void postCompletedCreateTableAction(
876      final ObserverContext<MasterCoprocessorEnvironment> ctx, final TableDescriptor desc,
877      final RegionInfo[] regions) throws IOException {
878      postCompletedCreateTableActionCalled = true;
879      tableCreationLatch.countDown();
880    }
881
882    public boolean wasPreCreateTableActionCalled() {
883      return preCreateTableActionCalled;
884    }
885
886    public boolean wasCreateTableActionCalled() {
887      return preCreateTableActionCalled && postCompletedCreateTableActionCalled;
888    }
889
890    public boolean wasCreateTableActionCalledOnly() {
891      return preCreateTableActionCalled && !postCompletedCreateTableActionCalled;
892    }
893
894    @Override
895    public void preDeleteTableAction(final ObserverContext<MasterCoprocessorEnvironment> env,
896      final TableName tableName) throws IOException {
897      preDeleteTableActionCalled = true;
898    }
899
900    @Override
901    public void postCompletedDeleteTableAction(
902      final ObserverContext<MasterCoprocessorEnvironment> ctx, final TableName tableName)
903      throws IOException {
904      postCompletedDeleteTableActionCalled = true;
905      tableDeletionLatch.countDown();
906    }
907
908    public boolean wasDeleteTableActionCalled() {
909      return preDeleteTableActionCalled && postCompletedDeleteTableActionCalled;
910    }
911
912    public boolean wasDeleteTableActionCalledOnly() {
913      return preDeleteTableActionCalled && !postCompletedDeleteTableActionCalled;
914    }
915
916    @Override
917    public void preTruncateTableAction(final ObserverContext<MasterCoprocessorEnvironment> env,
918      final TableName tableName) throws IOException {
919      preTruncateTableActionCalled = true;
920    }
921
922    @Override
923    public void postCompletedTruncateTableAction(
924      final ObserverContext<MasterCoprocessorEnvironment> ctx, final TableName tableName)
925      throws IOException {
926      postCompletedTruncateTableActionCalled = true;
927    }
928
929    public boolean wasTruncateTableActionCalled() {
930      return preTruncateTableActionCalled && postCompletedTruncateTableActionCalled;
931    }
932
933    public boolean wasTruncateTableActionCalledOnly() {
934      return preTruncateTableActionCalled && !postCompletedTruncateTableActionCalled;
935    }
936
937    @Override
938    public void preModifyTableAction(final ObserverContext<MasterCoprocessorEnvironment> env,
939      final TableName tableName, final TableDescriptor currentDescriptor,
940      final TableDescriptor newDescriptor) throws IOException {
941      preModifyTableActionCalled = true;
942    }
943
944    @Override
945    public void postCompletedModifyTableAction(
946      final ObserverContext<MasterCoprocessorEnvironment> env, final TableName tableName,
947      final TableDescriptor oldDescriptor, final TableDescriptor currentDescriptor)
948      throws IOException {
949      postCompletedModifyTableActionCalled = true;
950    }
951
952    public boolean wasModifyTableActionCalled() {
953      return preModifyTableActionCalled && postCompletedModifyTableActionCalled;
954    }
955
956    public boolean wasModifyTableActionCalledOnly() {
957      return preModifyTableActionCalled && !postCompletedModifyTableActionCalled;
958    }
959
960    @Override
961    public void preEnableTableAction(final ObserverContext<MasterCoprocessorEnvironment> ctx,
962      final TableName tableName) throws IOException {
963      preEnableTableActionCalled = true;
964    }
965
966    @Override
967    public void postCompletedEnableTableAction(
968      final ObserverContext<MasterCoprocessorEnvironment> ctx, final TableName tableName)
969      throws IOException {
970      postCompletedEnableTableActionCalled = true;
971    }
972
973    public boolean wasEnableTableActionCalled() {
974      return preEnableTableActionCalled && postCompletedEnableTableActionCalled;
975    }
976
977    public boolean preEnableTableActionCalledOnly() {
978      return preEnableTableActionCalled && !postCompletedEnableTableActionCalled;
979    }
980
981    @Override
982    public void preDisableTableAction(final ObserverContext<MasterCoprocessorEnvironment> ctx,
983      final TableName tableName) throws IOException {
984      preDisableTableActionCalled = true;
985    }
986
987    @Override
988    public void postCompletedDisableTableAction(
989      final ObserverContext<MasterCoprocessorEnvironment> ctx, final TableName tableName)
990      throws IOException {
991      postCompletedDisableTableActionCalled = true;
992    }
993
994    public boolean wasDisableTableActionCalled() {
995      return preDisableTableActionCalled && postCompletedDisableTableActionCalled;
996    }
997
998    public boolean preDisableTableActionCalledOnly() {
999      return preDisableTableActionCalled && !postCompletedDisableTableActionCalled;
1000    }
1001
1002    @Override
1003    public void preGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1004      List<TableName> tableNamesList, List<TableDescriptor> descriptors, String regex)
1005      throws IOException {
1006      preGetTableDescriptorsCalled = true;
1007    }
1008
1009    @Override
1010    public void postGetTableDescriptors(ObserverContext<MasterCoprocessorEnvironment> ctx,
1011      List<TableName> tableNamesList, List<TableDescriptor> descriptors, String regex)
1012      throws IOException {
1013      postGetTableDescriptorsCalled = true;
1014    }
1015
1016    public boolean wasGetTableDescriptorsCalled() {
1017      return preGetTableDescriptorsCalled && postGetTableDescriptorsCalled;
1018    }
1019
1020    @Override
1021    public void preGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
1022      List<TableDescriptor> descriptors, String regex) throws IOException {
1023      preGetTableNamesCalled = true;
1024    }
1025
1026    @Override
1027    public void postGetTableNames(ObserverContext<MasterCoprocessorEnvironment> ctx,
1028      List<TableDescriptor> descriptors, String regex) throws IOException {
1029      postGetTableNamesCalled = true;
1030    }
1031
1032    public boolean wasGetTableNamesCalled() {
1033      return preGetTableNamesCalled && postGetTableNamesCalled;
1034    }
1035
1036    @Override
1037    public void preMasterStoreFlush(ObserverContext<MasterCoprocessorEnvironment> ctx)
1038      throws IOException {
1039      preMasterStoreFlushCalled = true;
1040    }
1041
1042    @Override
1043    public void postMasterStoreFlush(ObserverContext<MasterCoprocessorEnvironment> ctx)
1044      throws IOException {
1045      postMasterStoreFlushCalled = true;
1046    }
1047
1048    @Override
1049    public void preRequestLock(ObserverContext<MasterCoprocessorEnvironment> ctx, String namespace,
1050      TableName tableName, RegionInfo[] regionInfos, String description) throws IOException {
1051      preRequestLockCalled = true;
1052    }
1053
1054    @Override
1055    public void postRequestLock(ObserverContext<MasterCoprocessorEnvironment> ctx, String namespace,
1056      TableName tableName, RegionInfo[] regionInfos, String description) throws IOException {
1057      postRequestLockCalled = true;
1058    }
1059
1060    @Override
1061    public void preLockHeartbeat(ObserverContext<MasterCoprocessorEnvironment> ctx, TableName tn,
1062      String description) throws IOException {
1063      preLockHeartbeatCalled = true;
1064    }
1065
1066    @Override
1067    public void postLockHeartbeat(ObserverContext<MasterCoprocessorEnvironment> ctx)
1068      throws IOException {
1069      postLockHeartbeatCalled = true;
1070    }
1071
1072    public boolean preAndPostForQueueLockAndHeartbeatLockCalled() {
1073      return preRequestLockCalled && postRequestLockCalled && preLockHeartbeatCalled
1074        && postLockHeartbeatCalled;
1075    }
1076
1077    @Override
1078    public void preMergeRegionsCommitAction(final ObserverContext<MasterCoprocessorEnvironment> ctx,
1079      final RegionInfo[] regionsToMerge, final List<Mutation> metaEntries) throws IOException {
1080    }
1081
1082    @Override
1083    public void preUpdateMasterConfiguration(ObserverContext<MasterCoprocessorEnvironment> ctx,
1084      Configuration preReloadConf) throws IOException {
1085      preUpdateMasterConfigurationCalled = true;
1086    }
1087
1088    @Override
1089    public void postUpdateMasterConfiguration(ObserverContext<MasterCoprocessorEnvironment> ctx,
1090      Configuration postReloadConf) throws IOException {
1091      postUpdateMasterConfigurationCalled = true;
1092    }
1093  }
1094
1095  private static HBaseTestingUtil UTIL = new HBaseTestingUtil();
1096  private static String TEST_SNAPSHOT = "observed_snapshot";
1097  private static TableName TEST_CLONE = TableName.valueOf("observed_clone");
1098  private static byte[] TEST_FAMILY = Bytes.toBytes("fam1");
1099  @Rule
1100  public TestName name = new TestName();
1101
1102  @BeforeClass
1103  public static void setupBeforeClass() throws Exception {
1104    Configuration conf = UTIL.getConfiguration();
1105    conf.set(CoprocessorHost.MASTER_COPROCESSOR_CONF_KEY, CPMasterObserver.class.getName());
1106    // We need more than one data server on this test
1107    UTIL.startMiniCluster(2);
1108  }
1109
1110  @AfterClass
1111  public static void tearDownAfterClass() throws Exception {
1112    UTIL.shutdownMiniCluster();
1113  }
1114
1115  @Test
1116  public void testStarted() throws Exception {
1117    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1118
1119    HMaster master = cluster.getMaster();
1120    assertTrue("Master should be active", master.isActiveMaster());
1121    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1122    assertNotNull("CoprocessorHost should not be null", host);
1123    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1124    assertNotNull("CPMasterObserver coprocessor not found or not installed!", cp);
1125
1126    // check basic lifecycle
1127    assertTrue("MasterObserver should have been started", cp.wasStarted());
1128    assertTrue("preMasterInitialization() hook should have been called",
1129      cp.wasMasterInitializationCalled());
1130    assertTrue("postStartMaster() hook should have been called", cp.wasStartMasterCalled());
1131  }
1132
1133  @Test
1134  public void testTableOperations() throws Exception {
1135    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1136    final TableName tableName = TableName.valueOf(name.getMethodName());
1137    HMaster master = cluster.getMaster();
1138    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1139    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1140    cp.resetStates();
1141    assertFalse("No table created yet", cp.wasCreateTableCalled());
1142
1143    // create a table
1144    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
1145      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
1146    try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
1147      Admin admin = connection.getAdmin()) {
1148      tableCreationLatch = new CountDownLatch(1);
1149      admin.createTable(tableDescriptor,
1150        Arrays.copyOfRange(HBaseTestingUtil.KEYS, 1, HBaseTestingUtil.KEYS.length));
1151
1152      assertTrue("Test table should be created", cp.wasCreateTableCalled());
1153      tableCreationLatch.await();
1154      assertTrue("Table pre create handler called.", cp.wasPreCreateTableActionCalled());
1155      assertTrue("Table create handler should be called.", cp.wasCreateTableActionCalled());
1156
1157      RegionLocator regionLocator = connection.getRegionLocator(tableDescriptor.getTableName());
1158      List<HRegionLocation> regions = regionLocator.getAllRegionLocations();
1159
1160      admin.mergeRegionsAsync(regions.get(0).getRegion().getEncodedNameAsBytes(),
1161        regions.get(1).getRegion().getEncodedNameAsBytes(), true).get();
1162      assertTrue("Coprocessor should have been called on region merge", cp.wasMergeRegionsCalled());
1163
1164      tableCreationLatch = new CountDownLatch(1);
1165      admin.disableTable(tableName);
1166      assertTrue(admin.isTableDisabled(tableName));
1167      assertTrue("Coprocessor should have been called on table disable",
1168        cp.wasDisableTableCalled());
1169      assertTrue("Disable table handler should be called.", cp.wasDisableTableActionCalled());
1170
1171      // enable
1172      assertFalse(cp.wasEnableTableCalled());
1173      admin.enableTable(tableName);
1174      assertTrue(admin.isTableEnabled(tableName));
1175      assertTrue("Coprocessor should have been called on table enable", cp.wasEnableTableCalled());
1176      assertTrue("Enable table handler should be called.", cp.wasEnableTableActionCalled());
1177
1178      admin.disableTable(tableName);
1179      assertTrue(admin.isTableDisabled(tableName));
1180
1181      // modify table
1182      tableDescriptor = TableDescriptorBuilder.newBuilder(tableDescriptor)
1183        .setMaxFileSize(512 * 1024 * 1024).build();
1184      modifyTableSync(admin, tableName, tableDescriptor);
1185      assertTrue("Test table should have been modified", cp.wasModifyTableCalled());
1186
1187      // truncate table
1188      admin.truncateTable(tableName, false);
1189
1190      // delete table
1191      admin.disableTable(tableName);
1192      assertTrue(admin.isTableDisabled(tableName));
1193      deleteTable(admin, tableName);
1194      assertFalse("Test table should have been deleted", admin.tableExists(tableName));
1195      assertTrue("Coprocessor should have been called on table delete", cp.wasDeleteTableCalled());
1196      assertTrue("Delete table handler should be called.", cp.wasDeleteTableActionCalled());
1197
1198      // When bypass was supported, we'd turn off bypass and rerun tests. Leaving rerun in place.
1199      cp.resetStates();
1200
1201      admin.createTable(tableDescriptor);
1202      assertTrue("Test table should be created", cp.wasCreateTableCalled());
1203      tableCreationLatch.await();
1204      assertTrue("Table pre create handler called.", cp.wasPreCreateTableActionCalled());
1205      assertTrue("Table create handler should be called.", cp.wasCreateTableActionCalled());
1206
1207      // disable
1208      assertFalse(cp.wasDisableTableCalled());
1209      assertFalse(cp.wasDisableTableActionCalled());
1210      admin.disableTable(tableName);
1211      assertTrue(admin.isTableDisabled(tableName));
1212      assertTrue("Coprocessor should have been called on table disable",
1213        cp.wasDisableTableCalled());
1214      assertTrue("Disable table handler should be called.", cp.wasDisableTableActionCalled());
1215
1216      // modify table
1217      tableDescriptor = TableDescriptorBuilder.newBuilder(tableDescriptor)
1218        .setMaxFileSize(512 * 1024 * 1024).build();
1219      modifyTableSync(admin, tableName, tableDescriptor);
1220      assertTrue("Test table should have been modified", cp.wasModifyTableCalled());
1221
1222      // enable
1223      assertFalse(cp.wasEnableTableCalled());
1224      assertFalse(cp.wasEnableTableActionCalled());
1225      admin.enableTable(tableName);
1226      assertTrue(admin.isTableEnabled(tableName));
1227      assertTrue("Coprocessor should have been called on table enable", cp.wasEnableTableCalled());
1228      assertTrue("Enable table handler should be called.", cp.wasEnableTableActionCalled());
1229
1230      // disable again
1231      admin.disableTable(tableName);
1232      assertTrue(admin.isTableDisabled(tableName));
1233
1234      // delete table
1235      assertFalse("No table deleted yet", cp.wasDeleteTableCalled());
1236      assertFalse("Delete table handler should not be called.", cp.wasDeleteTableActionCalled());
1237      deleteTable(admin, tableName);
1238      assertFalse("Test table should have been deleted", admin.tableExists(tableName));
1239      assertTrue("Coprocessor should have been called on table delete", cp.wasDeleteTableCalled());
1240      assertTrue("Delete table handler should be called.", cp.wasDeleteTableActionCalled());
1241    }
1242  }
1243
1244  @Test
1245  public void testSnapshotOperations() throws Exception {
1246    final TableName tableName = TableName.valueOf(name.getMethodName());
1247    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1248    HMaster master = cluster.getMaster();
1249    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1250    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1251    cp.resetStates();
1252
1253    // create a table
1254    TableDescriptor tableDescriptor = TableDescriptorBuilder.newBuilder(tableName)
1255      .setColumnFamily(ColumnFamilyDescriptorBuilder.of(TEST_FAMILY)).build();
1256    Admin admin = UTIL.getAdmin();
1257
1258    tableCreationLatch = new CountDownLatch(1);
1259    admin.createTable(tableDescriptor);
1260    tableCreationLatch.await();
1261    tableCreationLatch = new CountDownLatch(1);
1262
1263    admin.disableTable(tableName);
1264    assertTrue(admin.isTableDisabled(tableName));
1265
1266    try {
1267      // Test snapshot operation
1268      assertFalse("Coprocessor should not have been called yet", cp.wasSnapshotCalled());
1269      admin.snapshot(TEST_SNAPSHOT, tableName);
1270      assertTrue("Coprocessor should have been called on snapshot", cp.wasSnapshotCalled());
1271
1272      // Test list operation
1273      admin.listSnapshots();
1274      assertTrue("Coprocessor should have been called on snapshot list",
1275        cp.wasListSnapshotCalled());
1276
1277      // Test clone operation
1278      admin.cloneSnapshot(TEST_SNAPSHOT, TEST_CLONE);
1279      assertTrue("Coprocessor should have been called on snapshot clone",
1280        cp.wasCloneSnapshotCalled());
1281      assertFalse("Coprocessor restore should not have been called on snapshot clone",
1282        cp.wasRestoreSnapshotCalled());
1283      admin.disableTable(TEST_CLONE);
1284      assertTrue(admin.isTableDisabled(tableName));
1285      deleteTable(admin, TEST_CLONE);
1286
1287      // Test restore operation
1288      cp.resetStates();
1289      admin.restoreSnapshot(TEST_SNAPSHOT);
1290      assertTrue("Coprocessor should have been called on snapshot restore",
1291        cp.wasRestoreSnapshotCalled());
1292      assertFalse("Coprocessor clone should not have been called on snapshot restore",
1293        cp.wasCloneSnapshotCalled());
1294
1295      admin.deleteSnapshot(TEST_SNAPSHOT);
1296      assertTrue("Coprocessor should have been called on snapshot delete",
1297        cp.wasDeleteSnapshotCalled());
1298    } finally {
1299      deleteTable(admin, tableName);
1300    }
1301  }
1302
1303  @Test
1304  public void testNamespaceOperations() throws Exception {
1305    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1306    String testNamespace = "observed_ns";
1307    HMaster master = cluster.getMaster();
1308    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1309    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1310
1311    // create a table
1312    Admin admin = UTIL.getAdmin();
1313
1314    admin.listNamespaces();
1315    assertTrue("preListNamespaces should have been called", cp.preListNamespacesCalled);
1316    assertTrue("postListNamespaces should have been called", cp.postListNamespacesCalled);
1317
1318    admin.createNamespace(NamespaceDescriptor.create(testNamespace).build());
1319    assertTrue("Test namespace should be created", cp.wasCreateNamespaceCalled());
1320
1321    assertNotNull(admin.getNamespaceDescriptor(testNamespace));
1322    assertTrue("Test namespace descriptor should have been called",
1323      cp.wasGetNamespaceDescriptorCalled());
1324    // This test used to do a bunch w/ bypass but bypass of these table and namespace stuff has
1325    // been removed so the testing code was removed.
1326  }
1327
1328  private void modifyTableSync(Admin admin, TableName tableName, TableDescriptor tableDescriptor)
1329    throws IOException {
1330    admin.modifyTable(tableDescriptor);
1331    // wait until modify table finishes
1332    for (int t = 0; t < 100; t++) { // 10 sec timeout
1333      TableDescriptor td = admin.getDescriptor(tableDescriptor.getTableName());
1334      if (td.equals(tableDescriptor)) {
1335        break;
1336      }
1337      Threads.sleep(100);
1338    }
1339  }
1340
1341  @Test
1342  public void testRegionTransitionOperations() throws Exception {
1343    final TableName tableName = TableName.valueOf(name.getMethodName());
1344    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1345
1346    HMaster master = cluster.getMaster();
1347    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1348    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1349    cp.resetStates();
1350
1351    Table table = UTIL.createMultiRegionTable(tableName, TEST_FAMILY);
1352
1353    try (RegionLocator r = UTIL.getConnection().getRegionLocator(tableName)) {
1354      UTIL.waitUntilAllRegionsAssigned(tableName);
1355
1356      List<HRegionLocation> regions = r.getAllRegionLocations();
1357      HRegionLocation firstGoodPair = null;
1358      for (HRegionLocation e : regions) {
1359        if (e.getServerName() != null) {
1360          firstGoodPair = e;
1361          break;
1362        }
1363      }
1364      assertNotNull("Found a non-null entry", firstGoodPair);
1365      LOG.info("Found " + firstGoodPair.toString());
1366      // Try to force a move
1367      Collection<ServerName> servers = master.getClusterMetrics().getLiveServerMetrics().keySet();
1368      String destName = null;
1369      String serverNameForFirstRegion = firstGoodPair.getServerName().toString();
1370      LOG.info("serverNameForFirstRegion=" + serverNameForFirstRegion);
1371      ServerName masterServerName = master.getServerName();
1372      boolean found = false;
1373      // Find server that is NOT carrying the first region
1374      for (ServerName info : servers) {
1375        LOG.info("ServerName=" + info);
1376        if (
1377          !serverNameForFirstRegion.equals(info.getServerName()) && !masterServerName.equals(info)
1378        ) {
1379          destName = info.toString();
1380          found = true;
1381          break;
1382        }
1383      }
1384      assertTrue("Found server", found);
1385      LOG.info("Found " + destName);
1386      master.getMasterRpcServices().moveRegion(null, RequestConverter.buildMoveRegionRequest(
1387        firstGoodPair.getRegion().getEncodedNameAsBytes(), ServerName.valueOf(destName)));
1388      assertTrue("Coprocessor should have been called on region move", cp.wasMoveCalled());
1389
1390      // make sure balancer is on
1391      master.balanceSwitch(true);
1392      assertTrue("Coprocessor should have been called on balance switch",
1393        cp.wasBalanceSwitchCalled());
1394
1395      // turn balancer off
1396      master.balanceSwitch(false);
1397
1398      // wait for assignments to finish, if any
1399      UTIL.waitUntilNoRegionsInTransition();
1400
1401      // move half the open regions from RS 0 to RS 1
1402      HRegionServer rs = cluster.getRegionServer(0);
1403      byte[] destRS = Bytes.toBytes(cluster.getRegionServer(1).getServerName().toString());
1404      // Make sure no regions are in transition now
1405      UTIL.waitUntilNoRegionsInTransition();
1406      List<RegionInfo> openRegions = ProtobufUtil.getOnlineRegions(rs.getRSRpcServices());
1407      int moveCnt = openRegions.size() / 2;
1408      for (int i = 0; i < moveCnt; i++) {
1409        RegionInfo info = openRegions.get(i);
1410        if (!info.isMetaRegion()) {
1411          master.getMasterRpcServices().moveRegion(null,
1412            RequestConverter.buildMoveRegionRequest(openRegions.get(i).getEncodedNameAsBytes(),
1413              ServerName.valueOf(Bytes.toString(destRS))));
1414        }
1415      }
1416      // Make sure no regions are in transition now
1417      UTIL.waitUntilNoRegionsInTransition();
1418      // now trigger a balance
1419      master.balanceSwitch(true);
1420      master.balance();
1421      assertTrue("Coprocessor should be called on region rebalancing", cp.wasBalanceCalled());
1422    } finally {
1423      Admin admin = UTIL.getAdmin();
1424      admin.disableTable(tableName);
1425      deleteTable(admin, tableName);
1426    }
1427  }
1428
1429  @Test
1430  public void testTableDescriptorsEnumeration() throws Exception {
1431    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1432
1433    HMaster master = cluster.getMaster();
1434    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1435    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1436    cp.resetStates();
1437
1438    GetTableDescriptorsRequest req =
1439      RequestConverter.buildGetTableDescriptorsRequest((List<TableName>) null);
1440    master.getMasterRpcServices().getTableDescriptors(null, req);
1441
1442    assertTrue("Coprocessor should be called on table descriptors request",
1443      cp.wasGetTableDescriptorsCalled());
1444  }
1445
1446  @Test
1447  public void testTableNamesEnumeration() throws Exception {
1448    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1449
1450    HMaster master = cluster.getMaster();
1451    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1452    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1453    cp.resetStates();
1454
1455    master.getMasterRpcServices().getTableNames(null, GetTableNamesRequest.newBuilder().build());
1456    assertTrue("Coprocessor should be called on table names request", cp.wasGetTableNamesCalled());
1457  }
1458
1459  @Test
1460  public void testAbortProcedureOperation() throws Exception {
1461    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1462
1463    HMaster master = cluster.getMaster();
1464    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1465    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1466    cp.resetStates();
1467
1468    master.abortProcedure(1, true);
1469    assertTrue("Coprocessor should be called on abort procedure request",
1470      cp.wasAbortProcedureCalled());
1471  }
1472
1473  @Test
1474  public void testGetProceduresOperation() throws Exception {
1475    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1476
1477    HMaster master = cluster.getMaster();
1478    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1479    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1480    cp.resetStates();
1481
1482    master.getProcedures();
1483    assertTrue("Coprocessor should be called on get procedures request",
1484      cp.wasGetProceduresCalled());
1485  }
1486
1487  @Test
1488  public void testGetLocksOperation() throws Exception {
1489    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1490
1491    HMaster master = cluster.getMaster();
1492    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1493    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1494    cp.resetStates();
1495
1496    master.getLocks();
1497    assertTrue("Coprocessor should be called on get locks request", cp.wasGetLocksCalled());
1498  }
1499
1500  private void deleteTable(Admin admin, TableName tableName) throws Exception {
1501    // NOTE: We need a latch because admin is not sync,
1502    // so the postOp coprocessor method may be called after the admin operation returned.
1503    tableDeletionLatch = new CountDownLatch(1);
1504    admin.deleteTable(tableName);
1505    tableDeletionLatch.await();
1506    tableDeletionLatch = new CountDownLatch(1);
1507  }
1508
1509  @Test
1510  public void testQueueLockAndLockHeartbeatOperations() throws Exception {
1511    HMaster master = UTIL.getMiniHBaseCluster().getMaster();
1512    CPMasterObserver cp = master.getMasterCoprocessorHost().findCoprocessor(CPMasterObserver.class);
1513    cp.resetStates();
1514
1515    final TableName tableName = TableName.valueOf("testLockedTable");
1516    long procId = master.getLockManager().remoteLocks().requestTableLock(tableName,
1517      LockType.EXCLUSIVE, "desc", null);
1518    master.getLockManager().remoteLocks().lockHeartbeat(procId, false);
1519
1520    assertTrue(cp.preAndPostForQueueLockAndHeartbeatLockCalled());
1521
1522    ProcedureTestingUtility.waitNoProcedureRunning(master.getMasterProcedureExecutor());
1523    ProcedureTestingUtility.assertProcNotFailed(master.getMasterProcedureExecutor(), procId);
1524  }
1525
1526  @Test
1527  public void testMasterStoreOperations() throws Exception {
1528    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1529    HMaster master = cluster.getMaster();
1530    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1531    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1532    cp.resetStates();
1533    assertFalse("No master store flush call", cp.preMasterStoreFlushCalled);
1534    assertFalse("No master store flush call", cp.postMasterStoreFlushCalled);
1535
1536    try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
1537      Admin admin = connection.getAdmin()) {
1538      admin.flushMasterStore();
1539
1540      assertTrue("Master store flush called", cp.preMasterStoreFlushCalled);
1541      assertTrue("Master store flush called", cp.postMasterStoreFlushCalled);
1542    }
1543  }
1544
1545  @Test
1546  public void testUpdateConfiguration() throws Exception {
1547    SingleProcessHBaseCluster cluster = UTIL.getHBaseCluster();
1548    HMaster master = cluster.getMaster();
1549    MasterCoprocessorHost host = master.getMasterCoprocessorHost();
1550    CPMasterObserver cp = host.findCoprocessor(CPMasterObserver.class);
1551    cp.resetStates();
1552    assertFalse("No update configuration call", cp.preUpdateMasterConfigurationCalled);
1553    assertFalse("No update configuration call", cp.postUpdateMasterConfigurationCalled);
1554
1555    try (Connection connection = ConnectionFactory.createConnection(UTIL.getConfiguration());
1556      Admin admin = connection.getAdmin()) {
1557      admin.updateConfiguration();
1558
1559      assertTrue("Update configuration called", cp.preUpdateMasterConfigurationCalled);
1560      assertTrue("Update configuration called", cp.postUpdateMasterConfigurationCalled);
1561    }
1562  }
1563}