apolloconfig / apollo

Apollo is a reliable configuration management system suitable for microservice configuration management scenarios.
https://www.apolloconfig.com
Apache License 2.0
28.95k stars 10.19k forks source link

Flaky JUnit test testAppNamespace in AppNamespaceServiceWithCacheTest.java of module apollo-configservice #4997

Closed ThugJudy closed 8 months ago

ThugJudy commented 8 months ago

Flaky JUnit Tests identified in apollo-configservice.

Describe the bug In the course of test execution, the testAppNamespace within AppNamespaceServiceWithCacheTest advances to a point at line 197 in AppNamespaceServiceWithCache. apollo/apollo-configservice/src/main/java/com/ctrip/framework/apollo/configservice/service/AppNamespaceServiceWithCache.java

List ids = Lists.newArrayList(appNamespaceIdCache.keySet());

Here, it retrieves a set of keys, generating a hash result from the following that appears to be nondeterministic. The same hash in line 201 is partition divides the array into subarrays of a given size. When the order changes we can expect different subarrays. I found and confirmed the flaky behavior using an open-source research tool NonDex, which shuffles implementations of nondeterminism operations.

To Reproduce Steps to reproduce the behavior:

  1. Run the following command
    mvn edu.illinois:nondex-maven-plugin:2.1.1:nondex -pl apollo-configservice -Dtest=com.ctrip.framework.apollo.configservice.service.AppNamespaceServiceWithCacheTest#testAppNamespace

    Expected behavior The testcase should pass everytime

Additional Details & Logs

Test Environment:

openjdk version "1.8.0_351"
Apache Maven 3.6.3
Operating System: macOS
Product Version: 13.5.2
dosubot[bot] commented 8 months ago

🤖

Thank you for bringing this to our attention. The issue you're experiencing seems to be related to the non-deterministic nature of the HashSet data structure used in the appNamespaceIdCache cache. The HashSet does not guarantee any specific order of its elements, which can lead to different results when the set is converted to a list and partitioned.

One possible solution to this issue is to use a LinkedHashSet instead of a HashSet. A LinkedHashSet is a hash set with predictable iteration order. It maintains a doubly-linked list running through all of its entries, which defines the iteration ordering, which is the order in which elements were inserted into the set (insertion-order).

Here is how you can modify the AppNamespaceServiceWithCache class to use a LinkedHashSet:

private ConcurrentMap<Long, AppNamespace> appNamespaceIdCache = new ConcurrentHashMap<>();

Change to:

private ConcurrentMap<Long, AppNamespace> appNamespaceIdCache = new ConcurrentLinkedHashMap<>();

This change should ensure that the order of the keys in the appNamespaceIdCache cache remains consistent across different runs, which should make the testAppNamespace test pass consistently.

Please note that this is a potential solution and might not completely solve the issue. If the problem persists after making this change, please let us know so we can investigate further.

Sources


This response is meant to be useful and save you time. It is not meant to be a precise solution, but rather a starting point for your own research.

Help me be more useful! Please leave a 👍 if this is helpful and 👎 if it is irrelevant.

If you want to continue the conversation, start your reply with @dosu-bot.