/*
* Copyright 2016 ThoughtWorks, Inc.
*
* Licensed 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 com.thoughtworks.go.config.update;
import com.thoughtworks.go.config.*;
import com.thoughtworks.go.config.materials.git.GitMaterialConfig;
import com.thoughtworks.go.config.merge.MergeEnvironmentConfig;
import com.thoughtworks.go.config.remote.ConfigRepoConfig;
import com.thoughtworks.go.config.remote.ConfigRepoConfigTest;
import com.thoughtworks.go.config.remote.FileConfigOrigin;
import com.thoughtworks.go.config.remote.RepoConfigOrigin;
import com.thoughtworks.go.helper.GoConfigMother;
import com.thoughtworks.go.i18n.Localizable;
import com.thoughtworks.go.i18n.LocalizedMessage;
import com.thoughtworks.go.server.domain.Username;
import com.thoughtworks.go.server.service.GoConfigService;
import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult;
import com.thoughtworks.go.serverhealth.HealthStateType;
import org.junit.Before;
import org.junit.Test;
import org.mockito.Mock;
import java.util.ArrayList;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.*;
import static org.mockito.Mockito.when;
import static org.mockito.MockitoAnnotations.initMocks;
public class PatchEnvironmentCommandTest {
private Username currentUser;
private BasicCruiseConfig cruiseConfig;
private BasicEnvironmentConfig environmentConfig;
private CaseInsensitiveString environmentName;
private HttpLocalizedOperationResult result;
private Localizable.CurryableLocalizable actionFailed;
private ArrayList<String> pipelinesToAdd;
private ArrayList<String> pipelinesToRemove;
private ArrayList<String> agentsToAdd;
private ArrayList<String> agentsToRemove;
private ArrayList<EnvironmentVariableConfig> envVarsToAdd;
private ArrayList<String> envVarsToRemove;
private PipelineConfig pipelineConfig;
private AgentConfig agentConfig;
@Mock
private GoConfigService goConfigService;
@Before
public void setup() throws Exception {
initMocks(this);
pipelinesToAdd = new ArrayList<>();
pipelinesToRemove = new ArrayList<>();
agentsToAdd = new ArrayList<>();
agentsToRemove = new ArrayList<>();
envVarsToAdd = new ArrayList<>();
envVarsToRemove = new ArrayList<>();
result = new HttpLocalizedOperationResult();
currentUser = new Username(new CaseInsensitiveString("user"));
cruiseConfig = new GoConfigMother().defaultCruiseConfig();
environmentName = new CaseInsensitiveString("Dev");
environmentConfig = new BasicEnvironmentConfig(environmentName);
cruiseConfig.addEnvironment(environmentConfig);
pipelineConfig = new PipelineConfig();
String pipelineName = "pipeline-1";
pipelineConfig.setName(pipelineName);
cruiseConfig.addPipeline("First-Group", pipelineConfig);
agentConfig = new AgentConfig("uuid-1");
cruiseConfig.agents().add(agentConfig);
actionFailed = LocalizedMessage.string("ENV_UPDATE_FAILED", environmentConfig.name());
}
@Test
public void shouldAllowAddingAgentsToTheSpecifiedEnvironment() throws Exception {
agentsToAdd.add(agentConfig.getUuid());
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(agentConfig.getUuid()));
command.update(cruiseConfig);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).hasAgent(agentConfig.getUuid()));
}
@Test
public void shouldAllowRemovingAgentsFromTheSpecifiedEnvironment() throws Exception {
environmentConfig.addAgent(agentConfig.getUuid());
agentsToRemove.add(agentConfig.getUuid());
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).hasAgent(agentConfig.getUuid()));
command.update(cruiseConfig);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(agentConfig.getUuid()));
}
@Test
public void shouldAllowAddingPipelinesToTheSpecifiedEnvironment() throws Exception {
pipelinesToAdd.add(pipelineConfig.name().toString());
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).contains(pipelineConfig.name().toString()));
command.update(cruiseConfig);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).contains(pipelineConfig.name().toString()));
}
@Test
public void shouldAllowRemovingPipelinesFromTheSpecifiedEnvironment() throws Exception {
environmentConfig.addPipeline(pipelineConfig.name());
pipelinesToRemove.add(pipelineConfig.name().toString());
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).contains(pipelineConfig.name().toString()));
command.update(cruiseConfig);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).contains(pipelineConfig.name().toString()));
}
@Test
public void shouldAllowAddingEnvironmentVariablesToTheSpecifiedEnvironment() throws Exception {
String variableName = "foo";
envVarsToAdd.add(new EnvironmentVariableConfig(variableName, "bar"));
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
command.update(cruiseConfig);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
}
@Test
public void shouldAllowRemovingEnvironmentVariablesFromTheSpecifiedEnvironment() throws Exception {
String variableName = "foo";
environmentConfig.addEnvironmentVariable(variableName, "bar");
envVarsToRemove.add(variableName);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertTrue(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
command.update(cruiseConfig);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
}
@Test
public void shouldValidateInvalidAgentUUIDs() throws Exception {
String uuid = "invalid-agent-uuid";
agentsToAdd.add(uuid);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(uuid));
command.update(cruiseConfig);
assertFalse(command.isValid(cruiseConfig));
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
expectedResult.unprocessableEntity(actionFailed.addParam("Environment 'Dev' has an invalid agent uuid 'invalid-agent-uuid'"));
assertThat(result, is(expectedResult));
}
@Test
public void shouldValidateInvalidPipelineNames() throws Exception {
String pipelineName = "invalid-pipeline-name";
pipelinesToAdd.add(pipelineName);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(pipelineName));
command.update(cruiseConfig);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(pipelineName));
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
expectedResult.unprocessableEntity(actionFailed.addParam("Environment 'Dev' refers to an unknown pipeline 'invalid-pipeline-name'."));
assertThat(result, is(expectedResult));
}
@Test
public void shouldValidateInvalidPipelineRemoval() throws Exception {
String pipelineName = "invalid-pipeline-to-remove";
pipelinesToRemove.add(pipelineName);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).containsPipeline(new CaseInsensitiveString(pipelineName)));
command.update(cruiseConfig);
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
expectedResult.unprocessableEntity(actionFailed.addParam("Pipeline 'invalid-pipeline-to-remove' does not exist in environment 'Dev'"));
assertThat(result, is(expectedResult));
}
@Test
public void shouldValidateInvalidAgentRemoval() throws Exception {
String agentUUID = "invalid-agent-to-remove";
agentsToRemove.add(agentUUID);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).hasAgent(agentUUID));
command.update(cruiseConfig);
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
expectedResult.unprocessableEntity(actionFailed.addParam("Agent with uuid 'invalid-agent-to-remove' does not exist in environment 'Dev'"));
assertThat(result, is(expectedResult));
}
@Test
public void shouldValidateInvalidEnvironmentVariableRemoval() throws Exception {
String variableName = "invalid-env-var-to-remove";
envVarsToRemove.add(variableName);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
command.update(cruiseConfig);
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
expectedResult.unprocessableEntity(actionFailed.addParam("Environment variable with name 'invalid-env-var-to-remove' does not exist in environment 'Dev'"));
assertThat(result, is(expectedResult));
}
@Test
public void shouldNotAllowRemovingRemotePipeline() throws Exception {
CaseInsensitiveString pipelineName = new CaseInsensitiveString("remote-pipeline-to-remove");
BasicEnvironmentConfig local = new BasicEnvironmentConfig(environmentName);
local.setOrigins(new FileConfigOrigin());
BasicEnvironmentConfig remote = new BasicEnvironmentConfig(environmentName);
remote.addPipeline(pipelineName);
ConfigRepoConfig configRepo = new ConfigRepoConfig(new GitMaterialConfig("foo/bar.git", "master"), "myPlugin");
remote.setOrigins(new RepoConfigOrigin(configRepo, "latest"));
MergeEnvironmentConfig mergedConfig = new MergeEnvironmentConfig(local, remote);
pipelinesToRemove.add(pipelineName.toString());
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).containsPipeline(new CaseInsensitiveString(pipelineName.toString())));
command.update(cruiseConfig);
cruiseConfig.getEnvironments().replace(cruiseConfig.getEnvironments().find(environmentName), mergedConfig); //preprocess
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
String message = "Pipeline 'remote-pipeline-to-remove' cannot be removed from environment 'Dev' as the association has been defined remotely in [foo/bar.git at latest]";
expectedResult.unprocessableEntity(actionFailed.addParam(message));
assertThat(result, is(expectedResult));
}
@Test
public void shouldNotAllowRemovingRemoteAgents() throws Exception {
String agentUUID = "remote-agent-to-remove";
BasicEnvironmentConfig local = new BasicEnvironmentConfig(environmentName);
local.setOrigins(new FileConfigOrigin());
BasicEnvironmentConfig remote = new BasicEnvironmentConfig(environmentName);
remote.addAgent(agentUUID);
ConfigRepoConfig configRepo = new ConfigRepoConfig(new GitMaterialConfig("foo/bar.git", "master"), "myPlugin");
remote.setOrigins(new RepoConfigOrigin(configRepo, "latest"));
MergeEnvironmentConfig mergedConfig = new MergeEnvironmentConfig(local, remote);
agentsToRemove.add(agentUUID);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).containsPipeline(new CaseInsensitiveString(agentUUID)));
command.update(cruiseConfig);
cruiseConfig.getEnvironments().replace(cruiseConfig.getEnvironments().find(environmentName), mergedConfig); //preprocess
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
String message = "Agent with uuid 'remote-agent-to-remove' cannot be removed from environment 'Dev' as the association has been defined remotely in [foo/bar.git at latest]";
expectedResult.unprocessableEntity(actionFailed.addParam(message));
assertThat(result, is(expectedResult));
}
@Test
public void shouldNotAllowRemovingRemoteEnvironmentVariables() throws Exception {
String variableName = "remote-env-var-to-remove";
BasicEnvironmentConfig local = new BasicEnvironmentConfig(environmentName);
local.setOrigins(new FileConfigOrigin());
BasicEnvironmentConfig remote = new BasicEnvironmentConfig(environmentName);
remote.addEnvironmentVariable(variableName, "bar");
ConfigRepoConfig configRepo = new ConfigRepoConfig(new GitMaterialConfig("foo/bar.git", "master"), "myPlugin");
remote.setOrigins(new RepoConfigOrigin(configRepo, "latest"));
MergeEnvironmentConfig mergedConfig = new MergeEnvironmentConfig(local, remote);
envVarsToRemove.add(variableName);
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
assertFalse(cruiseConfig.getEnvironments().find(environmentName).getVariables().hasVariable(variableName));
command.update(cruiseConfig);
cruiseConfig.getEnvironments().replace(cruiseConfig.getEnvironments().find(environmentName), mergedConfig); //preprocess
boolean isValid = command.isValid(cruiseConfig);
assertFalse(isValid);
HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult();
String message = "Environment variable with name 'remote-env-var-to-remove' cannot be removed from environment 'Dev' as the association has been defined remotely in [foo/bar.git at latest]";
expectedResult.unprocessableEntity(actionFailed.addParam(message));
assertThat(result, is(expectedResult));
}
@Test
public void shouldNotContinueIfTheUserDontHavePermissionsToOperateOnEnvironments() throws Exception {
PatchEnvironmentCommand command = new PatchEnvironmentCommand(goConfigService, environmentConfig, pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToRemove, envVarsToAdd, envVarsToRemove, currentUser, actionFailed, result);
when(goConfigService.isAdministrator(currentUser.getUsername())).thenReturn(false);
assertThat(command.canContinue(cruiseConfig), is(false));
HttpLocalizedOperationResult expectResult = new HttpLocalizedOperationResult();
Localizable noPermission = LocalizedMessage.string("NO_PERMISSION_TO_UPDATE_ENVIRONMENT", environmentConfig.name().toString(), currentUser.getDisplayName());
expectResult.unauthorized(noPermission, HealthStateType.unauthorised());
assertThat(result, is(expectResult));
}
}