/**
* 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.users;
import java.io.IOException;
import java.util.Arrays;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentMap;
import org.apache.ambari.server.AmbariException;
import org.apache.ambari.server.Role;
import org.apache.ambari.server.RoleCommand;
import org.apache.ambari.server.actionmanager.HostRoleCommand;
import org.apache.ambari.server.agent.CommandReport;
import org.apache.ambari.server.agent.ExecutionCommand;
import org.apache.ambari.server.hooks.users.UserHookParams;
import org.apache.ambari.server.state.SecurityType;
import org.apache.ambari.server.utils.ShellCommandUtil;
import org.codehaus.jackson.map.ObjectMapper;
import org.easymock.Capture;
import org.easymock.EasyMock;
import org.easymock.EasyMockRule;
import org.easymock.EasyMockSupport;
import org.easymock.Mock;
import org.easymock.TestSubject;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Rule;
import org.junit.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import com.google.common.collect.Maps;
/**
* Test suite for the PostUserCreationHookServer action class.
*/
public class PostUserCreationHookServerActionTest extends EasyMockSupport {
private static final Logger LOGGER = LoggerFactory.getLogger(PostUserCreationHookServerActionTest.class);
@Rule
public EasyMockRule mocks = new EasyMockRule(this);
@Mock
private ShellCommandUtilityWrapper shellCommandUtilityWrapper;
@Mock
private ExecutionCommand executionCommand;
@Mock
private HostRoleCommand hostRoleCommand;
@Mock
private ObjectMapper objectMapperMock;
@Mock
private CollectionPersisterServiceFactory collectionPersisterServiceFactoryMock;
@Mock
private CsvFilePersisterService collectionPersisterService;
@TestSubject
private PostUserCreationHookServerAction customScriptServerAction = new PostUserCreationHookServerAction();
private ConcurrentMap<String, Object> requestSharedDataContext = Maps.newConcurrentMap();
private Capture<String[]> commandCapture = null;
private Map<String, List<String>> payload = new HashMap<>();
private ObjectMapper om = new ObjectMapper();
@Before
public void before() throws IOException, InterruptedException {
payload.clear();
resetAll();
EasyMock.expect(hostRoleCommand.getRequestId()).andReturn(-1l).times(2);
EasyMock.expect(hostRoleCommand.getStageId()).andReturn(-1l).times(2);
}
@Test
public void shouldCommandStringBeAssembledCorrectlyForSingleUser() throws Exception {
// GIVEN
payload = mockPayload(1);
mockExecutionCommand(payload.size());
String payloadJson = om.writeValueAsString(payload);
// command params as passed to the serveraction implementation
Map<String, String> commandParams = new HashMap<>();
commandParams.put(UserHookParams.PAYLOAD.param(), payloadJson);
commandParams.put(UserHookParams.SCRIPT.param(), "/hookfolder/hook.name");
commandParams.put(UserHookParams.CMD_TIME_FRAME.param(), "1000");
commandParams.put(UserHookParams.CMD_INPUT_FILE.param(), "/test/user_data.csv");
commandParams.put(UserHookParams.CLUSTER_SECURITY_TYPE.param(), SecurityType.KERBEROS.name());
commandParams.put(UserHookParams.CMD_HDFS_USER.param(), "test-hdfs-user");
EasyMock.expect(executionCommand.getCommandParams()).andReturn(commandParams);
EasyMock.expect(objectMapperMock.readValue(payloadJson, Map.class)).andReturn(payload);
// captures the command arguments passed to the shell callable through the factory
commandCapture = EasyMock.newCapture();
// the callable mock returns a dummy result, no assertions made on the result
EasyMock.expect(shellCommandUtilityWrapper.runCommand(EasyMock.capture(commandCapture))).andReturn(new ShellCommandUtil.Result(0, null, null)).times(payload.size());
customScriptServerAction.setExecutionCommand(executionCommand);
EasyMock.expect(collectionPersisterServiceFactoryMock.createCsvFilePersisterService(EasyMock.anyString())).andReturn(collectionPersisterService);
EasyMock.expect(collectionPersisterService.persistMap(EasyMock.<Map<String, List<String>>>anyObject())).andReturn(Boolean.TRUE);
replayAll();
// WHEN
CommandReport commandReport = customScriptServerAction.execute(requestSharedDataContext);
// THEN
String[] commandArray = commandCapture.getValue();
Assert.assertNotNull("The command to be executed must not be null!", commandArray);
Assert.assertEquals("The command argument array length is not as expected!", 6, commandArray.length);
Assert.assertEquals("The command script is not as expected", "/hookfolder/hook.name", commandArray[0]);
}
@Test(expected = AmbariException.class)
public void shouldServerActionFailWhenCommandParametersAreMissing() throws Exception {
//GIVEN
Map<String, String> commandParams = new HashMap<>();
// the execution command lacks the required command parameters (commandparams is an empty list)
EasyMock.expect(executionCommand.getCommandParams()).andReturn(commandParams).times(2);
customScriptServerAction.setExecutionCommand(executionCommand);
replayAll();
// WHEN
CommandReport commandReport = customScriptServerAction.execute(requestSharedDataContext);
//THEN
//exception is thrown
}
private void mockExecutionCommand(int callCnt) {
EasyMock.expect(executionCommand.getRoleCommand()).andReturn(RoleCommand.EXECUTE).times(callCnt);
EasyMock.expect(executionCommand.getClusterName()).andReturn("unit-test-cluster").times(callCnt);
EasyMock.expect(executionCommand.getConfigurationTags()).andReturn(Collections.<String, Map<String, String>>emptyMap()).times(callCnt);
EasyMock.expect(executionCommand.getRole()).andReturn(Role.AMBARI_SERVER_ACTION.toString()).times(callCnt);
EasyMock.expect(executionCommand.getServiceName()).andReturn("custom-hook-script").times(callCnt);
EasyMock.expect(executionCommand.getTaskId()).andReturn(-1l).times(callCnt);
}
private Map<String, List<String>> mockPayload(int size) {
Map<String, List<String>> ret = new HashMap<>();
for (int i = 0; i < size; i++) {
ret.put("user-" + i, Arrays.asList("hdfs" + i, "yarn" + i));
}
return ret;
}
}