/*************************** GO-LICENSE-START********************************* * 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. * ************************GO-LICENSE-END***********************************/ package com.thoughtworks.go.agent; import com.thoughtworks.go.buildsession.ArtifactsRepository; import com.thoughtworks.go.domain.Property; import com.thoughtworks.go.helper.TestStreamConsumer; import com.thoughtworks.go.util.CachedDigestUtils; import com.thoughtworks.go.util.FileUtil; import com.thoughtworks.go.util.HttpService; import com.thoughtworks.go.util.TestFileUtil; import com.thoughtworks.go.util.ZipUtil; import org.apache.commons.io.FileUtils; import org.junit.After; import org.junit.Before; import org.junit.Test; import org.junit.runner.RunWith; import org.mockito.ArgumentCaptor; import org.mockito.Mock; import org.mockito.runners.MockitoJUnitRunner; import javax.servlet.http.HttpServletResponse; import java.io.File; import java.io.IOException; import java.util.Properties; import static com.thoughtworks.go.matchers.ConsoleOutMatcher.printedUploadingFailure; import static org.hamcrest.core.Is.is; import static org.junit.Assert.assertThat; import static org.junit.Assert.fail; import static org.mockito.Mockito.any; import static org.mockito.Mockito.anyLong; import static org.mockito.Mockito.eq; import static org.mockito.Mockito.verify; import static org.mockito.Mockito.when; @RunWith(MockitoJUnitRunner.class) public class UrlBasedArtifactsRepositoryTest { @Mock private HttpService httpService; private File tempFile; private File artifactFolder; private ArtifactsRepository artifactsRepository; private TestStreamConsumer console; @Before public void setUp() throws Exception { artifactFolder = TestFileUtil.createTempFolder("artifact_folder"); tempFile = TestFileUtil.createTestFile(artifactFolder, "file.txt"); console = new TestStreamConsumer(); artifactsRepository = new UrlBasedArtifactsRepository(httpService, "http://baseurl/artifacts/", "http://baseurl/properties/", new ZipUtil()); } @After public void tearDown() throws IOException { FileUtil.tryDeleting(artifactFolder); } @Test public void shouldBombWithErrorWhenStatusCodeReturnedIsRequestEntityTooLarge() throws IOException, InterruptedException { long size = anyLong(); when(httpService.upload(any(String.class), size, any(File.class), any(Properties.class))).thenReturn(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); try { artifactsRepository.upload(console, tempFile, "some_dest", "build42"); fail("should have thrown request entity too large error"); } catch (RuntimeException e) { String expectedMessage = "Artifact upload for file " + tempFile.getAbsolutePath() + " (Size: " + size + ") was denied by the server. This usually happens when server runs out of disk space."; assertThat(e.getMessage(), is("java.lang.RuntimeException: " + expectedMessage + ". HTTP return code is 413")); assertThat(console.output().contains(expectedMessage), is(true)); } } @Test public void uploadShouldBeGivenFileSize() throws IOException { when(httpService.upload(any(String.class), eq(tempFile.length()), any(File.class), any(Properties.class))).thenReturn(HttpServletResponse.SC_REQUEST_ENTITY_TOO_LARGE); try { artifactsRepository.upload(console, tempFile, "dest", "build42"); fail("should have thrown request entity too large error"); } catch (RuntimeException e) { verify(httpService).upload(eq("http://baseurl/artifacts/dest?attempt=1&buildId=build42"), eq(tempFile.length()), any(File.class), any(Properties.class)); } } @Test public void shouldRetryUponUploadFailure() throws IOException { String data = "Some text whose checksum can be asserted"; final String md5 = CachedDigestUtils.md5Hex(data); FileUtils.writeStringToFile(tempFile, data); Properties properties = new Properties(); properties.setProperty("dest/path/file.txt", md5); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=1&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_BAD_GATEWAY); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=2&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_BAD_GATEWAY); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=3&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_OK); artifactsRepository.upload(console, tempFile, "dest/path", "build42"); } @Test public void shouldPrintFailureMessageToConsoleWhenUploadFailed() throws IOException { String data = "Some text whose checksum can be asserted"; final String md5 = CachedDigestUtils.md5Hex(data); FileUtils.writeStringToFile(tempFile, data); Properties properties = new Properties(); properties.setProperty("dest/path/file.txt", md5); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=1&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_BAD_GATEWAY); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=2&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_BAD_GATEWAY); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=3&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_BAD_GATEWAY); try { artifactsRepository.upload(console, tempFile, "dest/path", "build42"); fail("should have thrown request entity too large error"); } catch (RuntimeException e) { assertThat(console.output(), printedUploadingFailure(tempFile)); } } @Test public void shouldUploadArtifactChecksumAlongWithArtifact() throws IOException { String data = "Some text whose checksum can be asserted"; final String md5 = CachedDigestUtils.md5Hex(data); FileUtils.writeStringToFile(tempFile, data); Properties properties = new Properties(); properties.setProperty("dest/path/file.txt", md5); when(httpService.upload(eq("http://baseurl/artifacts/dest/path?attempt=1&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_OK); artifactsRepository.upload(console, tempFile, "dest/path", "build42"); } @Test public void shouldUploadArtifactChecksumWithRightPathWhenArtifactDestinationPathIsEmpty() throws IOException { String data = "Some text whose checksum can be asserted"; final String md5 = CachedDigestUtils.md5Hex(data); FileUtils.writeStringToFile(tempFile, data); Properties properties = new Properties(); properties.setProperty("file.txt", md5); when(httpService.upload(eq("http://baseurl/artifacts/?attempt=1&buildId=build42"), eq(tempFile.length()), any(File.class), eq(properties))).thenReturn(HttpServletResponse.SC_OK); artifactsRepository.upload(console, tempFile, "", "build42"); } @Test public void shouldUploadArtifactChecksumForADirectory() throws IOException { String data = "Some text whose checksum can be asserted"; String secondData = "some more"; FileUtils.writeStringToFile(tempFile, data); File anotherFile = new File(artifactFolder, "bond/james_bond/another_file"); FileUtils.writeStringToFile(anotherFile, secondData); when(httpService.upload(eq("http://baseurl/artifacts/dest?attempt=1&buildId=build42"), eq(FileUtils.sizeOfDirectory(artifactFolder)), any(File.class), eq(expectedProperties(data, secondData)))).thenReturn(HttpServletResponse.SC_OK); artifactsRepository.upload(console, artifactFolder, "dest", "build42"); } @Test public void setRemoteBuildPropertyShouldEncodePropertyName() throws IOException { ArgumentCaptor<String> url = ArgumentCaptor.forClass(String.class); ArgumentCaptor<String> value = ArgumentCaptor.forClass(String.class); artifactsRepository.setProperty(new Property("fo,o", "bar")); verify(httpService).postProperty(url.capture(), value.capture()); assertThat(value.getValue(), is("bar")); assertThat(url.getValue(), is("http://baseurl/properties/fo%2Co")); } private Properties expectedProperties(String data, String secondData) { Properties properties = new Properties(); properties.setProperty("dest/artifact_folder/file.txt", CachedDigestUtils.md5Hex(data)); properties.setProperty("dest/artifact_folder/bond/james_bond/another_file", CachedDigestUtils.md5Hex(secondData)); return properties; } }