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

unstable build caused by UT005071 #82

Closed musketyr closed 6 years ago

musketyr commented 6 years ago

I have a test using Ersatz which is working great when executed in isolation but on the CI or within test suite it fails with following. Any suggestion what can go wrong - using 1.5.0:safe@jar

15:04:34.261 [Test worker] INFO  ersatz.xnio - XNIO version 3.3.8.Final
15:04:34.301 [Test worker] INFO  com.jcabi.manifests.Manifests - 53 attributes loaded from 56 stream(s) in 16ms, 53 saved, 739 ignored: ["Ant-Version", "Archiver-Version", "Bnd-LastModified", "Build-Jdk", "Built-By", "Built-Date", "Bundle-ClassPath", "Bundle-Description", "Bundle-DocURL", "Bundle-License", "Bundle-ManifestVersion", "Bundle-Name", "Bundle-RequiredExecutionEnvironment", "Bundle-SymbolicName", "Bundle-Vendor", "Bundle-Version", "Created-By", "DynamicImport-Package", "Eclipse-BuddyPolicy", "Embed-Dependency", "Export-Package", "Extension-Name", "Implementation-Build-Date", "Implementation-Title", "Implementation-URL", "Implementation-Vendor", "Implementation-Vendor-Id", "Implementation-Version", "Import-Package", "JCabi-Build", "JCabi-Date", "JCabi-Version", "Main-Class", "Main-class", "Manifest-Version", "Maven-Artifact-Id", "Maven-Group-Id", "Maven-Version", "Originally-Created-By", "Package", "Private-Package", "Provide-Capability", "Require-Capability", "Specification-Title", "Specification-Vendor", "Specification-Version", "Time-Zone-Database-Version", "Tool", "X-Compile-Source-JDK", "X-Compile-Target-JDK", "X-Git-Hash", "build-time", "provider"]
15:04:34.308 [Test worker] WARN  io.sentry.dsn.Dsn - *** Couldn't find a suitable DSN, Sentry operations will do nothing! See documentation: https://docs.sentry.io/clients/java/ ***
15:04:34.313 [Test worker] INFO  io.sentry.DefaultSentryClientFactory - Using noop to send events.
15:04:34.401 [Test worker] INFO  ersatz.xnio.nio - XNIO NIO Implementation Version 3.3.8.Final
15:04:35.329 [XNIO-1 task-1] ERROR ersatz.undertow.request - UT005071: Undertow request failed HttpServerExchange{ GET /api/me/accounts/summary request {Authorization=[Bearer TeddyTheBear], User-Agent=[Vert.x-WebClient/3.5.0], Host=[localhost:52998]} response {}}
java.lang.NullPointerException: null
    at ersatz.undertow.io.BlockingSenderImpl.send(BlockingSenderImpl.java:94)
    at ersatz.undertow.io.BlockingSenderImpl.send(BlockingSenderImpl.java:117)
    at com.stehno.ersatz.ErsatzServer.send(ErsatzServer.groovy:494)
    at com.stehno.ersatz.ErsatzServer.access$0(ErsatzServer.groovy)
    at com.stehno.ersatz.ErsatzServer$1.handleRequest(ErsatzServer.groovy:370)
    at ersatz.undertow.server.handlers.HttpTraceHandler.handleRequest(HttpTraceHandler.java:70)
    at ersatz.undertow.server.handlers.encoding.EncodingHandler.handleRequest(EncodingHandler.java:66)
    at ersatz.undertow.server.Connectors.executeRootHandler(Connectors.java:332)
    at ersatz.undertow.server.HttpServerExchange$1.run(HttpServerExchange.java:812)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:744)
cjstehno commented 6 years ago

What CI are you using? They each have their own odd twichyness :-)

Can you provide a test case to demonstrate the problem? Even if it works by itself and fails in CI, I might be able to see what may be happening.

https://issues.jboss.org/browse/UNDERTOW-950 - just a quick search but this seems to suggest that it may be a client-terminated request. Not sure why this would happen in CI but not local though.

I should be able to give this some time next week.

musketyr commented 6 years ago

The problem is that it is bit indeterministic. It does not fail all the time but it only fails when executed as a Gradle build (but again, not always)

Dne st 20. 12. 2017 15:40 uživatel Christopher J. Stehno < notifications@github.com> napsal:

What CI are you using? They each have their own odd twichyness :-)

Can you provide a test case to demonstrate the problem? Even if it works by itself and fails in CI, I might be able to see what may be happening.

https://issues.jboss.org/browse/UNDERTOW-950 - just a quick search but this seems to suggest that it may be a client-terminated request. Not sure why this would happen in CI but not local though.

I should be able to give this some time next week.

— You are receiving this because you authored the thread. Reply to this email directly, view it on GitHub https://github.com/cjstehno/ersatz/issues/82#issuecomment-353080080, or mute the thread https://github.com/notifications/unsubscribe-auth/AAoTtWgxShMtww__7iPfYdQtZw8ncImKks5tCRxQgaJpZM4RIctN .

cjstehno commented 6 years ago

I get that, but it would be helpful to see the code or type of code that is failing (when it does). Possibly some sort of race condition.

musketyr commented 6 years ago
    @Rule ErsatzServerRule ersatz = new ErsatzServerRule()

    def "check is authorized"() {
        given:
            ersatz.expectations {
                get('/api/me/accounts/summary'){
                    header('Authorization', 'Bearer TeddyTheBear')
                    responder {
                        content AuthServiceSpec.getResourceAsStream('accounts.json').text, ContentType.APPLICATION_JSON
                    }
                }

                get('/api/me/accounts/summary'){
                    header('Authorization', 'Bearer CatWithHat')
                    responder {
                        code 401
                    }
                }
            }.start()

        when:
            Vertx vertx = Vertx.vertx()
            AuthService service = new AuthService(ersatz.httpUrl, vertx)
            BlockingVariable<Boolean> teddyTwitterAuthorized = new BlockingVariable<Boolean>(20, TimeUnit.SECONDS)
            BlockingVariable<Boolean> catTwitterAuthorized = new BlockingVariable<Boolean>(20, TimeUnit.SECONDS)
            BlockingVariable<Boolean> teddyFacebookAuthorized = new BlockingVariable<Boolean>(20, TimeUnit.SECONDS)
        and:
            service.isAuthorized('twitter_50', ImmutableMap.of('Authorization', 'Bearer TeddyTheBear')) {
                teddyTwitterAuthorized.set(it)
            }

            service.isAuthorized('twitter_50', ImmutableMap.of('Authorization', 'Bearer CatWithHat')) {
                catTwitterAuthorized.set(it)
            }

            service.isAuthorized('facebook_51', ImmutableMap.of('Authorization', 'Bearer TeddyTheBear')) {
                teddyFacebookAuthorized.set(it)
            }
        then:
            teddyTwitterAuthorized.get()
            !catTwitterAuthorized.get()
            !teddyFacebookAuthorized.get()

AuthService is using Vert.x WebClient to fetch the data from the server (ersatz server for the spec)

musketyr commented 6 years ago

more or less

     WebClient.create(vertx).getAbs("$managerUrl$ACCOUNTS_ENDPOINT")
              .as(BodyCodec.jsonObject())
              .putHeader('Authorization', authHeader)
              .send {
            ar ->
                if (ar.succeeded()) {
                    JsonObject body = ar.result().body();

                    if (!body || !body.getJsonArray('accounts')) {
                        callback false
                        return
                    }

                    callback createAccounts(body).canAccessAccount(accountUid)
                } else {
                    log.error("Problems connecting to $managerUrl$ACCOUNTS_ENDPOINT", ar.cause())
                    callback false
                }
        }
cjstehno commented 6 years ago

Is this issue still valid?

musketyr commented 6 years ago

I don't know really. when I track the progress after rising this issue I've just added a @RetryOnFailure to these tests. feel free to close it for the moment.

cjstehno commented 6 years ago

Ok. Feel free to re-open if you feel the need.