spring-cloud / spring-cloud-contract

Support for Consumer Driven Contracts in Spring
https://cloud.spring.io/spring-cloud-contract
Apache License 2.0
719 stars 438 forks source link

Generating Pact.io pacts from SCC groovy contracts via exec-maven-plugin throws exception #1277

Closed 0248991 closed 4 years ago

0248991 commented 4 years ago

Describe the bug Generating Pact.io pacts from SCC groovy contracts via exec-maven-plugin throws java.lang.IllegalStateException: java.lang.UnsupportedOperationException: use the array(String name) form Previously discussed on stackoverflow here

Sample I generate groovy contract via SCC like this: Before each method to set mockmvc:

@BeforeEach
void setUp(WebApplicationContext context,
           RestDocumentationContextProvider restDocumentation) {
    MockMvcRestDocumentationConfigurer configurer = documentationConfiguration(restDocumentation);
    configurer.operationPreprocessors()
            .withRequestDefaults(prettyPrint())
            .withResponseDefaults(prettyPrint());
    configurer.snippets()
            .withDefaults(
                    httpRequest(),
                    httpResponse()
            );
    this.mockMvc = MockMvcBuilders.webAppContextSetup(context)
            .apply(configurer)
            .build();

Test method:

@Test
void createAdminHttpRequest() throws Exception {
    var adminDTO = HandlerTestObjectGenerator.createFixedAdminDTO();

    mockMvc.perform(
            RestDocumentationRequestBuilders
                    .post("/api/admins")
                    .content(objectMapper.writeValueAsString(adminDTO))
                    .contentType(MediaType.APPLICATION_JSON_UTF8)
    ).andExpect(status().isCreated())
            .andDo(document("create-admin",
                    preprocessRequest(),
                    preprocessResponse(),
                    requestFields(
                            usernameFieldDescriptor,
                            passwordFieldDescriptor,
                            rolesFieldDescriptor
                    ),
                    responseFields(
                            admin_adminIdFieldDescriptor,
                            admin_usernameFieldDescriptor,
                            admin_rolesFieldDescriptor
                    ),
                    SpringCloudContractRestDocs.dslContract(),
            ));
}

Groovy contract is successfully generated and is like this:

import org.springframework.cloud.contract.spec.Contract

Contract.make {
    request {
        method 'PUT'
        url '/api/admins/1'
        body('''{
  "username" : "username",
  "password" : "password",
  "roles" : [ "ADMIN" ]
}''')
        headers {
            header('''Content-Type''', '''application/json;charset=UTF-8''')
        }
    }
    response {
        status 200
        body('''{
  "admin" : {
    "adminId" : 1,
    "username" : "username",
    "roles" : [ "ADMIN" ]
  }
}''')
        headers {
            header('''Content-Type''', '''application/json;charset=UTF-8''')
        }
    }
}

Using exec-maven-plugin like this:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>exec-maven-plugin</artifactId>
    <version>1.6.0</version>
    <executions>
        <execution>
            <id>convert-dsl-to-pact</id>
            <phase>deploy</phase>
            <configuration>
                <mainClass>
                    org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer
                </mainClass>
                <arguments>
                    <argument>
                        org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter
                    </argument>
                    <argument>${project.build.directory}/pacts</argument>
                    <argument>${project.build.directory}/generated-snippets/contracts</argument>
                </arguments>
            </configuration>
            <goals>
                <goal>java</goal>
            </goals>
        </execution>
    </executions>
</plugin>

with dependencies explicitly stated to latest version:

<dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-starter-contract-stub-runner</artifactId>
            <version>2.2.0.RELEASE</version>
            <scope>test</scope>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-pact</artifactId>
            <version>2.2.1.BUILD-SNAPSHOT</version>
        </dependency>
        <dependency>
            <groupId>org.springframework.cloud</groupId>
            <artifactId>spring-cloud-contract-verifier</artifactId>
            <version>2.2.1.BUILD-SNAPSHOT</version>
        </dependency>

throws this exception:

[INFO] 
[INFO] --- exec-maven-plugin:1.6.0:java (convert-dsl-to-pact) @ admin-management-service ---
17:06:34.877 [org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main()] WARN org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer - You're using an incubating feature. Note, that it can be changed / removed in the future
17:06:34.994 [org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main()] INFO org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer - Input path [/home/milkam/Desktop/admin-management-service/target/generated-snippets/contracts]
17:06:34.994 [org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main()] INFO org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer - FQN of the converter [org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter]
17:06:34.994 [org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main()] INFO org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer - Output path [/home/milkam/Desktop/admin-management-service/target/pacts]
17:06:35.635 [org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main()] INFO org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer - Found [6] contract definition
[WARNING] 
java.lang.IllegalStateException: java.lang.UnsupportedOperationException: use the array(String name) form
    at org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.storeContractsAsFiles (ToFileContractsTransformer.groovy:103)
    at org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main (ToFileContractsTransformer.groovy:55)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:834)
Caused by: java.lang.UnsupportedOperationException: use the array(String name) form
    at au.com.dius.pact.consumer.dsl.PactDslJsonBody.array (PactDslJsonBody.java:673)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter.traverse (BodyConverter.groovy:94)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter.access$0 (BodyConverter.groovy)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter$_processMap_closure2.doCall (BodyConverter.groovy:151)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.groovy.reflection.CachedMethod.invoke (CachedMethod.java:101)
    at groovy.lang.MetaMethod.doMethodInvoke (MetaMethod.java:323)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod (ClosureMetaClass.java:263)
    at groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:1041)
    at groovy.lang.Closure.call (Closure.java:405)
    at org.codehaus.groovy.runtime.ConvertedClosure.invokeCustom (ConvertedClosure.java:50)
    at org.codehaus.groovy.runtime.ConversionHandler.invoke (ConversionHandler.java:122)
    at com.sun.proxy.$Proxy73.accept (Unknown Source)
    at java.util.Map.forEach (Map.java:661)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter.processMap (BodyConverter.groovy:133)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter.traverse (BodyConverter.groovy:87)
    at org.springframework.cloud.contract.verifier.spec.pact.BodyConverter.toPactBody (BodyConverter.groovy:56)
    at org.springframework.cloud.contract.verifier.spec.pact.RequestResponsePactCreator.createPactDslRequestWithPath (RequestResponsePactCreator.groovy:150)
    at org.springframework.cloud.contract.verifier.spec.pact.RequestResponsePactCreator.access$0 (RequestResponsePactCreator.groovy)
    at org.springframework.cloud.contract.verifier.spec.pact.RequestResponsePactCreator$_createFromContract_closure1.doCall (RequestResponsePactCreator.groovy:63)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.groovy.reflection.CachedMethod.invoke (CachedMethod.java:101)
    at groovy.lang.MetaMethod.doMethodInvoke (MetaMethod.java:323)
    at org.codehaus.groovy.runtime.metaclass.ClosureMetaClass.invokeMethod (ClosureMetaClass.java:263)
    at groovy.lang.MetaClassImpl.invokeMethod (MetaClassImpl.java:1041)
    at groovy.lang.Closure.call (Closure.java:405)
    at groovy.lang.Closure.call (Closure.java:421)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each (DefaultGroovyMethods.java:2330)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each (DefaultGroovyMethods.java:2315)
    at org.codehaus.groovy.runtime.DefaultGroovyMethods.each (DefaultGroovyMethods.java:2356)
    at org.springframework.cloud.contract.verifier.spec.pact.RequestResponsePactCreator.createFromContract (RequestResponsePactCreator.groovy:59)
    at org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter.convertTo (PactContractConverter.groovy:77)
    at org.springframework.cloud.contract.verifier.spec.pact.PactContractConverter.convertTo (PactContractConverter.groovy)
    at org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.storeContractsAsFiles (ToFileContractsTransformer.groovy:80)
    at org.springframework.cloud.contract.verifier.util.ToFileContractsTransformer.main (ToFileContractsTransformer.groovy:55)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke0 (Native Method)
    at jdk.internal.reflect.NativeMethodAccessorImpl.invoke (NativeMethodAccessorImpl.java:62)
    at jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke (DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke (Method.java:566)
    at org.codehaus.mojo.exec.ExecJavaMojo$1.run (ExecJavaMojo.java:282)
    at java.lang.Thread.run (Thread.java:834)
dagmarakruk commented 4 years ago

This bug is regression? Is any working version with this converter?

marcingrzejszczak commented 4 years ago

You'd have to downgrade Pact version to make this work or wait for the Hoxton.SR2 release (https://github.com/spring-cloud/spring-cloud-contract/pull/1323)