Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix non-deterministic behaviors in IgniteSQLBuilder and IgniteStoreMetadataAnalyzer #296

Open
wants to merge 2 commits into
base: master
Choose a base branch
from

Conversation

ZhanwangZhou
Copy link

Description

I encountered non-deterministic behavior while running the following tests using NonDex:

org.apache.gora.ignite.store.TestIgniteStore

In gora-ignite/src/main/java/org/apache/gora/ignite/utils/IgniteSQLBuilder, method createInsertQuery and fillInsertQuery convert the entrySet of Map object data into List object list:

List<Entry<Column, Object>> list = new ArrayList<>(data.entrySet());

These two methods then iterate the list and pass its elements as other methods' parameters. The conversion from entrySet of Map to List causes the random order of List's element. This randomness further causes the non-deterministic behavior of put method in gora-ignite/src/main/java/org/apache/gora/ignite/store/IgniteStore, which calls these two methods. All tests calling put method of class IgniteStore are thus flaky.

Similarly, in gora-ignite/src/main/java/org/apache/gora/ignite/store/IgnoreStoreMetadataAnalyzer, method getTableNames iterates an unsorted ResultSet object executeQuery and appends its elements into List of table name Strings. The order of the table names in the list is random, but the list is then returned and compared with a list with fixed order in line 42 of gora-ignite/src/test/java/org/apache/gora/ignite/store/TestIgniteStore

Assert.assertTrue("Ignite Store Metadata Table Names", createAnalyzer.getTablesNames().equals(Lists.newArrayList("WEBPAGE", "EMPLOYEE")));

The randomness of the list returned by getTableNames thus may cause unexpected failure of TestIgniteStore.

Steps to Reproduce

I used tool NonDex to detect the flaky tests.

NonDex: https://github.com/TestingResearchIllinois/NonDex

Run the tests with NonDex:

mvn -pl gora-ignite edu.illinois:nondex-maven-plugin:2.1.7:nondex -Dtest=org.apache.gora.ignite.store.TestIgniteStore

The error message shows:

Click to view
[ERROR] Tests run: 45, Failures: 12, Errors: 17, Skipped: 0, Time elapsed: 12.609 s <<< FAILURE! - in org.apache.gora.ignite.store.TestIgniteStore
[ERROR] igniteStoreMetadataAnalyzerTest(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 1.6 s  <<< FAILURE!
java.lang.AssertionError: Ignite Store Metadata Table Names
	at org.apache.gora.ignite.store.TestIgniteStore.igniteStoreMetadataAnalyzerTest(TestIgniteStore.java:42)

[ERROR] testQuery(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.339 s  <<< FAILURE!
java.lang.AssertionError: expected:<10> but was:<0>

[ERROR] testGet3UnionField(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.402 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testGetPartitions(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.291 s  <<< FAILURE!
java.lang.AssertionError

[ERROR] testAutoCreateSchema(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.39 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.Long, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.Long, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.Long, to=java.lang.Integer]

[ERROR] testBenchmarkExists(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.371 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testPutArray(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.271 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=BYTEDATA, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=BYTEDATA, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=BYTEDATA, from=java.lang.String, to=[B]

[ERROR] testGetNested(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.485 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]

[ERROR] testQueryWebPageSingleKey(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.186 s  <<< FAILURE!
java.lang.AssertionError

[ERROR] testGetWebPageDefaultFields(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.266 s  <<< ERROR!
org.apache.gora.util.GoraException: java.io.EOFException
Caused by: java.io.EOFException

[ERROR] testPutNested(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.19 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]

[ERROR] testUpdate(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.14 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]
Caused by: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]

[ERROR] testDeleteByQueryFields(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.136 s  <<< FAILURE!
java.lang.AssertionError: expected:<10> but was:<0>

[ERROR] testQueryEndKey(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.296 s  <<< FAILURE!
java.lang.AssertionError: expected:<1> but was:<0>

[ERROR] testGetDoubleRecursive(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.303 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testQueryKeyRange(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.121 s  <<< FAILURE!
java.lang.AssertionError: expected:<1> but was:<0>

[ERROR] testExists(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.147 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testQueryWebPageSingleKeyDefaultFields(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.111 s  <<< FAILURE!
java.lang.AssertionError

[ERROR] testGet(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.107 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testGetRecursive(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.556 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]
Caused by: java.sql.SQLException: Value conversion failed [column=SALARY, from=java.lang.String, to=java.lang.Integer]

[ERROR] testGetWithFields(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.149 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=WEBPAGE, from=java.lang.String, to=[B]

[ERROR] testObjectFieldValue(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.109 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]
Caused by: java.sql.SQLException: Value conversion failed [column=DATEOFBIRTH, from=java.lang.String, to=java.lang.Long]

[ERROR] testPutMixedMaps(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.118 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=OUTLINKS, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=OUTLINKS, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=OUTLINKS, from=java.lang.String, to=[B]

[ERROR] testGetWebPage(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.117 s  <<< FAILURE!
java.lang.AssertionError

[ERROR] testPutMap(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.12 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]

[ERROR] testDelete(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.331 s  <<< FAILURE!
java.lang.AssertionError: expected:<9> but was:<0>

[ERROR] testDeleteByQuery(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.269 s  <<< FAILURE!
java.lang.AssertionError: expected:<10> but was:<0>

[ERROR] testQueryStartKey(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.156 s  <<< FAILURE!
java.lang.AssertionError: expected:<10> but was:<0>

[ERROR] testPutBytes(org.apache.gora.ignite.store.TestIgniteStore)  Time elapsed: 0.13 s  <<< ERROR!
org.apache.gora.util.GoraException: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: org.apache.gora.util.GoraException: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]
Caused by: java.sql.SQLException: Value conversion failed [column=PARSEDCONTENT, from=java.lang.String, to=[B]

[INFO]
[INFO] Results:
[INFO]
[ERROR] Failures:
[ERROR]   TestIgniteStore.igniteStoreMetadataAnalyzerTest:42 Ignite Store Metadata Table Names
[ERROR]   TestIgniteStore>DataStoreTestBase.testDelete:353 expected:<9> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testDeleteByQuery:359 expected:<10> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testDeleteByQueryFields:365 expected:<10> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetPartitions:371
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetWebPage:293
[ERROR]   TestIgniteStore>DataStoreTestBase.testQuery:311 expected:<10> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testQueryEndKey:323 expected:<1> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testQueryKeyRange:329 expected:<1> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testQueryStartKey:317 expected:<10> but was:<0>
[ERROR]   TestIgniteStore>DataStoreTestBase.testQueryWebPageSingleKey:335
[ERROR]   TestIgniteStore>DataStoreTestBase.testQueryWebPageSingleKeyDefaultFields:341
[ERROR] Errors:
[ERROR]   TestIgniteStore>DataStoreTestBase.testAutoCreateSchema:123 » Gora org.apache.g...
[ERROR]   TestIgniteStore>DataStoreTestBase.testBenchmarkExists:226 » Gora org.apache.go...
[ERROR]   TestIgniteStore>DataStoreTestBase.testExists:220 » Gora org.apache.gora.util.G...
[ERROR]   TestIgniteStore>DataStoreTestBase.testGet:232 » Gora org.apache.gora.util.Gora...
[ERROR]   TestIgniteStore>DataStoreTestBase.testGet3UnionField:281 » Gora org.apache.gor...
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetDoubleRecursive:256 » Gora org.apache...
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetNested:269 » Gora org.apache.gora.uti...
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetRecursive:244 » Gora org.apache.gora....
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetWebPageDefaultFields:299 » Gora java....
[ERROR]   TestIgniteStore>DataStoreTestBase.testGetWithFields:287 » Gora org.apache.gora...
[ERROR]   TestIgniteStore>DataStoreTestBase.testObjectFieldValue:426 » Gora org.apache.g...
[ERROR]   TestIgniteStore>DataStoreTestBase.testPutArray:169 » Gora org.apache.gora.util...
[ERROR]   TestIgniteStore>DataStoreTestBase.testPutBytes:179 » Gora org.apache.gora.util...
[ERROR]   TestIgniteStore>DataStoreTestBase.testPutMap:189 » Gora org.apache.gora.util.G...
[ERROR]   TestIgniteStore>DataStoreTestBase.testPutMixedMaps:199 » Gora org.apache.gora....
[ERROR]   TestIgniteStore>DataStoreTestBase.testPutNested:163 » Gora org.apache.gora.uti...
[ERROR]   TestIgniteStore>DataStoreTestBase.testUpdate:205 » Gora org.apache.gora.util.G...
[INFO]
[ERROR] Tests run: 45, Failures: 12, Errors: 17, Skipped: 0

Potential Solution

To fix the non-deterministic behavior of method createInsertQuery and fillInsertQuery of class IgniteSQLBuilder, we can pass a fix-ordered List instead of a random-ordered Map as parameters into these two functions:

public static String createInsertQuery(IgniteMapping mapping, List<Column> dataKeyList)
public static void fillInsertQuery(PreparedStatement statement, List<Object> insertData)

Meanwhile, in put method of class IgniteStore, we maintain two lists storing Map object data's keys and values:

List<Column> dataKeyList = new ArrayList<>();
List<Object> dataValueList = new ArrayList<>();

Whenever we put a key-value pair into Map object data, we update these two lists by adding the key and value. Therefore, the order of elements in these two lists will be deterministic, exactly matching the order in which we put key-value pairs into Map object data. We can then pass these two lists into method createInsertQuery and fillInsertQuery and fix the non-deterministic behavior.

To fix the non-deterministic behavior of method getTableNames in class IgnoreStoreMetadataAnalyzer, we can sort the List tab before returning it:

Collections.sort(tabs);

Then, the order of elements in List tab will be deterministic, following alphabetical order.

Correspondingly, we need to change the list for comparison in line 42 of TestIgniteStore to alphabetical order:

Assert.assertTrue("Ignite Store Metadata Table Names", createAnalyzer.getTablesNames().equals(Lists.newArrayList("EMPLOYEE", "WEBPAGE")));

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

1 participant