/* * 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.materials; import com.thoughtworks.go.config.*; import com.thoughtworks.go.config.update.ConfigUpdateAjaxResponse; import com.thoughtworks.go.config.update.ConfigUpdateResponse; import com.thoughtworks.go.config.update.UpdateConfigFromUI; import com.thoughtworks.go.domain.config.PluginConfiguration; import com.thoughtworks.go.domain.packagerepository.ConfigurationPropertyMother; import com.thoughtworks.go.domain.packagerepository.PackageRepository; import com.thoughtworks.go.helper.GoConfigMother; import com.thoughtworks.go.i18n.LocalizedMessage; import com.thoughtworks.go.i18n.Localizer; import com.thoughtworks.go.plugin.access.packagematerial.PackageRepositoryExtension; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfiguration; import com.thoughtworks.go.plugin.access.packagematerial.PackageConfigurations; import com.thoughtworks.go.plugin.access.packagematerial.RepositoryMetadataStore; import com.thoughtworks.go.plugin.api.material.packagerepository.RepositoryConfiguration; import com.thoughtworks.go.plugin.api.response.Result; import com.thoughtworks.go.plugin.api.response.validation.ValidationError; import com.thoughtworks.go.plugin.api.response.validation.ValidationResult; import com.thoughtworks.go.plugin.infra.PluginManager; import com.thoughtworks.go.plugin.infra.plugininfo.GoPluginDescriptor; import com.thoughtworks.go.server.domain.Username; import com.thoughtworks.go.server.service.EntityHashingService; import com.thoughtworks.go.server.service.GoConfigService; import com.thoughtworks.go.server.service.SecurityService; import com.thoughtworks.go.server.service.result.HttpLocalizedOperationResult; import com.thoughtworks.go.server.service.result.LocalizedOperationResult; import org.apache.http.HttpStatus; import org.junit.Before; import org.junit.Test; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.invocation.InvocationOnMock; import org.mockito.stubbing.Answer; import java.util.Arrays; import static java.util.Arrays.asList; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.mockito.Mockito.*; import static org.mockito.MockitoAnnotations.initMocks; public class PackageRepositoryServiceTest { @Mock private PluginManager pluginManager; @Mock private PackageRepositoryExtension packageRepositoryExtension; @Mock private GoConfigService goConfigService; @Mock private SecurityService securityService; @Mock private Localizer localizer; @Mock private EntityHashingService entityHashingService; private PackageRepositoryService service; @Before public void setUp() throws Exception { initMocks(this); service = new PackageRepositoryService(pluginManager, packageRepositoryExtension, goConfigService, securityService, entityHashingService, localizer); } @Test public void shouldSavePackageRepositoryAndReturnSuccess() throws Exception { service = spy(service); PackageRepository packageRepository = new PackageRepository(); packageRepository.setId("repoid"); Username username = new Username(new CaseInsensitiveString("user")); UpdateConfigFromUI updateConfigFromUI = mock(UpdateConfigFromUI.class); doNothing().when(service).performPluginValidationsFor(packageRepository); doReturn(updateConfigFromUI).when(service).getPackageRepositoryUpdateCommand(packageRepository, username); when(goConfigService.updateConfigFromUI(eq(updateConfigFromUI), eq("md5"), eq(username), any(LocalizedOperationResult.class))).then(new Answer<ConfigUpdateResponse>() { @Override public ConfigUpdateResponse answer(InvocationOnMock invocationOnMock) throws Throwable { return new ConfigUpdateResponse(null, null, null, mock(ConfigAwareUpdate.class), ConfigSaveState.UPDATED); } }); when(localizer.localize("SAVED_CONFIGURATION_SUCCESSFULLY")).thenReturn("SAVED_CONFIGURATION_SUCCESSFULLY"); ConfigUpdateAjaxResponse response = service.savePackageRepositoryToConfig(packageRepository, "md5", username); assertThat(response.isSuccessful(), is(true)); assertThat(response.getMessage(), is("SAVED_CONFIGURATION_SUCCESSFULLY")); assertThat(response.getSubjectIdentifier(), is("repoid")); assertThat(response.getStatusCode(), is(HttpStatus.SC_OK)); verify(service).performPluginValidationsFor(packageRepository); verify(service).getPackageRepositoryUpdateCommand(packageRepository, username); } @Test public void shouldFailAndReturnReturnFailureResponse() throws Exception { service = spy(service); Username username = new Username(new CaseInsensitiveString("user")); final PackageRepository packageRepository = new PackageRepository(); packageRepository.errors().add("name", "Name is invalid"); final CruiseConfig cruiseConfig = GoConfigMother.configWithPipelines("sample"); cruiseConfig.errors().add("global", "error"); final UpdateConfigFromUI updateConfigFromUI = mock(UpdateConfigFromUI.class); final ConfigAwareUpdate configAwareUpdate = mock(ConfigAwareUpdate.class); doNothing().when(service).performPluginValidationsFor(packageRepository); doReturn(updateConfigFromUI).when(service).getPackageRepositoryUpdateCommand(packageRepository, username); when(configAwareUpdate.configAfter()).thenReturn(cruiseConfig); when(goConfigService.updateConfigFromUI(eq(updateConfigFromUI), eq("md5"), eq(username), any(LocalizedOperationResult.class))).then(new Answer<ConfigUpdateResponse>() { @Override public ConfigUpdateResponse answer(InvocationOnMock invocationOnMock) throws Throwable { LocalizedOperationResult result = (LocalizedOperationResult) invocationOnMock.getArguments()[3]; result.badRequest(LocalizedMessage.string("BAD_REQUEST")); return new ConfigUpdateResponse(cruiseConfig, cruiseConfig, packageRepository, configAwareUpdate, ConfigSaveState.UPDATED); } }); when(localizer.localize("BAD_REQUEST", new Object[]{})).thenReturn("Save Failed"); ConfigUpdateAjaxResponse response = service.savePackageRepositoryToConfig(packageRepository, "md5", username); assertThat(response.isSuccessful(), is(false)); assertThat(response.getMessage(), is("Save Failed")); assertThat(response.getFieldErrors().size(), is(1)); assertThat(response.getFieldErrors().get("package_repository[name]"), is(asList("Name is invalid"))); assertThat(response.getGlobalErrors().size(), is(1)); assertThat(response.getGlobalErrors().contains("error"), is(true)); assertThat(response.getStatusCode(), is(HttpStatus.SC_BAD_REQUEST)); verify(service).performPluginValidationsFor(packageRepository); verify(service).getPackageRepositoryUpdateCommand(packageRepository, username); } @Test public void shouldCheckIfUserCanAccessAdminPagesWhileUpdatingPackageRepository() throws Exception { Username username = new Username(new CaseInsensitiveString("user")); when(securityService.canViewAdminPage(username)).thenReturn(false); UpdateConfigFromUI updateCommand = service.getPackageRepositoryUpdateCommand(new PackageRepository(), username); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); updateCommand.checkPermission(GoConfigMother.configWithPipelines("sample"), result); assertThat(result.isSuccessful(), is(false)); assertThat(result.httpCode(), is(401)); verify(securityService).canViewAdminPage(username); } @Test public void shouldUpdateSubjectWhenUpdateCalledOnCommand() throws Exception { Username username = new Username(new CaseInsensitiveString("user")); PackageRepository packageRepository = new PackageRepository(); UpdateConfigFromUI updateCommand = service.getPackageRepositoryUpdateCommand(packageRepository, username); CruiseConfig cruiseConfig = mock(BasicCruiseConfig.class); updateCommand.update(cruiseConfig); verify(cruiseConfig).savePackageRepository(packageRepository); } @Test public void shouldValidateUpdateCommandForPackageRepository() throws Exception { Username username = new Username(new CaseInsensitiveString("user")); Validatable packageRepository = new PackageRepository(); ((PackageRepository) packageRepository).setId("id"); Validatable cruiseConfig = GoConfigMother.configWithPipelines("sample"); ((CruiseConfig) cruiseConfig).getPackageRepositories().add((PackageRepository) packageRepository); UpdateConfigFromUI updateCommand = service.getPackageRepositoryUpdateCommand((PackageRepository) packageRepository, username); assertThat(updateCommand.node((CruiseConfig) cruiseConfig), is(cruiseConfig)); assertThat(updateCommand.updatedNode((CruiseConfig) cruiseConfig), is(cruiseConfig)); assertThat(updateCommand.subject(cruiseConfig), is(packageRepository)); assertThat(updateCommand.updatedSubject(cruiseConfig), is(packageRepository)); } @Test public void shouldPerformPluginValidationsUsingMetaDataBeforeSavingPackageRepository() throws Exception { //metadata setup String pluginId = "yum"; PackageConfigurations repositoryConfiguration = new PackageConfigurations(); repositoryConfiguration.add(new PackageConfiguration("required").with(PackageConfiguration.REQUIRED, true)); repositoryConfiguration.add(new PackageConfiguration("required_secure").with(PackageConfiguration.REQUIRED, true).with(PackageConfiguration.SECURE, true)); repositoryConfiguration.add(new PackageConfiguration("secure").with(PackageConfiguration.SECURE, true).with(PackageConfiguration.REQUIRED, false)); repositoryConfiguration.add(new PackageConfiguration("not_required_not_secure")); RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, repositoryConfiguration); PackageRepository packageRepository = new PackageRepository(); packageRepository.setPluginConfiguration(new PluginConfiguration(pluginId, "1.0")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("required", false, "")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("required_secure", true, "")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("secure", true, "")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("not_required_not_secure", false, "")); when(packageRepositoryExtension.isRepositoryConfigurationValid(eq(pluginId),any(RepositoryConfiguration.class))).thenReturn(new ValidationResult()); when(pluginManager.getPluginDescriptorFor(pluginId)).thenReturn(new GoPluginDescriptor(pluginId, "1.0", null, null, null, true)); when(localizer.localize("MANDATORY_CONFIGURATION_FIELD")).thenReturn("mandatory field"); service.performPluginValidationsFor(packageRepository); assertThat(packageRepository.getConfiguration().get(0).getConfigurationValue().errors().getAllOn("value"), is(Arrays.asList("mandatory field"))); assertThat(packageRepository.getConfiguration().get(1).getEncryptedConfigurationValue().errors().getAllOn("value"), is(Arrays.asList("mandatory field"))); } @Test public void shouldInvokePluginValidationsBeforeSavingPackageRepository() throws Exception { String pluginId = "yum"; PackageRepository packageRepository = new PackageRepository(); RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, new PackageConfigurations()); packageRepository.setPluginConfiguration(new PluginConfiguration(pluginId, "1.0")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("url", false, "junk-url")); ArgumentCaptor<RepositoryConfiguration> packageConfigurationsArgumentCaptor = ArgumentCaptor.forClass(RepositoryConfiguration.class); ValidationResult expectedValidationResult = new ValidationResult(); expectedValidationResult.addError(new ValidationError("url", "url format incorrect")); when(pluginManager.getPluginDescriptorFor(pluginId)).thenReturn(new GoPluginDescriptor("yum", "1.0", null, null, null, true)); when(packageRepositoryExtension.isRepositoryConfigurationValid(eq(pluginId), packageConfigurationsArgumentCaptor.capture())).thenReturn(expectedValidationResult); service = new PackageRepositoryService(pluginManager, packageRepositoryExtension, goConfigService, securityService, entityHashingService,mock(Localizer.class)); service.performPluginValidationsFor(packageRepository); assertThat(packageRepository.getConfiguration().get(0).getConfigurationValue().errors().getAllOn("value"), is(Arrays.asList("url format incorrect"))); } @Test public void shouldAddErrorWhenPluginIdIsMissing() { PackageRepository packageRepository = new PackageRepository(); when(localizer.localize("PLUGIN_ID_REQUIRED")).thenReturn("Please provide plugin id"); service.performPluginValidationsFor(packageRepository); assertThat(packageRepository.getPluginConfiguration().errors().getAllOn(PluginConfiguration.ID), is(Arrays.asList("Please provide plugin id"))); } @Test public void shouldAddErrorWhenPluginIdIsInvalid() { when(pluginManager.plugins()).thenReturn(Arrays.asList(new GoPluginDescriptor("valid", "1.0", null, null, null, true))); PackageRepository packageRepository = new PackageRepository(); packageRepository.setPluginConfiguration(new PluginConfiguration("missing-plugin", "1.0")); when(localizer.localize("PLUGIN_ID_INVALID")).thenReturn("Invalid plugin id"); service.performPluginValidationsFor(packageRepository); assertThat(packageRepository.getPluginConfiguration().errors().getAllOn(PluginConfiguration.ID), is(Arrays.asList("Invalid plugin id"))); } @Test public void shouldUpdatePluginVersionWhenValid() { String pluginId = "valid"; RepositoryMetadataStore.getInstance().addMetadataFor(pluginId, new PackageConfigurations()); when(pluginManager.getPluginDescriptorFor(pluginId)).thenReturn(new GoPluginDescriptor(pluginId, "1.0", null, null, null, true)); when(packageRepositoryExtension.isRepositoryConfigurationValid(eq(pluginId), any(RepositoryConfiguration.class))).thenReturn(new ValidationResult()); PackageRepository packageRepository = new PackageRepository(); packageRepository.setPluginConfiguration(new PluginConfiguration(pluginId, "")); service.performPluginValidationsFor(packageRepository); assertThat(packageRepository.getPluginConfiguration().getVersion(), is("1.0")); } @Test public void shouldPerformCheckConnectionOnPlugin() throws Exception { String pluginId = "yum"; PackageRepository packageRepository = packageRepository(pluginId); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); PackageRepositoryService service = new PackageRepositoryService(pluginManager, packageRepositoryExtension, goConfigService, securityService, entityHashingService, localizer); ArgumentCaptor<RepositoryConfiguration> argumentCaptor = ArgumentCaptor.forClass(RepositoryConfiguration.class); when(packageRepositoryExtension.checkConnectionToRepository(eq(pluginId), argumentCaptor.capture())).thenReturn(new Result().withSuccessMessages("Accessed Repo File!!!")); service.checkConnection(packageRepository, result); RepositoryConfiguration packageConfigurations = argumentCaptor.getValue(); PackageMaterialTestHelper.assertPackageConfiguration(packageConfigurations.list(), packageRepository.getConfiguration()); assertThat(result.isSuccessful(), is(true)); when(localizer.localize("CONNECTION_OK", "Accessed Repo File!!!")).thenReturn("success_msg"); assertThat(result.message(localizer), is("success_msg")); verify(packageRepositoryExtension).checkConnectionToRepository(eq(pluginId),any(RepositoryConfiguration.class)); } @Test public void shouldPerformCheckConnectionOnPluginAndCatchAnyExceptionsThrownByThePlugin() throws Exception { String pluginId = "yum"; PackageRepository packageRepository = packageRepository(pluginId); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); PackageRepositoryService service = new PackageRepositoryService(pluginManager, packageRepositoryExtension, goConfigService, securityService, entityHashingService, localizer); ArgumentCaptor<RepositoryConfiguration> argumentCaptor = ArgumentCaptor.forClass(RepositoryConfiguration.class); when(packageRepositoryExtension.checkConnectionToRepository(eq(pluginId),argumentCaptor.capture())).thenThrow(new RuntimeException("Check Connection not implemented!!")); service.checkConnection(packageRepository, result); assertThat(result.isSuccessful(), is(false)); when(localizer.localize("CHECK_CONNECTION_FAILED", "package repository", "Check Connection not implemented!!")).thenReturn("error_msg"); assertThat(result.message(localizer), is("error_msg")); verify(packageRepositoryExtension).checkConnectionToRepository(eq(pluginId),any(RepositoryConfiguration.class)); } @Test public void shouldPopulateErrorsForCheckConnectionOnPlugin() throws Exception { String pluginId = "yum"; PackageRepository packageRepository = packageRepository(pluginId); HttpLocalizedOperationResult result = new HttpLocalizedOperationResult(); PackageRepositoryService service = new PackageRepositoryService(pluginManager, packageRepositoryExtension, goConfigService, securityService, entityHashingService, localizer); ArgumentCaptor<RepositoryConfiguration> argumentCaptor = ArgumentCaptor.forClass(RepositoryConfiguration.class); when(packageRepositoryExtension.checkConnectionToRepository(eq(pluginId),argumentCaptor.capture())).thenReturn(new Result().withErrorMessages("Repo invalid!!", "Could not connect")); service.checkConnection(packageRepository, result); RepositoryConfiguration packageConfigurations = argumentCaptor.getValue(); PackageMaterialTestHelper.assertPackageConfiguration(packageConfigurations.list(), packageRepository.getConfiguration()); assertThat(result.isSuccessful(), is(false)); when(localizer.localize("CHECK_CONNECTION_FAILED", "package repository","Repo invalid!!\nCould not connect")).thenReturn("error_msg"); assertThat(result.message(localizer), is("error_msg")); verify(packageRepositoryExtension).checkConnectionToRepository(eq(pluginId),any(RepositoryConfiguration.class)); } private PackageRepository packageRepository(String pluginId) { PackageRepository packageRepository = new PackageRepository(); packageRepository.setPluginConfiguration(new PluginConfiguration(pluginId, "1.0")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("p1", false, "v1")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("p2", true, "v2")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("p3", true, "v3")); packageRepository.getConfiguration().add(ConfigurationPropertyMother.create("p4", false, "v4")); return packageRepository; } }