/* * Copyright 2017 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.server.service; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.exceptions.NoSuchEnvironmentException; import com.thoughtworks.go.domain.ConfigElementForEdit; import com.thoughtworks.go.helper.PipelineConfigMother; import com.thoughtworks.go.i18n.Localizer; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.util.GoConfigFileHelper; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.test.context.ContextConfiguration; import org.springframework.test.context.junit4.SpringJUnit4ClassRunner; import javax.servlet.http.HttpServletResponse; import java.io.IOException; import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Map; import static com.thoughtworks.go.server.service.EnvironmentConfigServiceTest.env; import static org.hamcrest.Matchers.nullValue; import static org.hamcrest.Matchers.sameInstance; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.StringContains.containsString; import static org.junit.Assert.*; @RunWith(SpringJUnit4ClassRunner.class) @ContextConfiguration(locations = { "classpath:WEB-INF/applicationContext-global.xml", "classpath:WEB-INF/applicationContext-dataLocalAccess.xml", "classpath:WEB-INF/applicationContext-acegi-security.xml" }) public class EnvironmentConfigServiceIntegrationTest { @Autowired private SecurityService securityService; @Autowired private GoConfigDao goConfigDao; @Autowired private GoConfigService goConfigService; @Autowired private EntityHashingService entityHashingService; @Autowired private AgentConfigService agentConfigService; @Autowired private EnvironmentConfigService service; @Autowired private Localizer localizer; @Autowired private AgentService agentService; private GoConfigFileHelper configHelper = new GoConfigFileHelper(); @Before public void setup() throws Exception { configHelper.usingCruiseConfigDao(goConfigDao).initializeConfigFile(); configHelper.onSetUp(); goConfigService.forceNotifyListeners(); } @After public void tearDown() throws Exception { configHelper.onTearDown(); } @Test public void shouldReturnTheCorrectLocalizedMessageForNoPermission() throws IOException { configHelper.turnOnSecurity(); configHelper.addAdmins("super_hero"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.createEnvironment(env("foo-env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("evil_hacker")), result); assertThat(result.message(localizer), is("Failed to add environment. User 'evil_hacker' does not have permission to add environments")); } @Test public void shouldReturnTheCorrectLocalizedMessageForDuplicateEnvironment() { configHelper.addEnvironments("foo-env"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.createEnvironment(env("foo-env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), result); assertThat(result.message(localizer), is("Failed to add environment. The environment 'foo-env' already exists.")); } @Test public void shouldReturnTheCorrectLocalizedMessageForDuplicatePipelinesInAnEnvironment() { BasicEnvironmentConfig environmentConfig = environmentConfig("uat"); goConfigService.addPipeline(PipelineConfigMother.createPipelineConfig("foo", "dev", "job"), "foo-grp"); environmentConfig.addPipeline(new CaseInsensitiveString("foo")); goConfigService.addEnvironment(environmentConfig); ArrayList<String> pipelines = new ArrayList<>(); pipelines.add("foo"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.createEnvironment(env("foo-env", pipelines, new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), result); result = new HttpLocalizedOperationResult(); service.createEnvironment(env("env", pipelines, new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), result); assertThat(result.message(localizer), is("Failed to add environment. Associating pipeline(s) which is already part of uat environment")); } @Test public void shouldReturnBadRequestForInvalidEnvName() { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.createEnvironment(env("foo env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), result); assertThat(result.httpCode(), is(HttpServletResponse.SC_BAD_REQUEST)); assertThat(result.message(localizer), containsString("Failed to add environment.")); } @Test public void shouldUpdateExistingEnvironment_ForNewUpdateEnvironmentMethod() throws Exception { BasicEnvironmentConfig uat = environmentConfig("uat"); goConfigService.addPipeline(PipelineConfigMother.createPipelineConfig("foo", "dev", "job"), "foo-grp"); goConfigService.addPipeline(PipelineConfigMother.createPipelineConfig("bar", "dev", "job"), "foo-grp"); Username user = Username.ANONYMOUS; agentConfigService.addAgent(new AgentConfig("uuid-1", "host-1", "192.168.1.2"), user); agentConfigService.addAgent(new AgentConfig("uuid-2", "host-2", "192.168.1.3"), user); uat.addPipeline(new CaseInsensitiveString("foo")); uat.addAgent("uuid-2"); uat.addEnvironmentVariable("env-one", "ONE"); uat.addEnvironmentVariable("env-two", "TWO"); goConfigService.addEnvironment(new BasicEnvironmentConfig(new CaseInsensitiveString("dev"))); goConfigService.addEnvironment(new BasicEnvironmentConfig(new CaseInsensitiveString("qa"))); goConfigService.addEnvironment(uat); goConfigService.addEnvironment(new BasicEnvironmentConfig(new CaseInsensitiveString("acceptance"))); goConfigService.addEnvironment(new BasicEnvironmentConfig(new CaseInsensitiveString("function_testing"))); EnvironmentConfig newUat = new BasicEnvironmentConfig(new CaseInsensitiveString("prod")); newUat.addPipeline(new CaseInsensitiveString("bar")); newUat.addAgent("uuid-1"); newUat.addEnvironmentVariable("env-three", "THREE"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); String md5 = entityHashingService.md5ForEntity(uat); service.updateEnvironment(uat.name().toString(), newUat, new Username(new CaseInsensitiveString("foo")), md5, result); EnvironmentConfig updatedEnv = service.named("prod"); assertThat(updatedEnv.name(), is(new CaseInsensitiveString("prod"))); assertThat(updatedEnv.getAgents().getUuids(), is(Arrays.asList("uuid-1"))); assertThat(updatedEnv.getPipelineNames(), is(Arrays.asList(new CaseInsensitiveString("bar")))); EnvironmentVariablesConfig updatedVariables = new EnvironmentVariablesConfig(); updatedVariables.add("env-three", "THREE"); assertThat(updatedEnv.getVariables(), is(updatedVariables)); EnvironmentsConfig currentEnvironments = goConfigService.getCurrentConfig().getEnvironments(); assertThat(currentEnvironments.indexOf(updatedEnv), is(2)); assertThat(currentEnvironments.size(), is(5)); } @Test public void shouldReturnTheCorrectLocalizedMessageWhenUserDoesNotHavePermissionToUpdate_ForNewUpdateEnvironmentMethod() throws Exception { configHelper.addEnvironments("foo"); configHelper.turnOnSecurity(); configHelper.addAdmins("super_hero"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); String md5 = entityHashingService.md5ForEntity(service.getEnvironmentConfig("foo")); service.updateEnvironment("foo", env("foo-env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("evil_hacker")), md5, result); assertThat(result.message(localizer), is("Failed to update environment 'foo'. User 'evil_hacker' does not have permission to update environments")); } @Test public void shouldReturnTheCorrectLocalizedMessageForUpdateWhenDuplicateEnvironmentExists_ForNewUpdateEnvironmentMethod() throws NoSuchEnvironmentException { configHelper.addEnvironments("foo-env"); configHelper.addEnvironments("bar-env"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); String md5 = entityHashingService.md5ForEntity(service.getEnvironmentConfig("bar-env")); service.updateEnvironment("bar-env", env("foo-env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), md5, result); assertThat(result.message(localizer), is("Failed to update environment 'bar-env'. failed to save : Duplicate unique value [foo-env] declared for identity constraint \"uniqueEnvironmentName\" of element \"environments\".")); } @Test public void shouldReturnTheCorrectLocalizedMessageForUpdateWhenStaleEtagIsProvided() throws NoSuchEnvironmentException { configHelper.addEnvironments("foo-env"); configHelper.addEnvironments("bar-env"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); String md5 = "invalid-md5"; service.updateEnvironment("bar-env", env("foo-env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), md5, result); assertThat(result.message(localizer), is("Someone has modified the configuration for Environment 'bar-env'. Please update your copy of the config with the changes.")); } @Test public void shouldReturnBadRequestForUpdateWhenUsingInvalidEnvName_ForNewUpdateEnvironmentMethod_ForNewUpdateEnvironmentMethod() throws NoSuchEnvironmentException { configHelper.addEnvironments("foo-env"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); String md5 = entityHashingService.md5ForEntity(service.getEnvironmentConfig("foo-env")); service.updateEnvironment("foo-env", env("foo env", new ArrayList<String>(), new ArrayList<Map<String, String>>(), new ArrayList<String>()), new Username(new CaseInsensitiveString("any")), md5, result); assertThat(result.httpCode(), is(HttpServletResponse.SC_BAD_REQUEST)); assertThat(result.message(localizer), containsString("Failed to update environment 'foo-env'.")); } @Test public void shouldDeleteAnEnvironment() throws Exception { String environmentName = "dev"; HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); goConfigService.addEnvironment(new BasicEnvironmentConfig(new CaseInsensitiveString(environmentName))); assertTrue(goConfigService.hasEnvironmentNamed(new CaseInsensitiveString(environmentName))); service.deleteEnvironment(service.getEnvironmentConfig(environmentName), new Username(new CaseInsensitiveString("foo")), result); assertFalse(goConfigService.hasEnvironmentNamed(new CaseInsensitiveString(environmentName))); assertThat(result.message(localizer), containsString("The environment 'dev' was deleted successfully.")); } @Test public void shouldReturnTheCorrectLocalizedMessageWhenUserDoesNotHavePermissionToDelete() throws IOException, NoSuchEnvironmentException { configHelper.addEnvironments("foo"); configHelper.turnOnSecurity(); configHelper.addAdmins("super_hero"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.deleteEnvironment(service.getEnvironmentConfig("foo"), new Username(new CaseInsensitiveString("evil_hacker")), result); assertThat(result.message(localizer), is("Failed to delete environment 'foo'. User 'evil_hacker' does not have permission to update environments")); } @Test public void shouldPatchAnEnvironment() throws Exception { String environmentName = "env"; BasicEnvironmentConfig env = environmentConfig(environmentName); Username user = Username.ANONYMOUS; String uuid = "uuid-1"; agentConfigService.addAgent(new AgentConfig(uuid, "host-1", "192.168.1.2"), user); goConfigService.addEnvironment(env); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<String> agentsToremove = new ArrayList<>(); List<String> agentsToAdd = new ArrayList<>(); agentsToAdd.add(uuid); List<String> pipelinesToAdd = new ArrayList<>(); List<String> pipelinesToRemove = new ArrayList<>(); List<EnvironmentVariableConfig> envVarsToAdd = new ArrayList<>(); List<String> envVarsToRemove = new ArrayList<>(); service.patchEnvironment(service.getEnvironmentConfig(environmentName), pipelinesToAdd, pipelinesToRemove, agentsToAdd, agentsToremove, envVarsToAdd, envVarsToRemove, user, result); EnvironmentConfig updatedEnv = service.named(env.name().toString()); assertThat(updatedEnv.name(), is(new CaseInsensitiveString(environmentName))); assertThat(updatedEnv.getAgents().getUuids(), is(Arrays.asList("uuid-1"))); assertThat(result.message(localizer), containsString("Updated environment 'env'.")); } @Test public void shouldReturnTheCorrectLocalizedMessageWhenUserDoesNotHavePermissionToPatch() throws IOException, NoSuchEnvironmentException { configHelper.addEnvironments("foo"); configHelper.turnOnSecurity(); configHelper.addAdmins("super_hero"); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.patchEnvironment(service.getEnvironmentConfig("foo"), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new ArrayList<>(), new Username(new CaseInsensitiveString("evil_hacker")), result); assertThat(result.message(localizer), is("Failed to update environment 'foo'. User 'evil_hacker' does not have permission to update environments")); } @Test public void shouldReturnAClonedInstanceOfEnvironmentConfig() throws NoSuchEnvironmentException { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); configHelper.addEnvironments("foo-env"); assertThat(service.named("foo-env"), sameInstance(service.named("foo-env"))); assertThat(service.named("foo-env"), not(sameInstance(service.getMergedEnvironmentforDisplay("foo-env", result).getConfigElement()))); assertThat(result.isSuccessful(), is(true)); } @Test public void shouldPopulateResultWithErrorIfEnvNotFound() throws NoSuchEnvironmentException { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); ConfigElementForEdit<EnvironmentConfig> edit = service.getMergedEnvironmentforDisplay("foo-env", result); assertThat(result.message(localizer), is("Environment 'foo-env' not found.")); assertThat(edit, is(nullValue())); } private BasicEnvironmentConfig environmentConfig(String name) { return new BasicEnvironmentConfig(new CaseInsensitiveString(name)); } }