HBASE-18317 Implement async admin operations for Normalizer/CleanerChore/CatalogJanitor

This commit is contained in:
Guanghao Zhang 2017-07-07 21:13:38 +08:00
parent 359f97711f
commit 5d4e4f2007
5 changed files with 441 additions and 136 deletions

View File

@ -283,40 +283,6 @@ public interface AsyncAdmin {
*/
CompletableFuture<List<NamespaceDescriptor>> listNamespaceDescriptors();
/**
* Turn the load balancer on or off.
* @param on
* @return Previous balancer value wrapped by a {@link CompletableFuture}.
*/
CompletableFuture<Boolean> setBalancerOn(boolean on);
/**
* Invoke the balancer. Will run the balancer and if regions to move, it will go ahead and do the
* reassignments. Can NOT run for various reasons. Check logs.
* @return True if balancer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
*/
default CompletableFuture<Boolean> balance() {
return balance(false);
}
/**
* Invoke the balancer. Will run the balancer and if regions to move, it will go ahead and do the
* reassignments. If there is region in transition, force parameter of true would still run
* balancer. Can *not* run for other reasons. Check logs.
* @param forcible whether we should force balance even if there is region in transition.
* @return True if balancer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
*/
CompletableFuture<Boolean> balance(boolean forcible);
/**
* Query the current state of the balancer.
* @return true if the balance switch is on, false otherwise The return value will be wrapped by a
* {@link CompletableFuture}.
*/
CompletableFuture<Boolean> isBalancerOn();
/**
* Close a region. For expert-admins Runs close on the regionserver. The master will not be
* informed of the close.
@ -891,4 +857,101 @@ public interface AsyncAdmin {
* @return the last major compaction timestamp wrapped by a {@link CompletableFuture}
*/
CompletableFuture<Optional<Long>> getLastMajorCompactionTimestampForRegion(byte[] regionName);
/**
* Turn the load balancer on or off.
* @param on
* @return Previous balancer value wrapped by a {@link CompletableFuture}.
*/
CompletableFuture<Boolean> setBalancerOn(boolean on);
/**
* Invoke the balancer. Will run the balancer and if regions to move, it will go ahead and do the
* reassignments. Can NOT run for various reasons. Check logs.
* @return True if balancer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
*/
default CompletableFuture<Boolean> balance() {
return balance(false);
}
/**
* Invoke the balancer. Will run the balancer and if regions to move, it will go ahead and do the
* reassignments. If there is region in transition, force parameter of true would still run
* balancer. Can *not* run for other reasons. Check logs.
* @param forcible whether we should force balance even if there is region in transition.
* @return True if balancer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
*/
CompletableFuture<Boolean> balance(boolean forcible);
/**
* Query the current state of the balancer.
* @return true if the balance switch is on, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}.
*/
CompletableFuture<Boolean> isBalancerOn();
/**
* Set region normalizer on/off.
* @param on whether normalizer should be on or off
* @return Previous normalizer value wrapped by a {@link CompletableFuture}
*/
CompletableFuture<Boolean> setNormalizerOn(boolean on);
/**
* Query the current state of the region normalizer
* @return true if region normalizer is on, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}
*/
CompletableFuture<Boolean> isNormalizerOn();
/**
* Invoke region normalizer. Can NOT run for various reasons. Check logs.
* @return true if region normalizer ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}
*/
CompletableFuture<Boolean> normalize();
/**
* Turn the cleaner chore on/off.
* @param on
* @return Previous cleaner state wrapped by a {@link CompletableFuture}
*/
CompletableFuture<Boolean> setCleanerChoreOn(boolean on);
/**
* Query the current state of the cleaner chore.
* @return true if cleaner chore is on, false otherwise. The return value will be wrapped by
* a {@link CompletableFuture}
*/
CompletableFuture<Boolean> isCleanerChoreOn();
/**
* Ask for cleaner chore to run.
* @return true if cleaner chore ran, false otherwise. The return value will be wrapped by a
* {@link CompletableFuture}
*/
CompletableFuture<Boolean> runCleanerChore();
/**
* Turn the catalog janitor on/off.
* @param on
* @return the previous state wrapped by a {@link CompletableFuture}
*/
CompletableFuture<Boolean> setCatalogJanitorOn(boolean on);
/**
* Query on the catalog janitor state.
* @return true if the catalog janitor is on, false otherwise. The return value will be
* wrapped by a {@link CompletableFuture}
*/
CompletableFuture<Boolean> isCatalogJanitorOn();
/**
* Ask for a scan of the catalog table.
* @return the number of entries cleaned. The return value will be wrapped by a
* {@link CompletableFuture}
*/
CompletableFuture<Integer> runCatalogJanitor();
}

View File

@ -201,21 +201,6 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
return wrap(rawAdmin.listNamespaceDescriptors());
}
@Override
public CompletableFuture<Boolean> setBalancerOn(boolean on) {
return wrap(rawAdmin.setBalancerOn(on));
}
@Override
public CompletableFuture<Boolean> balance(boolean forcible) {
return wrap(rawAdmin.balance(forcible));
}
@Override
public CompletableFuture<Boolean> isBalancerOn() {
return wrap(rawAdmin.isBalancerOn());
}
@Override
public CompletableFuture<Boolean> closeRegion(byte[] regionName, Optional<ServerName> serverName) {
return wrap(rawAdmin.closeRegion(regionName, serverName));
@ -489,4 +474,64 @@ public class AsyncHBaseAdmin implements AsyncAdmin {
byte[] regionName) {
return wrap(rawAdmin.getLastMajorCompactionTimestampForRegion(regionName));
}
@Override
public CompletableFuture<Boolean> setBalancerOn(boolean on) {
return wrap(rawAdmin.setBalancerOn(on));
}
@Override
public CompletableFuture<Boolean> balance(boolean forcible) {
return wrap(rawAdmin.balance(forcible));
}
@Override
public CompletableFuture<Boolean> isBalancerOn() {
return wrap(rawAdmin.isBalancerOn());
}
@Override
public CompletableFuture<Boolean> setNormalizerOn(boolean on) {
return wrap(rawAdmin.setNormalizerOn(on));
}
@Override
public CompletableFuture<Boolean> isNormalizerOn() {
return wrap(rawAdmin.isNormalizerOn());
}
@Override
public CompletableFuture<Boolean> normalize() {
return wrap(rawAdmin.normalize());
}
@Override
public CompletableFuture<Boolean> setCleanerChoreOn(boolean enabled) {
return wrap(rawAdmin.setCleanerChoreOn(enabled));
}
@Override
public CompletableFuture<Boolean> isCleanerChoreOn() {
return wrap(rawAdmin.isCleanerChoreOn());
}
@Override
public CompletableFuture<Boolean> runCleanerChore() {
return wrap(rawAdmin.runCleanerChore());
}
@Override
public CompletableFuture<Boolean> setCatalogJanitorOn(boolean enabled) {
return wrap(rawAdmin.setCatalogJanitorOn(enabled));
}
@Override
public CompletableFuture<Boolean> isCatalogJanitorOn() {
return wrap(rawAdmin.isCatalogJanitorOn());
}
@Override
public CompletableFuture<Integer> runCatalogJanitor() {
return wrap(rawAdmin.runCatalogJanitor());
}
}

View File

@ -116,6 +116,8 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteSnap
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteSnapshotResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DisableTableRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DisableTableResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableCatalogJanitorRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableCatalogJanitorResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTableRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.EnableTableResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteColumnRequest;
@ -142,8 +144,14 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteTabl
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.DeleteTableResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsBalancerEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsBalancerEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCatalogJanitorEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCleanerChoreEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsCleanerChoreEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsInMaintenanceModeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsInMaintenanceModeResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsNormalizerEnabledRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsNormalizerEnabledResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsProcedureDoneRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsProcedureDoneResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.IsSnapshotDoneRequest;
@ -164,12 +172,22 @@ import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ModifyName
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.ModifyNamespaceResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MoveRegionRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.MoveRegionResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.NormalizeRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.NormalizeResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.OfflineRegionRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.OfflineRegionResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RestoreSnapshotRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RestoreSnapshotResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunCatalogScanRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunCatalogScanResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunCleanerChoreRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.RunCleanerChoreResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetBalancerRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetBalancerRunningResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetCleanerChoreRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetCleanerChoreRunningResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetNormalizerRunningRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetNormalizerRunningResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaRequest;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SetQuotaResponse;
import org.apache.hadoop.hbase.shaded.protobuf.generated.MasterProtos.SnapshotRequest;
@ -673,39 +691,6 @@ public class RawAsyncHBaseAdmin implements AsyncAdmin {
.toNamespaceDescriptorList(resp))).call();
}
@Override
public CompletableFuture<Boolean> setBalancerOn(final boolean on) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<SetBalancerRunningRequest, SetBalancerRunningResponse, Boolean> call(controller,
stub, RequestConverter.buildSetBalancerRunningRequest(on, true),
(s, c, req, done) -> s.setBalancerRunning(c, req, done),
(resp) -> resp.getPrevBalanceValue())).call();
}
@Override
public CompletableFuture<Boolean> balance(boolean forcible) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this.<BalanceRequest, BalanceResponse, Boolean> call(controller,
stub, RequestConverter.buildBalanceRequest(forcible),
(s, c, req, done) -> s.balance(c, req, done), (resp) -> resp.getBalancerRan())).call();
}
@Override
public CompletableFuture<Boolean> isBalancerOn() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this.<IsBalancerEnabledRequest, IsBalancerEnabledResponse, Boolean> call(
controller, stub, RequestConverter.buildIsBalancerEnabledRequest(),
(s, c, req, done) -> s.isBalancerEnabled(c, req, done), (resp) -> resp.getEnabled()))
.call();
}
@Override
public CompletableFuture<Boolean> closeRegion(byte[] regionName, Optional<ServerName> serverName) {
CompletableFuture<Boolean> future = new CompletableFuture<>();
@ -2486,4 +2471,143 @@ public class RawAsyncHBaseAdmin implements AsyncAdmin {
});
return future;
}
@Override
public CompletableFuture<Boolean> setBalancerOn(final boolean on) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<SetBalancerRunningRequest, SetBalancerRunningResponse, Boolean> call(controller,
stub, RequestConverter.buildSetBalancerRunningRequest(on, true),
(s, c, req, done) -> s.setBalancerRunning(c, req, done),
(resp) -> resp.getPrevBalanceValue())).call();
}
@Override
public CompletableFuture<Boolean> balance(boolean forcible) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this.<BalanceRequest, BalanceResponse, Boolean> call(controller,
stub, RequestConverter.buildBalanceRequest(forcible),
(s, c, req, done) -> s.balance(c, req, done), (resp) -> resp.getBalancerRan())).call();
}
@Override
public CompletableFuture<Boolean> isBalancerOn() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this.<IsBalancerEnabledRequest, IsBalancerEnabledResponse, Boolean> call(
controller, stub, RequestConverter.buildIsBalancerEnabledRequest(),
(s, c, req, done) -> s.isBalancerEnabled(c, req, done), (resp) -> resp.getEnabled()))
.call();
}
@Override
public CompletableFuture<Boolean> setNormalizerOn(boolean on) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<SetNormalizerRunningRequest, SetNormalizerRunningResponse, Boolean> call(
controller, stub, RequestConverter.buildSetNormalizerRunningRequest(on), (s, c,
req, done) -> s.setNormalizerRunning(c, req, done), (resp) -> resp
.getPrevNormalizerValue())).call();
}
@Override
public CompletableFuture<Boolean> isNormalizerOn() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<IsNormalizerEnabledRequest, IsNormalizerEnabledResponse, Boolean> call(controller,
stub, RequestConverter.buildIsNormalizerEnabledRequest(),
(s, c, req, done) -> s.isNormalizerEnabled(c, req, done),
(resp) -> resp.getEnabled())).call();
}
@Override
public CompletableFuture<Boolean> normalize() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this.<NormalizeRequest, NormalizeResponse, Boolean> call(
controller, stub, RequestConverter.buildNormalizeRequest(),
(s, c, req, done) -> s.normalize(c, req, done), (resp) -> resp.getNormalizerRan()))
.call();
}
@Override
public CompletableFuture<Boolean> setCleanerChoreOn(boolean enabled) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<SetCleanerChoreRunningRequest, SetCleanerChoreRunningResponse, Boolean> call(
controller, stub, RequestConverter.buildSetCleanerChoreRunningRequest(enabled), (s,
c, req, done) -> s.setCleanerChoreRunning(c, req, done), (resp) -> resp
.getPrevValue())).call();
}
@Override
public CompletableFuture<Boolean> isCleanerChoreOn() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<IsCleanerChoreEnabledRequest, IsCleanerChoreEnabledResponse, Boolean> call(
controller, stub, RequestConverter.buildIsCleanerChoreEnabledRequest(), (s, c, req,
done) -> s.isCleanerChoreEnabled(c, req, done), (resp) -> resp.getValue()))
.call();
}
@Override
public CompletableFuture<Boolean> runCleanerChore() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<RunCleanerChoreRequest, RunCleanerChoreResponse, Boolean> call(controller, stub,
RequestConverter.buildRunCleanerChoreRequest(),
(s, c, req, done) -> s.runCleanerChore(c, req, done),
(resp) -> resp.getCleanerChoreRan())).call();
}
@Override
public CompletableFuture<Boolean> setCatalogJanitorOn(boolean enabled) {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<EnableCatalogJanitorRequest, EnableCatalogJanitorResponse, Boolean> call(
controller, stub, RequestConverter.buildEnableCatalogJanitorRequest(enabled), (s,
c, req, done) -> s.enableCatalogJanitor(c, req, done), (resp) -> resp
.getPrevValue())).call();
}
@Override
public CompletableFuture<Boolean> isCatalogJanitorOn() {
return this
.<Boolean> newMasterCaller()
.action(
(controller, stub) -> this
.<IsCatalogJanitorEnabledRequest, IsCatalogJanitorEnabledResponse, Boolean> call(
controller, stub, RequestConverter.buildIsCatalogJanitorEnabledRequest(), (s, c,
req, done) -> s.isCatalogJanitorEnabled(c, req, done), (resp) -> resp
.getValue())).call();
}
@Override
public CompletableFuture<Integer> runCatalogJanitor() {
return this
.<Integer> newMasterCaller()
.action(
(controller, stub) -> this.<RunCatalogScanRequest, RunCatalogScanResponse, Integer> call(
controller, stub, RequestConverter.buildCatalogScanRequest(),
(s, c, req, done) -> s.runCatalogScan(c, req, done), (resp) -> resp.getScanResult()))
.call();
}
}

View File

@ -1,54 +0,0 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
@RunWith(Parameterized.class)
@Category({ MediumTests.class, ClientTests.class })
public class TestAsyncBalancerAdminApi extends TestAsyncAdminBase {
@Test
public void testBalancer() throws Exception {
boolean initialState = admin.isBalancerOn().get();
// Start the balancer, wait for it.
boolean prevState = admin.setBalancerOn(!initialState).get();
// The previous state should be the original state we observed
assertEquals(initialState, prevState);
// Current state should be opposite of the original
assertEquals(!initialState, admin.isBalancerOn().get());
// Reset it back to what it was
prevState = admin.setBalancerOn(initialState).get();
// The previous state should be the opposite of the initial state
assertEquals(!initialState, prevState);
// Current state should be the original state again
assertEquals(initialState, admin.isBalancerOn().get());
}
}

View File

@ -0,0 +1,127 @@
/**
* Licensed to the Apache Software Foundation (ASF) under one
* or more contributor license agreements. See the NOTICE file
* distributed with this work for additional information
* regarding copyright ownership. The ASF licenses this file
* to you under the Apache License, Version 2.0 (the
* "License"); you may not use this file except in compliance
* with the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.apache.hadoop.hbase.client;
import static org.junit.Assert.assertEquals;
import org.apache.hadoop.hbase.testclassification.ClientTests;
import org.apache.hadoop.hbase.testclassification.MediumTests;
import org.junit.Test;
import org.junit.experimental.categories.Category;
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
/**
* Test the admin operations for Balancer, Normalizer, CleanerChore, and CatalogJanitor.
*/
@RunWith(Parameterized.class)
@Category({ MediumTests.class, ClientTests.class })
public class TestAsyncToolAdminApi extends TestAsyncAdminBase {
@Test
public void testBalancer() throws Exception {
boolean initialState = admin.isBalancerOn().get();
// Start the balancer, wait for it.
boolean prevState = admin.setBalancerOn(!initialState).get();
// The previous state should be the original state we observed
assertEquals(initialState, prevState);
// Current state should be opposite of the original
assertEquals(!initialState, admin.isBalancerOn().get());
// Reset it back to what it was
prevState = admin.setBalancerOn(initialState).get();
// The previous state should be the opposite of the initial state
assertEquals(!initialState, prevState);
// Current state should be the original state again
assertEquals(initialState, admin.isBalancerOn().get());
}
@Test
public void testNormalizer() throws Exception {
boolean initialState = admin.isNormalizerOn().get();
// flip state
boolean prevState = admin.setNormalizerOn(!initialState).get();
// The previous state should be the original state we observed
assertEquals(initialState, prevState);
// Current state should be opposite of the original
assertEquals(!initialState, admin.isNormalizerOn().get());
// Reset it back to what it was
prevState = admin.setNormalizerOn(initialState).get();
// The previous state should be the opposite of the initial state
assertEquals(!initialState, prevState);
// Current state should be the original state again
assertEquals(initialState, admin.isNormalizerOn().get());
}
@Test
public void testCleanerChore() throws Exception {
boolean initialState = admin.isCleanerChoreOn().get();
// flip state
boolean prevState = admin.setCleanerChoreOn(!initialState).get();
// The previous state should be the original state we observed
assertEquals(initialState, prevState);
// Current state should be opposite of the original
assertEquals(!initialState, admin.isCleanerChoreOn().get());
// Reset it back to what it was
prevState = admin.setCleanerChoreOn(initialState).get();
// The previous state should be the opposite of the initial state
assertEquals(!initialState, prevState);
// Current state should be the original state again
assertEquals(initialState, admin.isCleanerChoreOn().get());
}
@Test
public void testCatalogJanitor() throws Exception {
boolean initialState = admin.isCatalogJanitorOn().get();
// flip state
boolean prevState = admin.setCatalogJanitorOn(!initialState).get();
// The previous state should be the original state we observed
assertEquals(initialState, prevState);
// Current state should be opposite of the original
assertEquals(!initialState, admin.isCatalogJanitorOn().get());
// Reset it back to what it was
prevState = admin.setCatalogJanitorOn(initialState).get();
// The previous state should be the opposite of the initial state
assertEquals(!initialState, prevState);
// Current state should be the original state again
assertEquals(initialState, admin.isCatalogJanitorOn().get());
}
}