diff --git a/README.md b/README.md index 0f19e26..ada9d14 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ Maven NodeJS Proxy ====== [![Build Status](https://travis-ci.org/wcm-io-devops/maven-nodejs-proxy.png?branch=develop)](https://travis-ci.org/wcm-io-devops/maven-nodejs-proxy) +[![Maven Central](https://maven-badges.herokuapp.com/maven-central/io.wcm.devops.maven/io.wcm.devops.maven.nodejs-proxy/badge.svg)](https://maven-badges.herokuapp.com/maven-central/io.wcm.devops.maven/io.wcm.devops.maven.nodejs-proxy) Maven proxy to download NodeJS binaries as Maven artifacts. diff --git a/changes.xml b/changes.xml index f79810f..491ab1c 100644 --- a/changes.xml +++ b/changes.xml @@ -23,6 +23,16 @@ xsi:schemaLocation="http://maven.apache.org/changes/1.0.0 http://maven.apache.org/plugins/maven-changes-plugin/xsd/changes-1.0.0.xsd"> + + + Binary File Structre changed in NPM Versions > 0.x and support for SHA-256 checksums. + Please update your configuration file, some parameters needed to be changed. + + + Update to dropwizard 0.9.2. + + + Initial release. diff --git a/maven-nodejs-proxy/config.yml b/maven-nodejs-proxy/config.yml index f54dd4b..c4a0fa5 100644 --- a/maven-nodejs-proxy/config.yml +++ b/maven-nodejs-proxy/config.yml @@ -1,3 +1,6 @@ +# This is a Dropwizard-based Microservice +# See https://dropwizard.github.io/dropwizard/manual/configuration.html + # Group Id to publish artifacts to groupId: org.nodejs.dist @@ -12,12 +15,17 @@ nodeJsBinariesRootUrl: "https://nodejs.org/dist" # Url parts to download the different artifacts nodeJsBinariesUrl: "/v${version}/node-v${version}-${os}-${arch}.${type}" -nodeJsBinariesUrlWindows: "/v${version}/${arch}/node.${type}" -nodeJsBinariesUrlWindowsX86: "/v${version}/node.${type}" +nodeJsBinariesUrlWindows: "/v${version}/win-${arch}/node.${type}" +nodeJsBinariesUrlWindowsX86Legacy: "/v${version}/node.${type}" +nodeJsBinariesUrlWindowsX64Legacy: "/v${version}/${arch}/node.${type}" npmBinariesUrl: "/npm/npm-${version}.${type}" -# SHA-1 checksums file -nodeJsChecksumUrl: "/v${version}/SHASUMS.txt" +# SHA-256 checksums file +nodeJsChecksumUrl: "/v${version}/SHASUMS256.txt" + +# Sample versions for index page +nodeJsSampleVersion: 4.4.0 +npmSampleVersion: 1.4.9 # HTTP Client settings httpClient: diff --git a/maven-nodejs-proxy/pom.xml b/maven-nodejs-proxy/pom.xml index 24e40b7..02030b2 100644 --- a/maven-nodejs-proxy/pom.xml +++ b/maven-nodejs-proxy/pom.xml @@ -25,20 +25,20 @@ io.wcm.devops io.wcm.devops.parent_toplevel - 1.0.0 + 1.0.2 io.wcm.devops.maven io.wcm.devops.maven.nodejs-proxy - 1.0.0 + 1.1.0 jar Maven NodeJS Proxy Maven proxy to download NodeJS binaries as Maven artifacts. - 0.9.0-rc4 + 0.9.2 @@ -55,6 +55,12 @@ ${dropwizard.version} compile + + io.dropwizard + dropwizard-testing + ${dropwizard.version} + test + commons-io @@ -70,6 +76,13 @@ compile + + org.apache.maven + maven-artifact + 3.3.9 + compile + + @@ -78,7 +91,6 @@ org.apache.maven.plugins maven-shade-plugin - 2.3 true @@ -122,6 +134,16 @@ + + + org.apache.maven.plugins + maven-surefire-plugin + + none + 0 + + + diff --git a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/MavenProxyConfiguration.java b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/MavenProxyConfiguration.java index 8e3da03..2f5be53 100644 --- a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/MavenProxyConfiguration.java +++ b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/MavenProxyConfiguration.java @@ -19,9 +19,6 @@ */ package io.wcm.devops.maven.nodejsproxy; -import io.dropwizard.Configuration; -import io.dropwizard.client.HttpClientConfiguration; - import javax.validation.Valid; import javax.validation.constraints.NotNull; @@ -29,6 +26,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; +import io.dropwizard.Configuration; +import io.dropwizard.client.HttpClientConfiguration; + /** * Configuration for Maven NodeJS Proxy. */ @@ -47,11 +47,17 @@ public class MavenProxyConfiguration extends Configuration { @NotEmpty private String nodeJsBinariesUrlWindows; @NotEmpty - private String nodeJsBinariesUrlWindowsX86; + private String nodeJsBinariesUrlWindowsX86Legacy; + @NotEmpty + private String nodeJsBinariesUrlWindowsX64Legacy; @NotEmpty private String npmBinariesUrl; @NotEmpty private String nodeJsChecksumUrl; + @NotEmpty + private String nodeJsSampleVersion; + @NotEmpty + private String npmSampleVersion; @Valid @NotNull @@ -88,8 +94,13 @@ public String getNodeJsBinariesUrlWindows() { } @JsonProperty - public String getNodeJsBinariesUrlWindowsX86() { - return this.nodeJsBinariesUrlWindowsX86; + public String getNodeJsBinariesUrlWindowsX86Legacy() { + return this.nodeJsBinariesUrlWindowsX86Legacy; + } + + @JsonProperty + public String getNodeJsBinariesUrlWindowsX64Legacy() { + return this.nodeJsBinariesUrlWindowsX64Legacy; } @JsonProperty @@ -102,6 +113,16 @@ public String getNodeJsChecksumUrl() { return this.nodeJsChecksumUrl; } + @JsonProperty + public String getNodeJsSampleVersion() { + return this.nodeJsSampleVersion; + } + + @JsonProperty + public String getNpmSampleVersion() { + return this.npmSampleVersion; + } + @JsonProperty("httpClient") public HttpClientConfiguration getHttpClient() { return httpClient; diff --git a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/Checksums.java b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/Checksums.java index 743863f..d0215c4 100644 --- a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/Checksums.java +++ b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/Checksums.java @@ -34,7 +34,7 @@ public class Checksums { private final Map checksums = new HashMap<>(); private static final Pattern LEVEL_1_RELATIVE_NAME = Pattern.compile("^.*/([^/]+)$"); - private static final Pattern LEVEL_2_RELATIVE_NAME = Pattern.compile("^.*/([^/]+/[^/]+)$");; + private static final Pattern LEVEL_2_RELATIVE_NAME = Pattern.compile("^.*/([^/]+/[^/]+)$"); /** * @param data Checksums file content @@ -42,10 +42,10 @@ public class Checksums { public Checksums(String data) { String[] lines = StringUtils.split(data, "\n"); for (String line : lines) { - String sha1 = StringUtils.substringBefore(line, " "); + String checksum = StringUtils.substringBefore(line, " "); String filename = StringUtils.substringAfter(line, " "); - if (StringUtils.isNoneBlank(sha1, filename)) { - checksums.put(filename, sha1); + if (StringUtils.isNoneBlank(checksum, filename)) { + checksums.put(filename, checksum); } } } diff --git a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/IndexPageBuilder.java b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/IndexPageBuilder.java index 4f332e2..bd75cd3 100644 --- a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/IndexPageBuilder.java +++ b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/IndexPageBuilder.java @@ -19,25 +19,24 @@ */ package io.wcm.devops.maven.nodejsproxy.resource; -import io.wcm.devops.maven.nodejsproxy.MavenProxyConfiguration; - import org.apache.commons.lang3.StringUtils; +import io.wcm.devops.maven.nodejsproxy.MavenProxyConfiguration; + /** * Builds HTML index page */ public final class IndexPageBuilder { private static final String[] EXAMPLE_URLS = new String[] { - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0.pom", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-windows-x86.exe", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-windows-x64.exe", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-linux-x86.tar.gz", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-linux-x64.tar.gz", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-darwin-x86.tar.gz", - "${groupIdPath}/${nodeJsArtifactId}/0.12.0/${nodeJsArtifactId}-0.12.0-darwin-x64.tar.gz", - "${groupIdPath}/${npmArtifactId}/1.4.9/${npmArtifactId}-1.4.9.pom", - "${groupIdPath}/${npmArtifactId}/1.4.9/${npmArtifactId}-1.4.9.tgz" + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}.pom", + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}-windows-x86.exe", + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}-windows-x64.exe", + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}-linux-x86.tar.gz", + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}-linux-x64.tar.gz", + "${groupIdPath}/${nodeJsArtifactId}/${nodeJsSampleVersion}/${nodeJsArtifactId}-${nodeJsSampleVersion}-darwin-x64.tar.gz", + "${groupIdPath}/${npmArtifactId}/${npmSampleVersion}/${npmArtifactId}-${npmSampleVersion}.pom", + "${groupIdPath}/${npmArtifactId}/${npmSampleVersion}/${npmArtifactId}-${npmSampleVersion}.tgz" }; private IndexPageBuilder() { @@ -54,14 +53,19 @@ public static String build(MavenProxyConfiguration config) { url = StringUtils.replace(url, "${groupIdPath}", StringUtils.replace(config.getGroupId(), ".", "/")); url = StringUtils.replace(url, "${nodeJsArtifactId}", config.getNodeJsArtifactId()); url = StringUtils.replace(url, "${npmArtifactId}", config.getNpmArtifactId()); + url = StringUtils.replace(url, "${nodeJsSampleVersion}", config.getNodeJsSampleVersion()); + url = StringUtils.replace(url, "${npmSampleVersion}", config.getNpmSampleVersion()); exampleUrlsMarkup.append("
  • ").append(url).append("
  • "); } String serviceVersion = IndexPageBuilder.class.getPackage().getImplementationVersion(); - return "" - + "Maven NodeJS Proxy" + return "\n" + + "" + + "Maven NodeJS Proxy" + + "" + + "" + "" + "

    Maven NodeJS Proxy

    " + "

    This is a Maven Artifact Proxy for NodeJS binaries located at: " @@ -69,7 +73,7 @@ public static String build(MavenProxyConfiguration config) { + "

    Every call to this repository is routed directly to this URL.

    " + "

    Please never use this Maven repository directly in your maven builds, but only via an Repository Manager " + "which caches the resolved artifacts.

    " - + "

    If you want to setup your own proxy get the source code:" + + "

    If you want to setup your own proxy get the source code: " + "https://github.com/wcm-io-devops/maven-nodejs-proxy

    " + "
    " + "

    Examples:

    " diff --git a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResource.java b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResource.java index b808240..6329f74 100644 --- a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResource.java +++ b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResource.java @@ -20,7 +20,6 @@ package io.wcm.devops.maven.nodejsproxy.resource; import static javax.ws.rs.core.HttpHeaders.CONTENT_LENGTH; -import io.wcm.devops.maven.nodejsproxy.MavenProxyConfiguration; import java.io.IOException; @@ -39,11 +38,14 @@ import org.apache.http.client.methods.HttpHead; import org.apache.http.impl.client.CloseableHttpClient; import org.apache.http.util.EntityUtils; +import org.apache.maven.artifact.versioning.DefaultArtifactVersion; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import com.codahale.metrics.annotation.Timed; +import io.wcm.devops.maven.nodejsproxy.MavenProxyConfiguration; + /** * Proxies NodeJS binaries. */ @@ -166,39 +168,8 @@ public Response getBinary( getChecksum = true; } - // return checksum from SHASUMS.txt - if (getChecksum) { - Checksums checksums = getChecksums(version); - String url = buildBinaryUrl(artifactType, version, os, arch, StringUtils.removeEnd(type, ".sha1")); - String checksum = checksums.get(url); - if (checksum != null) { - return Response.ok(checksum) - .type(MediaType.TEXT_PLAIN) - .build(); - } - else { - return Response.status(Response.Status.NOT_FOUND).build(); - } - } - - // return binary file - else { - String url = buildBinaryUrl(artifactType, version, os, arch, type); - - log.info("Proxy file: {}", url); - HttpGet get = new HttpGet(url); - HttpResponse response = httpClient.execute(get); - if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) { - return Response.ok(new SpoolStreamingOutput(response.getEntity())) - .type(MediaType.APPLICATION_OCTET_STREAM) - .header(CONTENT_LENGTH, response.containsHeader(CONTENT_LENGTH) ? response.getFirstHeader(CONTENT_LENGTH).getValue() : null) - .build(); - } - else { - EntityUtils.consumeQuietly(response.getEntity()); - return Response.status(Response.Status.NOT_FOUND).build(); - } - } + String url = buildBinaryUrl(artifactType, version, os, arch, StringUtils.removeEnd(type, ".sha1")); + return getBinaryWithChecksumValidation(url, version, getChecksum); } /** @@ -235,20 +206,48 @@ public Response getBinary( } String url = buildBinaryUrl(artifactType, version, null, null, StringUtils.removeEnd(type, ".sha1")); + return getBinary(url, version, getChecksum, null); + } + + private Response getBinaryWithChecksumValidation(String url, String version, boolean getChecksum) throws IOException { + // get original checksum from source directory + Checksums checksums = getChecksums(version); + if (checksums == null) { + log.info("File not found: {} - no checksum file found.", url); + return Response.status(Response.Status.NOT_FOUND).build(); + } + String checksum = checksums.get(url); + if (checksum == null) { + log.info("File not found: {} - no checksum found in checkum file.", url); + return Response.status(Response.Status.NOT_FOUND).build(); + } + return getBinary(url, version, getChecksum, checksum); + } + + private Response getBinary(String url, String version, boolean getChecksum, String expectedChecksum) throws IOException { log.info("Proxy file: {}", url); HttpGet get = new HttpGet(url); HttpResponse response = httpClient.execute(get); if (response.getStatusLine().getStatusCode() == HttpServletResponse.SC_OK) { + byte[] data = EntityUtils.toByteArray(response.getEntity()); + + // validate checksum + if (expectedChecksum != null) { + String remoteChecksum = DigestUtils.sha256Hex(data); + if (!StringUtils.equals(expectedChecksum, remoteChecksum)) { + log.warn("Reject file: {} - checksum comparison failed - expected: {}, actual: {}", url, expectedChecksum, remoteChecksum); + return Response.status(Response.Status.NOT_FOUND).build(); + } + } + if (getChecksum) { - byte[] data = EntityUtils.toByteArray(response.getEntity()); - EntityUtils.consumeQuietly(response.getEntity()); return Response.ok(DigestUtils.sha1Hex(data)) .type(MediaType.TEXT_PLAIN) .build(); } else { - return Response.ok(new SpoolStreamingOutput(response.getEntity())) + return Response.ok(data) .type(MediaType.APPLICATION_OCTET_STREAM) .header(CONTENT_LENGTH, response.containsHeader(CONTENT_LENGTH) ? response.getFirstHeader(CONTENT_LENGTH).getValue() : null) .build(); @@ -337,11 +336,14 @@ private String buildBinaryUrl(ArtifactType artifactType, String version, String switch (artifactType) { case NODEJS: if (StringUtils.equals(os, "windows")) { - if (StringUtils.equals(arch, "x86")) { - url = config.getNodeJsBinariesUrlWindowsX86(); + if (isVersion4Up(version)) { + url = config.getNodeJsBinariesUrlWindows(); + } + else if (StringUtils.equals(arch, "x86")) { + url = config.getNodeJsBinariesUrlWindowsX86Legacy(); } else { - url = config.getNodeJsBinariesUrlWindows(); + url = config.getNodeJsBinariesUrlWindowsX64Legacy(); } } else { @@ -362,4 +364,10 @@ private String buildBinaryUrl(ArtifactType artifactType, String version, String return url; } + private boolean isVersion4Up(String version) { + DefaultArtifactVersion givenVersion = new DefaultArtifactVersion(version); + DefaultArtifactVersion minVersion = new DefaultArtifactVersion("4.0.0"); + return givenVersion.compareTo(minVersion) >= 0; + } + } diff --git a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/SpoolStreamingOutput.java b/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/SpoolStreamingOutput.java deleted file mode 100644 index 88dc2aa..0000000 --- a/maven-nodejs-proxy/src/main/java/io/wcm/devops/maven/nodejsproxy/resource/SpoolStreamingOutput.java +++ /dev/null @@ -1,57 +0,0 @@ -/* - * #%L - * wcm.io - * %% - * Copyright (C) 2015 wcm.io - * %% - * 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. - * #L% - */ -package io.wcm.devops.maven.nodejsproxy.resource; - -import java.io.IOException; -import java.io.InputStream; -import java.io.OutputStream; - -import javax.ws.rs.WebApplicationException; -import javax.ws.rs.core.StreamingOutput; - -import org.apache.commons.io.IOUtils; -import org.apache.http.HttpEntity; -import org.apache.http.util.EntityUtils; - -/** - * Spool binary data from HTTP response to JAX-RS output. - */ -class SpoolStreamingOutput implements StreamingOutput { - - private final HttpEntity httpEntity; - - public SpoolStreamingOutput(HttpEntity httpEntity) { - this.httpEntity = httpEntity; - } - - @Override - public void write(OutputStream os) throws IOException, WebApplicationException { - try (InputStream is = httpEntity.getContent()) { - IOUtils.copyLarge(is, os); - } - catch (IOException ex) { - // ignore - } - finally { - EntityUtils.consumeQuietly(httpEntity); - } - } - -} diff --git a/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResourceTest.java b/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResourceTest.java new file mode 100644 index 0000000..63ed700 --- /dev/null +++ b/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/MavenProxyResourceTest.java @@ -0,0 +1,141 @@ +/* + * #%L + * wcm.io + * %% + * Copyright (C) 2016 wcm.io + * %% + * 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. + * #L% + */ +package io.wcm.devops.maven.nodejsproxy.resource; + +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; + +import java.io.IOException; +import java.io.InputStream; + +import javax.ws.rs.core.MediaType; +import javax.ws.rs.core.Response; + +import org.apache.commons.codec.digest.DigestUtils; +import org.apache.commons.io.IOUtils; +import org.apache.http.HttpStatus; +import org.junit.Rule; +import org.junit.Test; + +import io.dropwizard.testing.junit.ResourceTestRule; + + +public class MavenProxyResourceTest { + + // test with the following NodeJS and NPM versions + private static final String[] NODEJS_VERSIONS = { + "0.12.0", + "4.4.0" + }; + private static final String[] NODEJS_TARGETS = { + "-windows-x86.exe", + "-windows-x64.exe", + "-linux-x86.tar.gz", + "-linux-x64.tar.gz", + "-darwin-x64.tar.gz" + }; + private static final String[] NPM_VERSIONS = { + "1.4.9" + }; + private static final String[] NPM_TARGETS = { + ".tgz" + }; + + @Rule + public ResourceTestRule context = new ResourceTestRule.Builder() + .addResource(new MavenProxyResource(TestContext.getConfiguration(), TestContext.getHttpClient())) + .build(); + + @Test + public void testGetIndex() { + String path = "/"; + Response response = context.client().target(path).request().get(); + assertResponse(path, response, MediaType.TEXT_HTML); + } + + @Test + public void testGetPomNodeJS() { + for (String version : NODEJS_VERSIONS) { + String path = "/org/nodejs/dist/nodejs-binaries/" + version + "/nodejs-binaries-" + version + ".pom"; + Response response = context.client().target(path).request().get(); + assertResponse(path, response, MediaType.APPLICATION_XML); + assertTrue("Content length " + path, response.getLength() > 0); + assertSHA1(path, response); + } + } + + @Test + public void testGetPomNPM() { + for (String version : NPM_VERSIONS) { + String path = "/org/nodejs/dist/npm-binaries/" + version + "/npm-binaries-" + version + ".pom"; + Response response = context.client().target(path).request().get(); + assertResponse(path, response, MediaType.APPLICATION_XML); + assertTrue("Content length " + path, response.getLength() > 0); + assertSHA1(path, response); + } + } + + @Test + public void testGetBinaryNodeJS() { + for (String version : NODEJS_VERSIONS) { + for (String target : NODEJS_TARGETS) { + String path = "/org/nodejs/dist/nodejs-binaries/" + version + "/nodejs-binaries-" + version + target; + Response response = context.client().target(path).request().get(); + assertResponse(path, response, MediaType.APPLICATION_OCTET_STREAM); + assertSHA1(path, response); + } + } + } + + @Test + public void testGetBinaryNPM() { + for (String version : NPM_VERSIONS) { + for (String target : NPM_TARGETS) { + String path = "/org/nodejs/dist/npm-binaries/" + version + "/npm-binaries-" + version + target; + Response response = context.client().target(path).request().get(); + assertResponse(path, response, MediaType.APPLICATION_OCTET_STREAM); + assertSHA1(path, response); + } + } + } + + private void assertResponse(String path, Response response, String mediaType) { + System.out.println("Integration test: " + path); + assertEquals("HTTP status " + path, HttpStatus.SC_OK, response.getStatus()); + assertEquals("Media type " + path, mediaType, response.getMediaType().toString()); + assertTrue(response.hasEntity()); + } + + private void assertSHA1(String path, Response dataResponse) { + String sha1Path = path + ".sha1"; + Response sha1Response = context.client().target(sha1Path).request().get(); + assertResponse(sha1Path, sha1Response, MediaType.TEXT_PLAIN); + + try (InputStream is = dataResponse.readEntity(InputStream.class)) { + byte[] data = IOUtils.toByteArray(is); + String sha1 = sha1Response.readEntity(String.class); + assertEquals("SHA-1 " + path, sha1, DigestUtils.sha1Hex(data)); + } + catch (IOException ex) { + throw new RuntimeException("Error checking SHA-1 of " + path, ex); + } + } + +} diff --git a/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/TestContext.java b/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/TestContext.java new file mode 100644 index 0000000..f2311d5 --- /dev/null +++ b/maven-nodejs-proxy/src/test/java/io/wcm/devops/maven/nodejsproxy/resource/TestContext.java @@ -0,0 +1,62 @@ +/* + * #%L + * wcm.io + * %% + * Copyright (C) 2016 wcm.io + * %% + * 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. + * #L% + */ +package io.wcm.devops.maven.nodejsproxy.resource; + +import java.io.File; +import java.io.IOException; + +import org.apache.http.impl.client.CloseableHttpClient; +import org.apache.http.impl.client.HttpClients; + +import com.fasterxml.jackson.databind.ObjectMapper; + +import io.dropwizard.configuration.ConfigurationException; +import io.dropwizard.configuration.ConfigurationFactory; +import io.dropwizard.jackson.Jackson; +import io.wcm.devops.maven.nodejsproxy.MavenProxyConfiguration; + +final class TestContext { + + private static final ObjectMapper OBJECT_MAPPER = Jackson.newObjectMapper(); + + private TestContext() { + // static methods only + } + + static MavenProxyConfiguration getConfiguration() { + ConfigurationFactory factory = new ConfigurationFactory( + MavenProxyConfiguration.class, null, OBJECT_MAPPER, "override"); + try { + File configFile = new File("config.yml"); + if (!configFile.exists()) { + throw new RuntimeException("Configuration file not found: " + configFile.getCanonicalPath()); + } + return (MavenProxyConfiguration)factory.build(new File("config.yml")); + } + catch (IOException | ConfigurationException ex) { + throw new RuntimeException(ex); + } + } + + static CloseableHttpClient getHttpClient() { + return HttpClients.createDefault(); + } + +} diff --git a/pom.xml b/pom.xml index 176f2be..83d5691 100644 --- a/pom.xml +++ b/pom.xml @@ -25,13 +25,13 @@ io.wcm.devops io.wcm.devops.parent_toplevel - 1.0.0 + 1.0.2 io.wcm.devops.maven io.wcm.devops.maven.nodejs-proxy.root - 1.0.0 + 1.1.0 pom Maven NodeJS Proxy Root