florin
florin

Reputation: 807

Spring testcontainer test hangs when trying to simulate no connection to Mongodb

I'm trying to simulate that the Mongo database is down when the query is run. I'm using testcontainers with Toxiproxy and Mongo.

In the below test class, test called withLatency work as expected but test withoutConnection is hanging.

Code:

@SpringBootApplication
public class ToxiproxyIssueApplication {
    public static void main(String[] args) {
        SpringApplication.run(ToxiproxyIssueApplication.class, args);
    }
}

@Document
public record Person(String name, int age) {
}

@Repository
public interface PersonRepository extends MongoRepository<Person, String> {
}

The properties file contains:

spring.data.mongodb.host=localhost
spring.data.mongodb.port=27017

The test:

@Testcontainers
@SpringBootTest(properties = {"spring.main.allow-bean-definition-overriding=true"})
class ToxiproxyIssueApplicationTests {

    @Autowired
    private PersonRepository personRepository;

    private static final Network network = Network.newNetwork();

    private static final DockerImageName dockerImageName = DockerImageName.parse("mongo:5.0.5").asCompatibleSubstituteFor("mongo");

    @Container
    static final MongoDBContainer mongoDbContainer = new MongoDBContainer(dockerImageName)
            .withNetwork(network)
            .withNetworkAliases("mongo");
//          .withReuse(true);

    @Container
    private static final ToxiproxyContainer toxiproxy = new ToxiproxyContainer("ghcr.io/shopify/toxiproxy:2.6.0")
            .withNetwork(network);

    private static Proxy mongoProxy;

    @DynamicPropertySource
    static void mongoProperties(DynamicPropertyRegistry registry) throws IOException {
        ToxiproxyClient toxiproxyClient = new ToxiproxyClient(toxiproxy.getHost(), toxiproxy.getControlPort());
        mongoProxy = toxiproxyClient.createProxy("mongodb", "0.0.0.0:8666", "mongo:27017");

        int port = mongoDbContainer.getMappedPort(27017);
        registry.add("spring.data.mongodb.host", toxiproxy::getHost);
        registry.add("spring.data.mongodb.port", () -> toxiproxy.getMappedPort(8666));
    }


    @Test
    void withLatency() throws IOException {
        mongoProxy.toxics().latency("mongo-latency", ToxicDirection.DOWNSTREAM, 2600).setJitter(100);
        var result = personRepository.findAll();
        assertThat(result).isEmpty();
    }

    @Test
    void withoutConnection() throws IOException {
        mongoProxy.toxics().bandwidth("no-connection-downstream", ToxicDirection.DOWNSTREAM, 0);
        mongoProxy.toxics().bandwidth("no-connection-upstream", ToxicDirection.UPSTREAM, 0);
        var result = personRepository.findAll();
        assertThat(result).isEmpty();

        mongoProxy.toxics().get("no-connection-downstream").remove();
        mongoProxy.toxics().get("no-connection-upstream").remove();
    }
}

When the test is hanging I see in the logs a timeout from the driver:

com.mongodb.MongoSocketReadTimeoutException: Timeout while receiving message

Is there something wrong in my config or is this a testcontainer bug?

P.S the code posted should be enough to reproduce the issue.

Later edit

Based on the discussion from here there is no bug. The client library is the one who provides the behavior. So further research will be conducted on this side.

Upvotes: 0

Views: 471

Answers (1)

florin
florin

Reputation: 807

Based on the Toxiproxy documentation, there is the down toxic (https://github.com/Shopify/toxiproxy#down): by disabling the proxy no traffic will be routed.

In java Toxiproxy client library there are some methods to enable and disable the proxy: https://github.com/trekawek/toxiproxy-java/blob/7c5ffc5d7aa4780bd2ea73ad945f0227793a7e3d/src/main/java/eu/rekawek/toxiproxy/Proxy.java#L70-L76

Thus, the mentioned failed test will be rewritten as:

@Test
void withoutConnection() throws IOException {
    mongoProxy.disable();
    assertThatThrownBy(()->personRepository.findAll()).isInstanceOf(Exception.class);
    mongoProxy.enable();
    var result = personRepository.findAll();
    assertThat(result).isEmpty();
}

Upvotes: 0

Related Questions