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