/* * 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.ambari.server.serveraction; import static org.easymock.EasyMock.anyBoolean; import static org.easymock.EasyMock.anyInt; import static org.easymock.EasyMock.anyLong; import static org.easymock.EasyMock.anyObject; import static org.easymock.EasyMock.createNiceMock; import static org.easymock.EasyMock.expect; import static org.junit.Assert.assertEquals; import static org.mockito.Matchers.any; import static org.mockito.Matchers.anyString; import static org.mockito.Mockito.doAnswer; import static org.mockito.Mockito.mock; import static org.mockito.Mockito.when; import java.sql.SQLException; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; import org.apache.ambari.server.AmbariException; import org.apache.ambari.server.H2DatabaseCleaner; import org.apache.ambari.server.Role; import org.apache.ambari.server.RoleCommand; import org.apache.ambari.server.actionmanager.ActionDBAccessor; import org.apache.ambari.server.actionmanager.HostRoleCommand; import org.apache.ambari.server.actionmanager.HostRoleStatus; import org.apache.ambari.server.actionmanager.Request; import org.apache.ambari.server.actionmanager.RequestStatus; import org.apache.ambari.server.actionmanager.Stage; import org.apache.ambari.server.actionmanager.StageFactory; import org.apache.ambari.server.agent.CommandReport; import org.apache.ambari.server.serveraction.upgrades.ManualStageAction; import org.apache.ambari.server.state.Clusters; import org.apache.ambari.server.state.svccomphost.ServiceComponentHostServerActionEvent; import org.apache.ambari.server.utils.StageUtils; import org.easymock.IAnswer; import org.junit.After; import org.junit.BeforeClass; import org.junit.Ignore; import org.junit.Test; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import com.google.inject.AbstractModule; import com.google.inject.Guice; import com.google.inject.Inject; import com.google.inject.Injector; // TODO, fix this test later. @Ignore public class ServerActionExecutorTest { private static final int MAX_CYCLE_ITERATIONS = 1000; private static final String SERVER_HOST_NAME = StageUtils.getHostName(); private static final String CLUSTER_HOST_INFO = "{all_hosts=[" + SERVER_HOST_NAME + "], slave_hosts=[" + SERVER_HOST_NAME + "]}"; private static Injector injector; @Inject static StageFactory stageFactory; @BeforeClass public static void beforeClass() throws Exception { injector = Guice.createInjector(new MockModule()); } @After public void tearDown() throws AmbariException, SQLException { H2DatabaseCleaner.clearDatabaseAndStopPersistenceService(injector); } /** * Test a normal server action */ @Test public void testServerAction() throws Exception { final Request request = createMockRequest(); final Stage s = getStageWithServerAction(1, 977, null, "test", 300); final List<Stage> stages = new ArrayList<Stage>() { { add(s); } }; ActionDBAccessor db = createMockActionDBAccessor(request, stages); ServerActionExecutor.init(injector); ServerActionExecutor executor = new ServerActionExecutor(db, 10000); // Force the task to be QUEUED s.getHostRoleCommand(SERVER_HOST_NAME, Role.AMBARI_SERVER_ACTION.toString()).setStatus(HostRoleStatus.QUEUED); int cycleCount = 0; while (!getTaskStatus(s).isCompletedState() && (cycleCount++ <= MAX_CYCLE_ITERATIONS)) { executor.doWork(); } assertEquals(HostRoleStatus.COMPLETED, getTaskStatus(s)); } /** * Test a manual stage */ @Test public void testServerActionManualStage() throws Exception { final Request request = createMockRequest(); stageFactory = createNiceMock(StageFactory.class); final Stage stage = stageFactory.createNew(1, "/tmp", "cluster1", 978, "context", "{\"host_param\":\"param_value\"}", "{\"stage_param\":\"param_value\"}"); stage.addServerActionCommand(ManualStageAction.class.getName(), null, Role.AMBARI_SERVER_ACTION, RoleCommand.EXECUTE, "cluster1", new ServiceComponentHostServerActionEvent(StageUtils.getHostName(), System.currentTimeMillis()), Collections.<String, String> emptyMap(), null, null, 1200, false, false); final List<Stage> stages = new ArrayList<Stage>() { { add(stage); } }; ActionDBAccessor db = createMockActionDBAccessor(request, stages); ServerActionExecutor.init(injector); ServerActionExecutor executor = new ServerActionExecutor(db, 10000); // Force the task to be QUEUED stage.getHostRoleCommand(SERVER_HOST_NAME, Role.AMBARI_SERVER_ACTION.toString()).setStatus(HostRoleStatus.QUEUED); int cycleCount = 0; while (!getTaskStatus(stage).isHoldingState() && (cycleCount++ <= MAX_CYCLE_ITERATIONS)) { executor.doWork(); } assertEquals(HostRoleStatus.HOLDING, getTaskStatus(stage)); } /** * Test a timeout server action */ @Test public void testServerActionTimeout() throws Exception { final Request request = createMockRequest(); final Stage s = getStageWithServerAction(1, 977, new HashMap<String, String>() {{ put(MockServerAction.PAYLOAD_FORCE_FAIL, "timeout"); }}, "test", 1); final List<Stage> stages = new ArrayList<Stage>() { { add(s); } }; ActionDBAccessor db = createMockActionDBAccessor(request, stages); ServerActionExecutor.init(injector); ServerActionExecutor executor = new ServerActionExecutor(db, 10000); // Force the task to be QUEUED s.getHostRoleCommand(SERVER_HOST_NAME, Role.AMBARI_SERVER_ACTION.toString()).setStatus(HostRoleStatus.QUEUED); int cycleCount = 0; while (!getTaskStatus(s).isCompletedState() && (cycleCount++ <= MAX_CYCLE_ITERATIONS)) { executor.doWork(); } assertEquals(HostRoleStatus.TIMEDOUT, getTaskStatus(s)); } /** * Test a timeout server action */ @Test public void testServerActionFailedException() throws Exception { final Request request = createMockRequest(); final Stage s = getStageWithServerAction(1, 977, new HashMap<String, String>() {{ put(MockServerAction.PAYLOAD_FORCE_FAIL, "exception"); }}, "test", 1); final List<Stage> stages = new ArrayList<Stage>() { { add(s); } }; ActionDBAccessor db = createMockActionDBAccessor(request, stages); ServerActionExecutor.init(injector); ServerActionExecutor executor = new ServerActionExecutor(db, 10000); // Force the task to be QUEUED s.getHostRoleCommand(SERVER_HOST_NAME, Role.AMBARI_SERVER_ACTION.toString()).setStatus(HostRoleStatus.QUEUED); int cycleCount = 0; while (!getTaskStatus(s).isCompletedState() && (cycleCount++ <= MAX_CYCLE_ITERATIONS)) { executor.doWork(); } assertEquals(HostRoleStatus.FAILED, getTaskStatus(s)); } /** * Test a timeout server action */ @Test public void testServerActionFailedReport() throws Exception { final Request request = createMockRequest(); final Stage s = getStageWithServerAction(1, 977, new HashMap<String, String>() {{ put(MockServerAction.PAYLOAD_FORCE_FAIL, "report"); }}, "test", 1); final List<Stage> stages = new ArrayList<Stage>() { { add(s); } }; ActionDBAccessor db = createMockActionDBAccessor(request, stages); ServerActionExecutor.init(injector); ServerActionExecutor executor = new ServerActionExecutor(db, 10000); // Force the task to be QUEUED s.getHostRoleCommand(SERVER_HOST_NAME, Role.AMBARI_SERVER_ACTION.toString()).setStatus(HostRoleStatus.QUEUED); int cycleCount = 0; while (!getTaskStatus(s).isCompletedState() && (cycleCount++ <= MAX_CYCLE_ITERATIONS)) { executor.doWork(); } assertEquals(HostRoleStatus.FAILED, getTaskStatus(s)); } private HostRoleStatus getTaskStatus(Stage stage) { return stage.getHostRoleStatus(SERVER_HOST_NAME, "AMBARI_SERVER_ACTION"); } private Request createMockRequest() { Request request = mock(Request.class); when(request.isExclusive()).thenReturn(false); when(request.getRequestId()).thenReturn(1L); return request; } private ActionDBAccessor createMockActionDBAccessor(final Request request, final List<Stage> stages) { ActionDBAccessor db = mock(ActionDBAccessor.class); when(db.getFirstStageInProgressPerRequest()).thenReturn(stages); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { RequestStatus status = (RequestStatus) invocation.getArguments()[0]; if (status == RequestStatus.IN_PROGRESS) { return Arrays.asList(request); } else { return Collections.emptyList(); } } }).when(db).getRequestsByStatus(any(RequestStatus.class), anyInt(), anyBoolean()); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { String host = (String) invocation.getArguments()[0]; String role = (String) invocation.getArguments()[3]; CommandReport commandReport = (CommandReport) invocation.getArguments()[4]; HostRoleCommand command = stages.get(0).getHostRoleCommand(host, role); command.setStatus(HostRoleStatus.valueOf(commandReport.getStatus())); return null; } }).when(db).updateHostRoleState(anyString(), anyLong(), anyLong(), anyString(), any(CommandReport.class)); doAnswer(new Answer() { @Override public Object answer(InvocationOnMock invocation) throws Throwable { String host = (String) invocation.getArguments()[0]; String role = (String) invocation.getArguments()[1]; HostRoleStatus status = (HostRoleStatus) invocation.getArguments()[2]; HostRoleCommand task = stages.get(0).getHostRoleCommand(host, role); if (task.getStatus() == status) { return Arrays.asList(task); } else { return null; } } }).when(db).getTasksByHostRoleAndStatus(anyString(), anyString(), any(HostRoleStatus.class)); return db; } private static Stage getStageWithServerAction(final long requestId, final long stageId, final Map<String, String> payload, final String requestContext, final int timeout) { stageFactory = createNiceMock(StageFactory.class); expect(stageFactory.createNew(anyLong(), anyObject(String.class), anyObject(String.class), anyLong(), anyObject(String.class), anyObject(String.class), anyObject(String.class))). andAnswer(new IAnswer<Stage>() { @Override public Stage answer() throws Throwable { Stage stage = stageFactory.createNew(requestId, "/tmp", "cluster1", 1L, requestContext, "{}", "{}"); stage.setStageId(stageId); stage.addServerActionCommand(MockServerAction.class.getName(), null, Role.AMBARI_SERVER_ACTION, RoleCommand.EXECUTE, "cluster1", new ServiceComponentHostServerActionEvent(SERVER_HOST_NAME, System.currentTimeMillis()), payload, "command detail", null, timeout, false, false); // TODO, take a look at KerberosHelperTest.java as an example return stage; } }); Stage stage = stageFactory.createNew(requestId, "", "", 1L, "", "", ""); return stage; } public static class MockModule extends AbstractModule { @Override protected void configure() { bind(Clusters.class).toInstance(mock(Clusters.class)); } } }