/* * 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.GoConfigInvalidException; import com.thoughtworks.go.config.update.CreateTemplateConfigCommand; import com.thoughtworks.go.helper.GoConfigMother; import com.thoughtworks.go.helper.PipelineTemplateConfigMother; import com.thoughtworks.go.helper.StageConfigMother; import com.thoughtworks.go.i18n.LocalizedMessage; import com.thoughtworks.go.i18n.Localizer; import com.thoughtworks.go.presentation.ConfigForEdit; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.service.tasks.PluggableTaskService; import com.thoughtworks.go.server.ui.TemplatesViewModel; import org.junit.Before; import org.junit.Test; import java.util.*; import static com.thoughtworks.go.helper.PipelineConfigMother.pipelineConfig; import static com.thoughtworks.go.server.service.TemplateConfigService.*; import static org.hamcrest.core.Is.is; import static org.hamcrest.core.IsNot.not; import static org.hamcrest.core.IsNull.nullValue; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*; public class TemplateConfigServiceTest { public GoConfigService goConfigService; private SecurityService securityService; private TemplateConfigService service; private EntityHashingService entityHashingService; private PluggableTaskService pluggableTaskService; @Before public void setup() { goConfigService = mock(GoConfigService.class); securityService = mock(SecurityService.class); entityHashingService = mock(EntityHashingService.class); pluggableTaskService = mock(PluggableTaskService.class); service = new TemplateConfigService(goConfigService, securityService, entityHashingService, pluggableTaskService); } @Test public void shouldReturnAMapOfTemplateNamesToListOfAssociatedPipelines() { Username user = new Username(new CaseInsensitiveString("user")); when(securityService.isUserAdmin(user)).thenReturn(true); PipelineTemplateConfig template = template("first_template"); PipelineTemplateConfig emptyTemplate = template("empty_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs(createPipelineWithTemplate("first", template), createPipelineWithTemplate("second", template))); cruiseConfig.addTemplate(template); cruiseConfig.addTemplate(emptyTemplate); when(goConfigService.getCurrentConfig()).thenReturn(cruiseConfig); Map<CaseInsensitiveString, List<CaseInsensitiveString>> templateWithPipelines = service.templatesWithPipelinesForUser("user"); assertThat(templateWithPipelines.size(), is(2)); assertThat(templateWithPipelines.get(new CaseInsensitiveString("first_template")), is(Arrays.asList(new CaseInsensitiveString("first"), new CaseInsensitiveString("second")))); assertThat(templateWithPipelines.get(new CaseInsensitiveString("empty_template")), is(new ArrayList<CaseInsensitiveString>())); } @Test public void shouldDeleteATemplateWithAGivenName() { PipelineTemplateConfig emptyTemplate = template("empty_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(); cruiseConfig.addTemplate(emptyTemplate); service.removeTemplate("empty_template", cruiseConfig, "md5", new HttpLocalizedOperationResult()); verify(goConfigService).updateConfig(new DeleteTemplateCommand("empty_template", "md5")); } @Test public void shouldReturn404WhenTheTemplateToBeDeletedIsNotFound() { PipelineTemplateConfig emptyTemplate = template("empty_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(); cruiseConfig.addTemplate(emptyTemplate); TemplateConfigService service = new TemplateConfigService(goConfigService, securityService, entityHashingService, pluggableTaskService); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); service.removeTemplate("not_found_template", cruiseConfig, "md5", result); assertThat(result.isSuccessful(), is(false)); assertThat(result.httpCode(), is(404)); } @Test public void shouldLoadClonedTemplateForEdit() { String templateName = "empty_template"; CaseInsensitiveString templateAdminUser = new CaseInsensitiveString("templateAdminUser"); Username templateUser = new Username(templateAdminUser); PipelineTemplateConfig emptyTemplate = PipelineTemplateConfigMother.createTemplate(templateName, new Authorization(new AdminsConfig(new AdminUser(templateAdminUser))), StageConfigMother.stageConfig("some_stage")); CruiseConfig cruiseConfig = new BasicCruiseConfig(); cruiseConfig.addTemplate(emptyTemplate); when(securityService.isAuthorizedToEditTemplate(templateName, templateUser)).thenReturn(true); when(goConfigService.getConfigHolder()).thenReturn(new GoConfigHolder(cruiseConfig, cruiseConfig)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); ConfigForEdit<PipelineTemplateConfig> configForEdit = service.loadForEdit(templateName, templateUser, result); assertThat(configForEdit, is(not(nullValue()))); CaseInsensitiveString empty_template = new CaseInsensitiveString(templateName); assertThat(configForEdit.getConfig().name(), is(empty_template)); PipelineTemplateConfig template = configForEdit.getConfig(); PipelineTemplateConfig templateForEdit = configForEdit.getCruiseConfig().findTemplate(empty_template); PipelineTemplateConfig processedTemplate = configForEdit.getProcessedConfig().findTemplate(empty_template); PipelineTemplateConfig serversTemplate = cruiseConfig.findTemplate(empty_template); serversTemplate.add(new StageConfig(new CaseInsensitiveString("stage-one"), new JobConfigs(new JobConfig("job"))));//modify the server's copy assertThat(serversTemplate.size(), is(2)); assertThat(template.size(), is(1));//given copy should remain unmodified assertThat(templateForEdit.size(), is(1)); assertThat(processedTemplate.size(), is(1)); } @Test public void shouldErrorOutIfTemplateIsNotFound() { PipelineTemplateConfig emptyTemplate = template("empty_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(); cruiseConfig.addTemplate(emptyTemplate); when(securityService.isAuthorizedToEditTemplate(anyString(), any(Username.class))).thenReturn(true); when(goConfigService.getConfigHolder()).thenReturn(new GoConfigHolder(cruiseConfig, cruiseConfig)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); ConfigForEdit<PipelineTemplateConfig> configForEdit = service.loadForEdit("blah", new Username(new CaseInsensitiveString("someuser")), result); assertThat(configForEdit, is(nullValue())); assertThat(result.isSuccessful(), is(false)); assertThat(result.httpCode(), is(404)); } @Test public void shouldErrorOutIfUserIsNotAllowedToAdministerTheGivenTemplate() { Username username = new Username(new CaseInsensitiveString("user")); String templateName = "templateName"; PipelineTemplateConfig emptyTemplate = PipelineTemplateConfigMother.createTemplate(templateName); CruiseConfig cruiseConfig = new BasicCruiseConfig(); cruiseConfig.addTemplate(emptyTemplate); when(securityService.isAuthorizedToEditTemplate(templateName, username)).thenReturn(false); when(goConfigService.getConfigHolder()).thenReturn(new GoConfigHolder(cruiseConfig, cruiseConfig)); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); ConfigForEdit<PipelineTemplateConfig> configForEdit = service.loadForEdit(templateName, username, result); assertThat(configForEdit, is(nullValue())); assertThat(result.isSuccessful(), is(false)); assertThat(result.httpCode(), is(401)); Localizer localizer = mock(Localizer.class); when(localizer.localize("UNAUTHORIZED_TO_EDIT_TEMPLATE", templateName)).thenReturn("No template for you"); assertThat(result.message(localizer), is("No template for you")); } @Test public void shouldReturnAListOfAllPipelineConfigsThatAreNotUsedInTemplates() { Username user = new Username(new CaseInsensitiveString("user")); when(securityService.isUserAdmin(user)).thenReturn(true); PipelineTemplateConfig template = template("first_template"); PipelineTemplateConfig another = template("another_template"); PipelineConfig pipelineWithoutTemplateOne = pipelineConfig("first_without_template"); PipelineConfig pipelineWithoutTemplateTwo = pipelineConfig("another_without_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs(createPipelineWithTemplate("first", template), createPipelineWithTemplate("second", template), pipelineWithoutTemplateOne, pipelineWithoutTemplateTwo, createPipelineWithTemplate("fifth", another))); cruiseConfig.addTemplate(template); cruiseConfig.addTemplate(another); when(goConfigService.getAllPipelineConfigsForEdit()).thenReturn(cruiseConfig.allPipelines()); List<PipelineConfig> pipelineConfigs = service.allPipelinesNotUsingTemplates(user, new HttpLocalizedOperationResult()); assertThat(pipelineConfigs, is(Arrays.asList(pipelineWithoutTemplateOne, pipelineWithoutTemplateTwo))); } @Test public void shouldReturnUnauthorizedIfTheUserIsNotAdmin() { Username user = new Username(new CaseInsensitiveString("user")); when(securityService.isUserAdmin(user)).thenReturn(false); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); List<PipelineConfig> pipelineConfigs = service.allPipelinesNotUsingTemplates(user, result); assertThat(result.isSuccessful(), is(false)); Localizer localizer = mock(Localizer.class); when(localizer.localize("UNAUTHORIZED_TO_ADMINISTER", new Object[0])).thenReturn("foo"); assertThat(result.message(localizer), is("foo")); assertThat(pipelineConfigs, is(nullValue())); } @Test public void shouldLoadTemplateForViewing(){ PipelineTemplateConfig template = template("first_template"); CruiseConfig cruiseConfig = new BasicCruiseConfig(new BasicPipelineConfigs(createPipelineWithTemplate("first", template), createPipelineWithTemplate("second", template))); cruiseConfig.addTemplate(template); when(goConfigService.getConfigHolder()).thenReturn(new GoConfigHolder(cruiseConfig, cruiseConfig)); PipelineTemplateConfig actual = service.loadForView(template.name().toString(), new HttpLocalizedOperationResult()); assertThat(template, is(actual)); } @Test public void shouldPopulateErrorInResultOnFailure() throws Exception { HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); Username user = new Username(new CaseInsensitiveString("user")); String templateName = "template-name"; PipelineTemplateConfig pipelineTemplateConfig = new PipelineTemplateConfig(new CaseInsensitiveString(templateName), StageConfigMother.oneBuildPlanWithResourcesAndMaterials("stage", "job")); String errorMessage = "invalid template"; doThrow(new GoConfigInvalidException(new GoConfigMother().defaultCruiseConfig(), errorMessage)).when(goConfigService).updateConfig(any(CreateTemplateConfigCommand.class), any(Username.class)); service.createTemplateConfig(user, pipelineTemplateConfig, result); HttpLocalizedOperationResult expectedResult = new HttpLocalizedOperationResult(); expectedResult.unprocessableEntity(LocalizedMessage.string("ENTITY_CONFIG_VALIDATION_FAILED", "template", templateName, errorMessage)); assertThat(result.toString(), is(expectedResult.toString())); } @Test public void shouldReturnAMapOfAllTemplatesWithAuthorizationsForAnyUser() { BasicCruiseConfig cruiseConfig = GoConfigMother.defaultCruiseConfig(); ServerConfig serverConfig = new ServerConfig(new SecurityConfig(null, null, false, new AdminsConfig(new AdminUser(new CaseInsensitiveString("admin")))), null); cruiseConfig.setServerConfig(serverConfig); GoConfigMother.enableSecurityWithPasswordFile(cruiseConfig); CaseInsensitiveString templateViewUser = new CaseInsensitiveString("template-view"); CaseInsensitiveString templateAdmin = new CaseInsensitiveString("template-admin"); PipelineTemplateConfig template1 = PipelineTemplateConfigMother.createTemplate("t1", new Authorization(new ViewConfig(new AdminUser(templateViewUser))), StageConfigMother.manualStage("foo")); PipelineTemplateConfig template2 = PipelineTemplateConfigMother.createTemplate("t2"); PipelineTemplateConfig template3 = PipelineTemplateConfigMother.createTemplate("t3", new Authorization(new AdminsConfig(new AdminUser(templateAdmin))), StageConfigMother.manualStage("foobar")); cruiseConfig.addTemplate(template1); cruiseConfig.addTemplate(template2); cruiseConfig.addTemplate(template3); when(goConfigService.cruiseConfig()).thenReturn(cruiseConfig); List<TemplatesViewModel> templatesForSuperAdmins = new ArrayList<>(); templatesForSuperAdmins.add(new TemplatesViewModel(template1, true, true)); templatesForSuperAdmins.add(new TemplatesViewModel(template2, true, true)); templatesForSuperAdmins.add(new TemplatesViewModel(template3, true, true)); List<TemplatesViewModel> templatesForTemplateAdmin = new ArrayList<>(); templatesForTemplateAdmin.add(new TemplatesViewModel(template1, false, false)); templatesForTemplateAdmin.add(new TemplatesViewModel(template2, false, false)); templatesForTemplateAdmin.add(new TemplatesViewModel(template3, true, true)); List<TemplatesViewModel> templatesForTemplateViewUser = new ArrayList<>(); templatesForTemplateViewUser.add(new TemplatesViewModel(template1, true, false)); templatesForTemplateViewUser.add(new TemplatesViewModel(template2, false, false)); templatesForTemplateViewUser.add(new TemplatesViewModel(template3, false, false)); assertThat(service.getTemplateViewModels(new CaseInsensitiveString("admin")), is(templatesForSuperAdmins)); assertThat(service.getTemplateViewModels(templateAdmin), is(templatesForTemplateAdmin)); assertThat(service.getTemplateViewModels(templateViewUser), is(templatesForTemplateViewUser)); } private PipelineConfig createPipelineWithTemplate(String pipelineName, PipelineTemplateConfig template) { PipelineConfig pipelineConfig = pipelineConfig(pipelineName); pipelineConfig.clear(); pipelineConfig.setTemplateName(template.name()); pipelineConfig.usingTemplate(template); return pipelineConfig; } private PipelineTemplateConfig template(final String name) { return new PipelineTemplateConfig(new CaseInsensitiveString(name), StageConfigMother.stageConfig("some_stage")); } }