package org.jboss.arquillian.drone.webdriver.binary.downloading.source; import com.google.common.base.Charsets; import com.google.common.io.CharStreams; import io.specto.hoverfly.junit.dsl.ResponseBuilder; import io.specto.hoverfly.junit.rule.HoverflyRule; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.PrintWriter; import org.apache.http.HttpHeaders; import org.apache.http.HttpStatus; import org.assertj.core.api.JUnitSoftAssertions; import org.jboss.arquillian.drone.webdriver.binary.downloading.ExternalBinary; import org.jboss.arquillian.drone.webdriver.utils.GitHubLastUpdateCache; import org.jboss.arquillian.drone.webdriver.utils.HttpClient; import org.junit.Before; import org.junit.ClassRule; import org.junit.Rule; import org.junit.Test; import org.junit.rules.TemporaryFolder; import static io.specto.hoverfly.junit.core.SimulationSource.dsl; import static io.specto.hoverfly.junit.dsl.HoverflyDsl.service; import static org.mockito.ArgumentMatchers.any; import static org.mockito.ArgumentMatchers.anyMap; import static org.mockito.ArgumentMatchers.anyString; import static org.mockito.Mockito.spy; import static org.mockito.Mockito.times; import static org.mockito.Mockito.verify; public class GitHubSourceLatestReleaseTestCase { private static final String CACHED_CONTENT = "{\"lastModified\":\"Tue, 31 Jan 2017 17:16:07 GMT\"," + "\"asset\":" + "{\"version\":\"v0.14.0\"," + "\"url\":\"https://github.com/mozilla/geckodriver/releases/download/v0.14.0/geckodriver-v0.14.0-linux64.tar.gz\"}" + "}"; @ClassRule public static HoverflyRule hoverflyRule = HoverflyRule.inSimulationMode(); @Rule public final TemporaryFolder folder = new TemporaryFolder(); @Rule public final JUnitSoftAssertions softly = new JUnitSoftAssertions(); private final String RESPONSE_BODY; private File tmpFolder; private GeckoDriverGitHubSource geckoDriverGitHubSource; private HttpClient httpClientSpy; private GitHubLastUpdateCache cacheSpy; public GitHubSourceLatestReleaseTestCase() throws IOException { this.RESPONSE_BODY = loadResponseBody("hoverfly/gh.simulation.mozilla@geckodriver.release.latest.json"); } @Before public void wireComponentsUnderTest() throws IOException { this.tmpFolder = folder.newFolder(); this.httpClientSpy = spy(new HttpClient()); this.cacheSpy = spy(new GitHubLastUpdateCache(tmpFolder)); this.geckoDriverGitHubSource = new GeckoDriverGitHubSource(httpClientSpy, cacheSpy); } @Test public void should_load_release_information_from_gh_and_store_in_cache() throws Exception { // given hoverflyRule.simulate(dsl(service("https://api.github.com") .get("/repos/mozilla/geckodriver/releases/latest") .queryParam("page", 1) .willReturn( ResponseBuilder.response().header("Last-Modified", "Tue, 31 Jan 2017 17:16:07 GMT").body(RESPONSE_BODY) ))); final String expectedVersion = "v0.14.0"; // when final ExternalBinary latestRelease = geckoDriverGitHubSource.getLatestRelease(); // then softly.assertThat(latestRelease.getVersion()).isEqualTo(expectedVersion); softly.assertThat(tmpFolder.listFiles()).hasSize(1); softly.assertThat(tmpFolder.listFiles()[0]).isFile().hasContent(CACHED_CONTENT); verify(httpClientSpy).get(anyString(), anyMap()); verify(cacheSpy, times(0)).load(anyString(), any()); verify(cacheSpy, times(1)).store(any(), anyString(), any()); } @Test public void should_load_release_information_from_cache_when_not_changed() throws Exception { // given hoverflyRule.simulate(dsl(service("https://api.github.com") .get("/repos/mozilla/geckodriver/releases/latest") .header(HttpHeaders.IF_MODIFIED_SINCE, "Tue, 31 Jan 2017 17:16:07 GMT") .queryParam("page", 1) .willReturn( ResponseBuilder.response().status(HttpStatus.SC_NOT_MODIFIED) ))); createCacheFile("gh.cache.mozilla@geckodriver.json", CACHED_CONTENT); final String expectedVersion = "v0.14.0"; // when final ExternalBinary latestRelease = geckoDriverGitHubSource.getLatestRelease(); // then softly.assertThat(latestRelease.getVersion()).isEqualTo(expectedVersion); softly.assertThat(tmpFolder.listFiles()).hasSize(1); softly.assertThat(tmpFolder.listFiles()[0]).isFile().hasContent(CACHED_CONTENT); verify(httpClientSpy).get(anyString(), anyMap()); verify(cacheSpy, times(1)).load(anyString(), any()); verify(cacheSpy, times(0)).store(any(), anyString(), any()); } @Test // With this test we make sure that the internal date is converted to RFC 2126 with GMT prior to GH call public void should_load_release_information_from_gh_and_overwrite_cache_when_last_modified_changed() throws Exception { // given String cached_content = "{\"lastModified\":\"Sun, 01 Jan 2017 18:16:07 +0100\"," + // Here we store the date with the offset "\"asset\":" + "{\"version\":\"v0.14.0\"," + "\"url\":\"https://github.com/mozilla/geckodriver/releases/download/v0.14.0/geckodriver-v0.14.0-linux64.tar.gz\"}" + "}"; hoverflyRule.simulate(dsl(service("https://api.github.com") .get("/repos/mozilla/geckodriver/releases/latest") .header(HttpHeaders.IF_MODIFIED_SINCE, "Sun, 01 Jan 2017 17:16:07 GMT") // But we expect it to be sent in GMT, as this is how we match the request .queryParam("page", 1) .willReturn( ResponseBuilder.response().header("Last-Modified", "Tue, 31 Jan 2017 17:16:07 GMT").body(RESPONSE_BODY) ))); createCacheFile("gh.cache.mozilla@geckodriver.json", cached_content); final String expectedVersion = "v0.14.0"; // when final ExternalBinary latestRelease = geckoDriverGitHubSource.getLatestRelease(); // then softly.assertThat(latestRelease.getVersion()).isEqualTo(expectedVersion); softly.assertThat(tmpFolder.listFiles()).hasSize(1); softly.assertThat(tmpFolder.listFiles()[0]).isFile().hasContent(CACHED_CONTENT); verify(httpClientSpy).get(anyString(), anyMap()); verify(cacheSpy, times(0)).load(anyString(), any()); verify(cacheSpy, times(1)).store(any(), anyString(), any()); } private String loadResponseBody(String path) throws IOException { String response; ClassLoader classLoader = getClass().getClassLoader(); try (final InputStreamReader inputStreamReader = new InputStreamReader(classLoader.getResourceAsStream(path), Charsets.UTF_8)) { response = CharStreams.toString(inputStreamReader); } return response; } private void createCacheFile(String fileName, String content) throws FileNotFoundException { try (final PrintWriter printWriter = new PrintWriter(new File(tmpFolder.getAbsolutePath() + "/" + fileName))) { printWriter.print(content); printWriter.flush(); } } }