Skip to content

Commit

Permalink
Reduce test pollution with spec.name and requires in http-client tests (
Browse files Browse the repository at this point in the history
#10084)

* Reduce PoolTimeout flakiness

Try to reduce the flakiness by using Requires and AutoCleanup to try and reduce pollution that may be occuring

* Remove Shared from ClientIntroductionAdviceSpec as it needs a fresh server each test
  • Loading branch information
timyates authored Nov 8, 2023
1 parent 35f37d1 commit 1817df1
Show file tree
Hide file tree
Showing 41 changed files with 470 additions and 778 deletions.
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.http.client

import io.micronaut.context.ApplicationContext
Expand All @@ -24,10 +9,20 @@ import io.micronaut.http.annotation.Get
import io.micronaut.runtime.server.EmbeddedServer
import org.reactivestreams.Publisher
import reactor.core.publisher.Flux
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

class BasicAuthSpec extends Specification {

@Shared
@AutoCleanup
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, [
'spec.name': 'BasicAuthSpec'
])

HttpClient httpClient = server.applicationContext.createBean(HttpClient, new URL("http://sherlock:password@localhost:${server.port}"))

def "basicAuth() sets Authorization Header with Basic base64(username:password)"() {
when:
// tag::basicAuth[]
Expand All @@ -40,23 +35,11 @@ class BasicAuthSpec extends Specification {
}

void "test user in absolute URL"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, [
'spec.name': 'BasicAuthSpec'
])
ApplicationContext ctx = server.applicationContext
HttpClient httpClient = ctx.createBean(HttpClient, new URL("http://sherlock:password@localhost:${server.port}"))

when:
String resp = httpClient.toBlocking().retrieve("/basicauth")

then:
resp == "sherlock:password"

cleanup:
httpClient.close()
ctx.close()
server.close()
}

@Requires(property = 'spec.name', value = 'BasicAuthSpec')
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,54 +3,51 @@ package io.micronaut.http.client
import io.micronaut.context.ApplicationContext
import io.micronaut.http.client.exceptions.HttpClientException
import io.micronaut.http.netty.channel.EventLoopGroupRegistry
import io.netty.channel.EventLoopGroup
import spock.lang.AutoCleanup
import spock.lang.Shared
import spock.lang.Specification

import java.util.concurrent.ExecutionException

class BlockingDeadlockSpec extends Specification {
def 'blocking on the same event loop should fail: connection already established'() {
given:
def ctx = ApplicationContext.run([
'micronaut.netty.event-loops.default.num-threads': 1
])
def group = ctx.getBean(EventLoopGroupRegistry).getDefaultEventLoopGroup()
def client = ctx.createBean(HttpClient, 'https://micronaut.io').toBlocking()

@Shared
@AutoCleanup
ApplicationContext ctx = ApplicationContext.run([
'micronaut.netty.event-loops.default.num-threads': 1
])

@Shared
EventLoopGroup group = ctx.getBean(EventLoopGroupRegistry).getDefaultEventLoopGroup()

@Shared
@AutoCleanup
BlockingHttpClient client = ctx.createBean(HttpClient, 'https://micronaut.io').toBlocking()

def 'blocking on the same event loop should fail: connection already established'() {
when:
// establish pool connection
client.exchange('/')
group.submit(() -> {
client.exchange('/')
}).get()

then:
def e = thrown ExecutionException
e.cause instanceof HttpClientException
e.cause.message.contains("deadlock")

cleanup:
client.close()
group.shutdownGracefully()
}

def 'blocking on the same event loop should fail: new connection'() {
given:
def ctx = ApplicationContext.run([
'micronaut.netty.event-loops.default.num-threads': 1
])
def group = ctx.getBean(EventLoopGroupRegistry).getDefaultEventLoopGroup()
def client = ctx.createBean(HttpClient, 'https://micronaut.io').toBlocking()

when:
group.submit(() -> {
client.exchange('/')
}).get()

then:
def e = thrown ExecutionException
e.cause instanceof HttpClientException
e.cause.message.contains("deadlock")

cleanup:
client.close()
group.shutdownGracefully()
}
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,3 @@
/*
* Copyright 2017-2019 original authors
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.micronaut.http.client

import io.micronaut.context.ApplicationContext
Expand All @@ -27,151 +12,115 @@ import io.micronaut.http.annotation.*
import io.micronaut.http.client.annotation.Client
import io.micronaut.http.client.exceptions.HttpClientResponseException
import io.micronaut.runtime.server.EmbeddedServer
import spock.lang.AutoCleanup
import spock.lang.Specification

class ClientIntroductionAdviceSpec extends Specification {

@AutoCleanup
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, [
'spec.name': 'ClientIntroductionAdviceSpec',
])

void "test implement HTTP client"() {
given:
EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
MyClient myService = embeddedServer.applicationContext.getBean(MyClient)
MyClient myService = server.applicationContext.getBean(MyClient)

expect:
myService.index() == 'success'

cleanup:
embeddedServer.close()
}

void "service id appears in exceptions"() {
given:
EmbeddedServer embeddedServer = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
embeddedServer.applicationContext.registerSingleton(new TestServiceInstanceList(embeddedServer.getURI()))

PolicyClient myService = embeddedServer.applicationContext.getBean(PolicyClient)
server.applicationContext.registerSingleton(new TestServiceInstanceList(server.getURI()))
PolicyClient myService = server.applicationContext.getBean(PolicyClient)

when:
myService.failure()

then:
def e = thrown(HttpClientResponseException)
e.serviceId == 'test-service'
e.message == "Client 'test-service': Bad Request"

cleanup:
embeddedServer.close()
}

void "test multiple clients with the same id and different paths"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
server.applicationContext.registerSingleton(new TestServiceInstanceList(server.getURI()))

expect:
server.applicationContext.getBean(PolicyClient).index() == 'policy'
server.applicationContext.getBean(OfferClient).index() == 'offer'

cleanup:
server.close()
}

void "test a client with a body and header"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
server.applicationContext.registerSingleton(new TestServiceInstanceList(server.getURI()))

when:
OfferClient client = server.applicationContext.getBean(OfferClient)

then:
client.post('abc', 'bar') == 'abc header=bar'

cleanup:
server.close()
}

void "test a client that auto encodes basic auth header"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
server.applicationContext.registerSingleton(new TestServiceInstanceList(server.getURI()))

when:
ApplicationContext ctx = ApplicationContext.run(['spec.name': 'ClientIntroductionAdviceSpec', 'server-port': server.port])
BasicAuthHeaderAutoEncodingClient client = server.applicationContext.getBean(BasicAuthHeaderAutoEncodingClient)

then:
client.post('abc', new BasicAuth("username", "password")) == 'abc basic-auth-header=Basic dXNlcm5hbWU6cGFzc3dvcmQ='

cleanup:
server.close()
}

void "test non body params have preference for uri templates"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])

when:
LocalOfferClient client = server.applicationContext.getBean(LocalOfferClient)

then:
client.putTest("abc", new MyObject(code: "def")) == "abc"

cleanup:
server.close()
}

void "test basic auth"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
ApplicationContext ctx = ApplicationContext.run(['spec.name': 'ClientIntroductionAdviceSpec', 'server-port': server.port])

when:
ApplicationContext ctx = ApplicationContext.run(['spec.name': 'ClientIntroductionAdviceSpec', 'server-port': server.port])
BasicAuthClient client = ctx.getBean(BasicAuthClient)

then:
client.get() == 'config:secret'

cleanup:
ctx.close()
server.close()
}

void "test execution of a default method"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
DefaultMethodClient myService = server.applicationContext.getBean(DefaultMethodClient)

expect:
myService.defaultMethod() == 'success from default method mutated'

cleanup:
server.close()
}

void "test execution of a default method 2"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
DefaultMethodClient2 myService = server.applicationContext.getBean(DefaultMethodClient2)

expect:
myService.index("ZZZ") == 'success ZZZ XYZ from default method'
myService.defaultMethod() == 'success from default method mutated'
myService.defaultMethod2("ABC") == 'success ABC XYZ from default method 2 mutated'

cleanup:
server.close()
}

void "test execution of a default method 3"() {
given:
EmbeddedServer server = ApplicationContext.run(EmbeddedServer, ['spec.name': 'ClientIntroductionAdviceSpec'])
DefaultMethodClient3 myService = server.applicationContext.getBean(DefaultMethodClient3)

expect:
myService.index("ZZZ") == 'success ZZZ XYZ from default method'
myService.defaultMethod() == 'success from default method mutated'
myService.defaultMethod2("ABC") == 'success ABC XYZ from default method 2 mutated'

cleanup:
server.close()
}

@Requires(property = 'spec.name', value = 'ClientIntroductionAdviceSpec')
Expand Down
Loading

0 comments on commit 1817df1

Please sign in to comment.