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.master.procedure;
019
020import static org.junit.Assert.assertEquals;
021import static org.junit.Assert.assertFalse;
022import static org.junit.Assert.assertThrows;
023import static org.junit.Assert.assertTrue;
024
025import java.io.IOException;
026import java.util.Optional;
027import java.util.concurrent.Future;
028import org.apache.hadoop.hbase.HBaseClassTestRule;
029import org.apache.hadoop.hbase.HBaseTestingUtil;
030import org.apache.hadoop.hbase.ServerName;
031import org.apache.hadoop.hbase.master.assignment.MockMasterServices;
032import org.apache.hadoop.hbase.procedure2.RemoteProcedureDispatcher;
033import org.apache.hadoop.hbase.testclassification.MasterTests;
034import org.apache.hadoop.hbase.testclassification.MediumTests;
035import org.junit.After;
036import org.junit.Before;
037import org.junit.ClassRule;
038import org.junit.Rule;
039import org.junit.Test;
040import org.junit.experimental.categories.Category;
041import org.junit.rules.TestName;
042import org.slf4j.Logger;
043import org.slf4j.LoggerFactory;
044
045@Category({ MasterTests.class, MediumTests.class })
046public class TestReloadQuotasProcedure {
047  private static final Logger LOG = LoggerFactory.getLogger(TestReloadQuotasProcedure.class);
048
049  @ClassRule
050  public static final HBaseClassTestRule CLASS_RULE =
051    HBaseClassTestRule.forClass(TestReloadQuotasProcedure.class);
052
053  @Rule
054  public TestName name = new TestName();
055
056  private HBaseTestingUtil util;
057  private MockMasterServices master;
058  private TestServerRemoteProcedure.MockRSProcedureDispatcher rsDispatcher;
059
060  @Before
061  public void setUp() throws Exception {
062    util = new HBaseTestingUtil();
063    master = new MockMasterServices(util.getConfiguration());
064    rsDispatcher = new TestServerRemoteProcedure.MockRSProcedureDispatcher(master);
065    master.start(2, rsDispatcher);
066  }
067
068  @After
069  public void tearDown() throws Exception {
070    master.stop("tearDown");
071  }
072
073  @Test
074  public void itHandlesClassNotFoundExceptionGracefully() throws Exception {
075    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
076    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
077
078    ClassNotFoundException classNotFound =
079      new ClassNotFoundException("ReloadQuotasCallable not found");
080    IOException wrappedException = new IOException("Remote call failed", classNotFound);
081
082    boolean result =
083      procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), wrappedException);
084
085    assertTrue(result);
086  }
087
088  @Test
089  public void itReturnsFailureForOtherExceptions() throws Exception {
090    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
091    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
092
093    IOException otherException = new IOException("Some other error");
094
095    boolean result =
096      procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), otherException);
097
098    assertFalse(result);
099  }
100
101  @Test
102  public void itReturnsSuccessForNoError() throws Exception {
103    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
104    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
105
106    boolean result = procedure.complete(master.getMasterProcedureExecutor().getEnvironment(), null);
107
108    assertTrue(result);
109  }
110
111  @Test
112  public void itCorrectlyDetectsCauseClass() {
113    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure();
114
115    ClassNotFoundException classNotFound = new ClassNotFoundException("test");
116    IOException wrappedException = new IOException("wrapper", classNotFound);
117    RuntimeException outerWrapper = new RuntimeException("outer", wrappedException);
118
119    assertTrue(procedure.containsCause(outerWrapper, ClassNotFoundException.class));
120    assertFalse(procedure.containsCause(outerWrapper, IllegalArgumentException.class));
121    assertTrue(procedure.containsCause(classNotFound, ClassNotFoundException.class));
122  }
123
124  @Test
125  public void itValidatesServerNameInRemoteCallBuild() throws Exception {
126    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
127    ServerName wrongServer = master.getServerManager().getOnlineServersList().get(1);
128    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
129
130    MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment();
131
132    Optional<RemoteProcedureDispatcher.RemoteOperation> result =
133      procedure.remoteCallBuild(env, targetServer);
134    assertTrue(result.isPresent());
135    assertTrue(result.get() instanceof RSProcedureDispatcher.ServerOperation);
136
137    assertThrows(IllegalArgumentException.class, () -> {
138      procedure.remoteCallBuild(env, wrongServer);
139    });
140  }
141
142  @Test
143  public void itCreatesCorrectRemoteOperation() throws Exception {
144    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
145    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
146    MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment();
147
148    Optional<RemoteProcedureDispatcher.RemoteOperation> operation =
149      procedure.remoteCallBuild(env, targetServer);
150
151    assertTrue(operation.isPresent());
152    RSProcedureDispatcher.ServerOperation serverOp =
153      (RSProcedureDispatcher.ServerOperation) operation.get();
154    assertEquals(serverOp.getRemoteProcedure(), procedure);
155    assertEquals(serverOp.buildRequest().getProcId(), procedure.getProcId());
156  }
157
158  @Test
159  public void itThrowsUnsupportedOperationExceptionOnRollback() throws Exception {
160    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
161    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
162    MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment();
163
164    assertThrows(UnsupportedOperationException.class, () -> {
165      procedure.rollback(env);
166    });
167  }
168
169  @Test
170  public void itReturnsFalseOnAbort() throws Exception {
171    ServerName targetServer = master.getServerManager().getOnlineServersList().get(0);
172    ReloadQuotasProcedure procedure = new ReloadQuotasProcedure(targetServer);
173    MasterProcedureEnv env = master.getMasterProcedureExecutor().getEnvironment();
174
175    boolean result = procedure.abort(env);
176
177    assertFalse(result);
178  }
179
180  private Future<byte[]> submitProcedure(ReloadQuotasProcedure procedure) {
181    return ProcedureSyncWait.submitProcedure(master.getMasterProcedureExecutor(), procedure);
182  }
183}