Spring Cloud Contract issues retrieving stubs from

2019-05-12 01:08发布

问题:

I have tests for two consumers and a producer working fine offline but the consumer tests fail when I change them for retrieving the stubs from Artifactory.

This is the code for working offline:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ContractTestConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.mycompany:service-name:+:stubs"}, workOffline = true)
@ImportAutoConfiguration(org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration.class)
@DirtiesContext
public class MyContractTest

And this is for online:

@RunWith(SpringRunner.class)
@SpringBootTest(classes = ContractTestConfiguration.class, webEnvironment = SpringBootTest.WebEnvironment.NONE)
@AutoConfigureStubRunner(ids = {"com.mycompany:service-name:+:stubs"}, repositoryRoot = "https://artifactory.companyname.com/artifactory/artifacts-snapshot-local")
@ImportAutoConfiguration(org.springframework.cloud.stream.test.binder.TestSupportBinderAutoConfiguration.class)
@DirtiesContext
public class MyContractTest {

I get this error:

Exception occurred while trying to download a stub for group [com.mycompany] module [service-name] and classifier [stubs] in [remote0 (https://artifactory.mycompany.com/artifactory/artifacts-snapshot-local, default, releases+snapshots)]
org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact com.mycompany.domain:service-name:jar:stubs:1.6.0-SNAPSHOT

I have looked in Artifactory and in https://artifactory.mycompany.com/artifactory/artifacts-snapshot-local and the stubs jar appears there. I have done a mvn install of the producer and when I run the tests again I get this error "The artifact was found in the local repository but you have explicitly stated that it should be downloaded from a remote one".

I have also tried adding to the consumers a dependency on the stubs of the producer but I get similar errors. And I would prefer to avoid it because it would add a dependency with the specific version of the producer:

<dependency>
    <groupId>com.companyname</groupId>
    <artifactId>service-name</artifactId>
    <classifier>stubs</classifier>
    <version>1.6.0-SNAPSHOT</version>
    <scope>test</scope>
    <exclusions>
        <exclusion>
            <groupId>*</groupId>
            <artifactId>*</artifactId>
        </exclusion>
    </exclusions>
</dependency>

I have added this to the POM file of the producer:

<spring.cloud.contract.verifier.skip>true</spring.cloud.contract.verifier.skip>

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-assembly-plugin</artifactId>
    <executions>
        <execution>
            <id>stub</id>
            <goals>
                <goal>single</goal>
            </goals>
            <phase>prepare-package</phase>
            <inherited>false</inherited>
            <configuration>
                <attach>true</attach>
                <descriptor>${basedir}/src/assembly/stub.xml</descriptor>
            </configuration>
        </execution>
    </executions>
</plugin>

And this is the content of the file stub.xml that is under src/assembly:

<assembly
        xmlns="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3"
        xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
        xsi:schemaLocation="http://maven.apache.org/plugins/maven-assembly-plugin/assembly/1.1.3 http://maven.apache.org/xsd/assembly-1.1.3.xsd">
    <id>stubs</id>
    <formats>
        <format>jar</format>
    </formats>
    <includeBaseDirectory>false</includeBaseDirectory>
    <fileSets>
        <fileSet>
            <directory>src/main/java</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>**com/companyname/projectname/*.*</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/classes</directory>
            <outputDirectory>/</outputDirectory>
            <includes>
                <include>**com/companyname/projectname/*.*</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${project.build.directory}/snippets/stubs</directory>
            <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/mappings</outputDirectory>
            <includes>
                <include>**/*</include>
            </includes>
        </fileSet>
        <fileSet>
            <directory>${basedir}/src/test/resources/contracts</directory>
            <outputDirectory>META-INF/${project.groupId}/${project.artifactId}/${project.version}/contracts</outputDirectory>
            <includes>
                <include>**/*.groovy</include>
            </includes>
        </fileSet>
    </fileSets>
</assembly>

Any idea of what I am missing? Thanks in advance

回答1:

I have looked in Artifactory and in https://artifactory.mycompany.com/artifactory/artifacts-snapshot-local and the stubs jar appears there. I have done a mvn install of the producer and when I run the tests again I get this error "The artifact was found in the local repository but you have explicitly stated that it should be downloaded from a remote one".

This happens when you install a stub locally, then try to download it from artifactory but SHAs are different, so Aether (engine that downloads stubs) picks the local one. In this case we throw an exception cause you wanted to download the stub from a remote location and not take it from the local one.

Exception occurred while trying to download a stub for group [com.mycompany] module [service-name] and classifier [stubs] in [remote0 (https://artifactory.mycompany.com/artifactory/artifacts-snapshot-local, default, releases+snapshots)] org.eclipse.aether.resolution.ArtifactResolutionException: Could not find artifact com.mycompany.domain:service-name:jar:stubs:1.6.0-SNAPSHOT

This looks like in Artifactory you had the entry in some Maven metadata that the latest jar is 1.6.0-SNAPSHOT but the JAR is no longer there. Can you double check that it's actually there?

I have also tried adding to the consumers a dependency on the stubs of the producer but I get similar errors. And I would prefer to avoid it because it would add a dependency with the specific version of the producer:

That only proves that you have something messed up with your artifactory / project settings. Do things still don't work if you hardcode versions?

UPDATE:

If your artifactory instance requires credentials or is behind a proxy you can use these values:

https://github.com/spring-cloud/spring-cloud-contract/blob/v1.1.4.RELEASE/spring-cloud-contract-stub-runner/src/main/java/org/springframework/cloud/contract/stubrunner/spring/StubRunnerProperties.java#L72-L87

You can provide the stubrunner.username, stubrunner.password, stubrunner.proxyHost and stubrunner.proxyPort



回答2:

Can stubrunner.username and stubrunner.password be provided in the @AutoConfigureStubRunner annotation? I have tried the following:

 @RunWith(SpringRunner.class)
 @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.NONE)
 @AutoConfigureStubRunner(ids = "com.mycompany.myproj:myservice:+:stubs:8100",
    repositoryRoot = "http://artifactory.mycompany.com/artifactory/libs-snapshot-local",
    properties = {"stubrunner.username=myusername", "stubrunner.password=mypassword"},
    stubsMode = StubRunnerProperties.StubsMode.REMOTE)
 @DirtiesContext
 class MyApiContractsVerificationTest {
     ...
 }

The credentials are correct, and the stubs are correctly generated and deployed into the remote Artifactory repository. The tests run fine if I configure them to look in the local .m2/repository (removing the "repositoryRoot and "properties" annotation args), but with the above configuration I get the following error:

Could not find metadata com.mycommany.myproject:myservice/maven-metadata.xml in local (/Users/myname/.m2/repository), 
org.eclipse.aether.transfer.MetadataTransferException: Could not transfer metadata com.mycommany.myproject:myservice/maven-metadata.xml from/to remote0 (http://artifactory.mycompany.com/artifactory/libs-snapshot-local): **Unauthorized (401)**]
...

I do clean the local .m2/repository of the stubs before I run the tests with the remote mode enabled, so there is no conflict.

Am I incorrectly providing the username and password? Is something incorrect or missing in the configuration?