cjstehno / ersatz

🤖 A simulated HTTP server for testing client code with configurable responses.
https://cjstehno.github.io/ersatz
Apache License 2.0
47 stars 5 forks source link

Compatibility with Groovy 4? #179

Closed radarsh closed 1 year ago

radarsh commented 1 year ago

Is there a version on the horizon that's compatible with Groovy 4? We are in the process of migrating to Spring Boot 3 and are transitively consuming Groovy 4 as a result. Our existing tests that make use of Ersatz are suddenly barfing due to missing org.codehaus.groovy package.

Any help here is appreciated. I can help contribute towards a PR as well.

I am using the safe version of Ersatz (currently 1.9.0 but will be migrating to 3.2.0 soon due to Spring Boot + Java 17 prerequisite). If there is anything that can be tweaked in the way the shadow JAR is constructed, I can explore that as well.

radarsh commented 1 year ago

I was able to build a version locally and successfully use Ersatz if I changed the below file:

Index: ersatz-groovy/build.gradle
IDEA additional info:
Subsystem: com.intellij.openapi.diff.impl.patch.CharsetEP
<+>UTF-8
===================================================================
diff --git a/ersatz-groovy/build.gradle b/ersatz-groovy/build.gradle
--- a/ersatz-groovy/build.gradle    (revision b28a089d99b1352d68e04ba1fb6ad8223247a0a6)
+++ b/ersatz-groovy/build.gradle    (date 1690548540928)
@@ -21,8 +21,8 @@

 dependencies {
     implementation project(':ersatz')
-    implementation "org.codehaus.groovy:groovy:$groovyVersion"
-    implementation "org.codehaus.groovy:groovy-json:$groovyVersion"
+    implementation "org.apache.groovy:groovy:$groovyVersion"
+    implementation "org.apache.groovy:groovy-json:$groovyVersion"

     testImplementation 'io.github.cjstehno:test-things:0.1.0'

@@ -90,6 +90,7 @@
         exclude(dependency('org.hamcrest::.*'))
         exclude(dependency('org.wildfly.client::.*'))
         exclude(dependency('org.codehaus.groovy::.*'))
+        exclude(dependency('org.apache.groovy::.*'))
     }

     mergeServiceFiles()
@@ -166,7 +167,7 @@
 }
cjstehno commented 1 year ago

Hmm. I don't really want to release a bug fix with a version and coordinate change in a major dependency, but you're pretty much the only known user at this point.

Let me take a look. I'd like to bring back the websocket support and I have a few other minor issues that I could add in as a full version release along with the groovy upgrade.

Did you have a chance to try out the new forwarding feature that replaces the old proxy? If not, please do as I'd like to remove the standalone proxy again since this will be the next major release. I could wait one more, but it will definitely go then so be sure to verify that the new feature works for you and create an issue if it doesn't.

Lastly, if there is anything else you think you'll need soon, please create issues as this may be the last release for this year.

radarsh commented 1 year ago

Thank you for still maintaining this project. I really wish more people got to hear about it. It's such an elegant way to perform HTTP mocking.

I will try the request forwarding feature right now and feedback to you.

radarsh commented 1 year ago

I can confirm that the request forwarding works nicely instead of proxy server. This is what I did in my test:

    def "can set proxy using URL convenience"() {
        given:
            server.expectations {
                GET('/api/hello') {
                    called 1
                    responder {
                        code 200
                        body 'World'
                    }
                }
            }
            def proxyServer = new GroovyErsatzServer({
                decoder 'application/json', JSON_DECODER
                encoder 'application/json', LinkedHashMap, JSON_ENCODER
                encoder 'application/vnd.custom+json', LinkedHashMap, JSON_ENCODER
            })
            proxyServer.expectations {
                GET('/api/hello') {
                    called 1
                    forward server.httpUrl
                }
            }
        and:
            restService = RestService.builder()
                    .url(server.httpUrl)
                    .proxyProperties(ProxyProperties.builder()
                            .url(proxyServer.httpUrl)
                            .build())
                    .build()
        when:
            def response = restService.get("/api/hello").execute(String)
        then:
            response.status == HttpStatus.OK
            response.body() == 'World'
            server.verify()
            proxyServer.verify()
        cleanup:
            proxyServer.stop()
    }

Here RestService is our abstraction for making HTTP requests. The test is proving that the request is correctly being forwarded to the target server and the proxy configuration is working.

radarsh commented 1 year ago

Lastly, if there is anything else you think you'll need soon, please create issues as this may be the last release for this year.

In that case, can you give me till mid next week? I will migrate all our existing tests to my patched version based on 3.2.0 (which uses Groovy 4) and hopefully be able to identify any issues.

cjstehno commented 1 year ago

Good to hear it works for you. Also, it will take me a couple weeks to get things done so go ahead - I'll give you a notice before I am ready to cut the release.

cjstehno commented 1 year ago

It's nothing I have noticed before, sorry.

On Mon, Jul 31, 2023 at 6:07 PM Adarsh Ramamurthy @.***> wrote:

There is something strange I am noticing with one test. I don't yet have exact steps to reproduce it but I seem to be getting duplicate requests being made by Ersatz and thus, the called verification is failing. The duplicate requests look something like this (The only difference is the Accept-Encoding header which is not there in my expectation).

17:49:26.521 [XNIO-1 task-2] DEBUG i.g.c.e.s.u.ErsatzMatchingHandler - Handling request(HTTP/1.1): { POST /v0/events(query={}, headers={Accept=[application/json, application/+json], Connection=[keep-alive], Accept-Encoding=[gzip, x-gzip, deflate], Content-Type=[application/vnd.custom+json], Content-Length=[595], User-Agent=[Apache-HttpClient/5.2.1 (Java/17.0.7)], Host=[localhost:65357]}, cookies={}): <595 of application/vnd.custom+json content> } 17:49:27.579 [XNIO-1 task-2] DEBUG i.g.c.e.s.u.ErsatzMatchingHandler - Handling request(HTTP/1.1): { POST /v0/events(query={}, headers={Accept=[application/json, application/+json], Connection=[keep-alive], Content-Type=[application/vnd.custom+json], Content-Length=[595], User-Agent=[Apache-HttpClient/5.2.1 (Java/17.0.7)], Host=[localhost:65357]}, cookies={}): <595 of application/vnd.custom+json content> }

This could be a red herring but if you have seen this behaviour already, any insight would be handy.

— Reply to this email directly, view it on GitHub https://github.com/cjstehno/ersatz/issues/179#issuecomment-1659313752, or unsubscribe https://github.com/notifications/unsubscribe-auth/AABMYKS3ASIHBHA7USTPSA3XTA3CJANCNFSM6AAAAAA22HY3HM . You are receiving this because you were assigned.Message ID: @.***>

--

Christopher J. Stehno @.*** https://cjstehno.github.io

radarsh commented 1 year ago

I found out that the culprit was default retry strategy in Apache HTTP client 5. Ersatz is fine here.

cjstehno commented 1 year ago

My working/4.0 branch has the changes you've requested, along with the removal of the standalone proxy server and re-built websocket support. I have one more feature I will be adding so you still have another week or so, but feel free to pull the branch and test it.

radarsh commented 1 year ago

Thanks, I'll check it out today.

radarsh commented 1 year ago

Looking good so far.

cjstehno commented 1 year ago

The working/4.0 branch is basically ready to go - I will clean things up and cut the release on or before next weekend.

cjstehno commented 1 year ago

This is merged into master and will be in the 4.0 release, probably Monday.

cjstehno commented 1 year ago

@radarsh I have released v4.0.0 this morning - it might take some time to propagate into the repository.

radarsh commented 1 year ago

Thank you @cjstehno, perfect timing.