diff --git a/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrl.java b/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrl.java new file mode 100644 index 0000000000..6cc561fb42 --- /dev/null +++ b/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrl.java @@ -0,0 +1,35 @@ +package au.com.dius.pact.provider.junit.loader; + +import au.com.dius.pact.provider.junit.PactRunner; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +/** + * Used to point {@link PactRunner} to a versioned source of pacts for contract tests. + *

+ * Use ${any.variable} in the url and specify any.variable as a system property. + *

+ *

+ * For example, when you annotate a provider test class with: + *

{@literal @}VersionedPactUrl(urls = {"http://artifactory:8081/artifactory/consumercontracts/foo-bar/${foo.version}/foo-bar-${foo.version}.json"})
+ * And pass a system property foo.version to the JVM, for example -Dfoo.version=123 + *

+ *

+ * Then the pact tests will fetch the following contract: + *

http://artifactory:8081/artifactory/consumercontracts/foo-bar/123/foo-bar-123.json
+ *

+ * + * @see VersionedPactUrlLoader pact loader + */ +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.TYPE) +@PactSource(VersionedPactUrlLoader.class) +public @interface VersionedPactUrl { + /** + * @return a list of urls to pact files + */ + String[] urls(); +} diff --git a/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoader.java b/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoader.java new file mode 100644 index 0000000000..75ff9063fe --- /dev/null +++ b/pact-jvm-provider-junit/src/main/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoader.java @@ -0,0 +1,54 @@ +package au.com.dius.pact.provider.junit.loader; + +import au.com.dius.pact.model.Pact; +import com.google.common.annotations.VisibleForTesting; + +import java.io.IOException; +import java.util.List; +import java.util.Map; +import java.util.stream.Collectors; + +import static java.lang.String.format; +import static java.util.Arrays.stream; + +/** + * Implementation of {@link PactLoader} that downloads pacts from given urls containing versions to be filtered in from system properties. + * + * @see VersionedPactUrl usage instructions + */ +public class VersionedPactUrlLoader implements PactLoader { + private final String[] urls; + + public VersionedPactUrlLoader(String[] urls) { + this.urls = urls; + } + + @SuppressWarnings("unused") + public VersionedPactUrlLoader(VersionedPactUrl pactUrl) { + this(pactUrl.urls()); + } + + @Override + public List load(String providerName) throws IOException { + return new PactUrlLoader(expandVariables(urls)).load(providerName); + } + + @VisibleForTesting + static String[] expandVariables(String[] urls) throws IOException { + return stream(urls) + .map(VersionedPactUrlLoader::expandVariables) + .collect(Collectors.toList()) + .toArray(new String[urls.length]); + } + + private static String expandVariables(String urlWithVariables) { + String urlWithVersions = urlWithVariables; + for (Map.Entry property : System.getProperties().entrySet()) { + urlWithVersions = urlWithVersions.replace(format("${%s}", property.getKey()), property.getValue().toString()); + } + if (urlWithVersions.matches(".*\\$\\{[a-z\\.]+\\}.*")) { + throw new IllegalArgumentException(urlWithVersions + " contains variables that could not be any of the system properties. Define a system property to replace them or remove the variables from the URL."); + } + return urlWithVersions; + } +} diff --git a/pact-jvm-provider-junit/src/test/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoaderTest.java b/pact-jvm-provider-junit/src/test/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoaderTest.java new file mode 100644 index 0000000000..811098cd3d --- /dev/null +++ b/pact-jvm-provider-junit/src/test/java/au/com/dius/pact/provider/junit/loader/VersionedPactUrlLoaderTest.java @@ -0,0 +1,48 @@ +package au.com.dius.pact.provider.junit.loader; + +import org.junit.Test; + +import static java.lang.String.format; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.fail; + +public class VersionedPactUrlLoaderTest { + @Test + public void replacesVersion() throws Exception { + String versionVariable = "jupiter.version"; + System.setProperty(versionVariable, "555"); + + String[] strings = VersionedPactUrlLoader + .expandVariables(new String[]{format("http://artifactory:8081/jupiter-hydra/${%1$s}/jupiter-hydra-${%1$s}.json", versionVariable)}); + + assertEquals("http://artifactory:8081/jupiter-hydra/555/jupiter-hydra-555.json", strings[0]); + assertEquals(1, strings.length); + } + + @Test + public void replacesVersions() throws Exception { + String versionVariable1 = "jupiter.version"; + String versionVariable2 = "saturn.version"; + System.setProperty(versionVariable1, "555"); + System.setProperty(versionVariable2, "666"); + + String[] strings = VersionedPactUrlLoader + .expandVariables(new String[]{format("http://artifactory:8081/jupiter-hydra/${%s}/jupiter-hydra-${%s}.json", versionVariable1, versionVariable2)}); + + assertEquals("http://artifactory:8081/jupiter-hydra/555/jupiter-hydra-666.json", strings[0]); + assertEquals(1, strings.length); + } + + @Test + public void failsWhenNoVersionSpecified() throws Exception { + String versionVariable = "jupiter.version"; + System.clearProperty(versionVariable); + + try { + VersionedPactUrlLoader.expandVariables(new String[]{format("http://artifactory:8081/jupiter-hydra/${%s}/jupiter-hydra-${%s}.json", versionVariable, versionVariable)}); + fail(); + } catch (Exception e) { + assertEquals("http://artifactory:8081/jupiter-hydra/${jupiter.version}/jupiter-hydra-${jupiter.version}.json contains variables that could not be any of the system properties. Define a system property to replace them or remove the variables from the URL.", e.getMessage()); + } + } +} \ No newline at end of file