From 18883052e6ea339259ef21d0022d99e93f1e6469 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 3 Aug 2024 14:43:37 +1000 Subject: [PATCH 1/6] Test that produces the same error as a manual run-through. --- .../corla/endpoint/ACVRUploadTests.java | 42 ++++++++++++++++++- 1 file changed, 40 insertions(+), 2 deletions(-) diff --git a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java index 7c0c95e4..00aff357 100644 --- a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java +++ b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java @@ -305,6 +305,39 @@ public class ACVRUploadTests extends TestClassWithAuth { " \"auditBoardIndex\": -1" + "}"; + /** + * 8. Reaudit of valid IRV vote, for CVR ID 240509; imprinted ID 1-1-1. + */ + private static final String validIRVReauditAsJson = "{" + + " \"cvr_id\": 240509," + + " \"audit_cvr\": {" + + " \"record_type\": \"AUDITOR_ENTERED\"," + + " \"county_id\": 1," + + " \"cvr_number\": 1," + + " \"sequence_number\": 1," + + " \"scanner_id\": 1," + + " \"batch_id\": \"1\"," + + " \"record_id\": 1," + + " \"imprinted_id\": \"1-1-1\"," + + " \"uri\": \"acvr:1:1-1-1\"," + + " \"ballot_type\": \"Ballot 1 - Type 1\"," + + " \"contest_info\": [" + + " {" + + " \"contest\": 240503," + + " \"comment\": \"A comment\"," + + " \"consensus\": \"YES\"," + + " \"choices\": [" + + " \"Alice(1)\"," + + " \"Chuan(2)\"" + + " ]" + + " }" + + " ]" + + " }," + + " \"reaudit\": true," + + " \"comment\": \"\"," + + " \"auditBoardIndex\": -1" + + "}"; + /** * Database init. */ @@ -338,8 +371,9 @@ public void initMocks() { * 3. a blank IRV vote, * 4. a vote with non-IRV choices ("Alice" instead of "Alice(1)"), * 5. a vote with invalid choices (names not in the list of choices for the contest), - * 6. a vote that doesn't properly correspond to the IDs it should have, and - * 7. an unparseable vote (typos in json data). + * 6. a vote that doesn't properly correspond to the IDs it should have, + * 7. an unparseable vote (typos in json data), and + * 8. a reaudit. * We check that it is accepted and that the right records for CVR and CVRContestInfo are * stored in the database. */ @@ -399,6 +433,10 @@ void testACVRUploadAndStorage() { // Seventh test: upload a vote that has typos preventing json deserialization. This should // cause an error. testErrorResponse(240515L, IRVJsonDeserializationFail, malformedACVRMsg); + + // Eighth test: upload a reaudit ballot. + testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, + List.of("Alice","Chuan"), 3); } } From 095b2508a6cbf34a5e3b118361815b8f0d51f7a6 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 3 Aug 2024 15:05:15 +1000 Subject: [PATCH 2/6] Simple reaudit test now passing. --- .../us/freeandfair/corla/query/CastVoteRecordQueries.java | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java b/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java index de877266..72154592 100644 --- a/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java +++ b/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java @@ -577,11 +577,16 @@ public static Long maxRevision(final CastVoteRecord cvr) { q.setString("imprintedId", cvr.imprintedID()); try { - return (Long) q.getSingleResult(); + // Make sure not to return null, which causes errors later. 0L is the correct return value if + // there are no prior revisions in the database. + final Long result = (Long) q.getSingleResult(); + return result == null ? 0L : result; } catch (final PersistenceException e) { // the DB had a problem! // TODO: Technically this should probably be an error code? // TODO: Otherwise there's no way to discern this from a CVR with no revisions? + // VT: Agree. Since 0L is used for "valid; no prior revisions", suggest using a different value + // here or throwing an exception. return 0L; } From faca297da369b5e9f900361e0a64942dcff7aeb7 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 3 Aug 2024 19:50:02 +1000 Subject: [PATCH 3/6] Tests of reauditing, including a second reaudit of something that has already been reaudited. --- .../corla/query/CastVoteRecordQueries.java | 3 +- .../corla/endpoint/ACVRUploadTests.java | 64 +++++++++++++++++-- 2 files changed, 59 insertions(+), 8 deletions(-) diff --git a/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java b/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java index 72154592..07c7f01b 100644 --- a/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java +++ b/server/eclipse-project/src/main/java/us/freeandfair/corla/query/CastVoteRecordQueries.java @@ -579,6 +579,7 @@ public static Long maxRevision(final CastVoteRecord cvr) { try { // Make sure not to return null, which causes errors later. 0L is the correct return value if // there are no prior revisions in the database. + // Some documentation says that getSingleResult() never returns null, but it definitely does. final Long result = (Long) q.getSingleResult(); return result == null ? 0L : result; } catch (final PersistenceException e) { @@ -586,7 +587,7 @@ public static Long maxRevision(final CastVoteRecord cvr) { // TODO: Technically this should probably be an error code? // TODO: Otherwise there's no way to discern this from a CVR with no revisions? // VT: Agree. Since 0L is used for "valid; no prior revisions", suggest using a different value - // here or throwing an exception. + // here (-1?) or throwing an exception. return 0L; } diff --git a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java index 00aff357..d3716126 100644 --- a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java +++ b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java @@ -21,15 +21,18 @@ import static au.org.democracydevelopers.corla.util.testUtils.tinyIRV; import static org.testng.Assert.assertEquals; import static org.testng.Assert.assertTrue; +import static org.testng.Assert.assertFalse; import spark.Request; import javax.transaction.Transactional; import java.util.HashSet; import java.util.List; +import java.util.OptionalLong; import static us.freeandfair.corla.endpoint.Endpoint.AuthorizationType.COUNTY; import static us.freeandfair.corla.model.CastVoteRecord.RecordType.AUDITOR_ENTERED; +import static us.freeandfair.corla.model.CastVoteRecord.RecordType.REAUDITED; /** * Test upload of IRV audit cvrs. Includes tests of both valid and invalid IRV CVRs, and tests that @@ -372,8 +375,10 @@ public void initMocks() { * 4. a vote with non-IRV choices ("Alice" instead of "Alice(1)"), * 5. a vote with invalid choices (names not in the list of choices for the contest), * 6. a vote that doesn't properly correspond to the IDs it should have, - * 7. an unparseable vote (typos in json data), and - * 8. a reaudit. + * 7. an unparseable vote (typos in json data), + * 8. a reaudit (which checks that the superseded upload is market REAUDITED), and + * 9. a second reaudit with the same data (which checks that the previous reaudit is also now marked REAUDITED and that + * there are now two revisions). * We check that it is accepted and that the right records for CVR and CVRContestInfo are * stored in the database. */ @@ -435,8 +440,17 @@ void testACVRUploadAndStorage() { testErrorResponse(240515L, IRVJsonDeserializationFail, malformedACVRMsg); // Eighth test: upload a reaudit ballot. - testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, - List.of("Alice","Chuan"), 3); + // Check that the new data successfully replaces the prior upload. + testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, List.of("Alice","Chuan"), 3); + // Test that the previous upload, with a vote for Bob and Chuan (validIRVAsJson) is now tagged as REAUDITED. + testPreviousAreReaudited(240509L, "1-1-1", List.of("Bob","Chuan"), 1, 1); + + // Ninth test: re-upload the same reaudit ballot, again. + // Check that the new data is identical (it replaces it, but it's the same). + testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, List.of("Alice","Chuan"), 3); + // Test that the previous upload (from test 8), with a vote for Alice and Chuan (validIRVReauditAsJson) is now tagged as REAUDITED. + // There should be two reaudited ballots now, and the max revision should be 2. + testPreviousAreReaudited(240509L, "1-1-1", List.of("Alice","Chuan"), 2, 2); } } @@ -465,14 +479,14 @@ private void testIRVBallotInterpretations(final long CvrNum, final String imprin /** * Test expected consequences of successful ACVR upload. - * @param CvrId The CVR number (last number of the imprinted ID). + * @param CvrId The CVR ID (of the original UPLOADED CVR). * @param expectedImprintedId The imprinted id, scanner-batch-record. * @param CvrAsJson The upload cvr, as a json string. * @param expectedInterpretedChoices The expected valid interpretation, which should be stored. * @param expectedACVRs The number of audit CVRs expected in total. */ private void testSuccessResponse(final long CvrId, final String expectedImprintedId, final String CvrAsJson, - final List expectedInterpretedChoices, final int expectedACVRs) { + final List expectedInterpretedChoices, final int expectedACVRs) { final Request request = new SparkRequestStub(CvrAsJson, new HashSet<>()); uploadEndpoint.endpointBody(request, response); @@ -481,7 +495,7 @@ private void testSuccessResponse(final long CvrId, final String expectedImprinte AUDITOR_ENTERED).toList(); assertEquals(acvrs.size(), expectedACVRs); - // There should now be an ACVR with matching cvrId. + // There should now be an AUDITOR_ENTERED ACVR with matching cvrId. final CastVoteRecord acvr = acvrs.stream().filter(a -> a.getCvrId() == CvrId).findFirst().orElseThrow(); assertEquals(acvr.recordType(), AUDITOR_ENTERED); // Check that we have the right record: CvrId and Imprinted ID should match. @@ -494,6 +508,42 @@ private void testSuccessResponse(final long CvrId, final String expectedImprinte assertTrue(testUtils.equalStringLists(choices, expectedInterpretedChoices)); } + /** + * Check that some previously-uploaded ballot has been tagged as "REAUDITED". This happens when a new ballot with the + * same CvrId is uploaded with "reaudit = true". The idea is that the most recent REAUDIT is always simply + * of type AUDITOR_ENTERED, but all _previously_ submitted versions of the same ballot are tagged as REAUDITED - these + * are then omitted from discrepancy and risk calculations, because only the most recent upload counts. + * @param CvrId The CVR ID (of the original UPLOADED CVR). + * @param expectedImprintedId The imprinted id, scanner-batch-record. + * @param expectedInterpretedChoices The expected valid interpretation, which should be stored. + * @param expectedReauditedBallots The number of expected REAUDITED ballots with this CvrId. + * @param expectedMaxRevision The revision of the old audit cvr (null for the first audit ballot; 1L for the + * first reaudit, then incrementing by 1 for subsequent reaudits. + */ + private void testPreviousAreReaudited(final long CvrId, final String expectedImprintedId, + final List expectedInterpretedChoices, final long expectedReauditedBallots, final long expectedMaxRevision) { + + // Check for the expected number of Reaudited ballots of the required CvrId. + final List acvrs = CastVoteRecordQueries.getMatching(1L, REAUDITED).filter(a -> a.getCvrId() == CvrId).toList(); + assertEquals(acvrs.size(), expectedReauditedBallots); + + // Check that we have the right records: Imprinted ID should match. + assertTrue(acvrs.stream().allMatch(cvr -> cvr.imprintedID().equals(expectedImprintedId))); + + // Find the maximum revision; check that it matches the expected maximum revision (this should match the number of + // reaudits). + assertFalse(acvrs.isEmpty()); + OptionalLong maxRevision = acvrs.stream().mapToLong(CastVoteRecord::getRevision).max(); + assertEquals(maxRevision, OptionalLong.of(expectedMaxRevision)); + + // Check that there is one record with the expected revision and it has the expected vote choices. + List maxRevisionAcvrs = acvrs.stream().filter(a -> a.getRevision() == expectedMaxRevision).toList(); + assertEquals(maxRevisionAcvrs.size(), 1); + assertTrue(maxRevisionAcvrs.get(0).contestInfoForContestResult(tinyIRV).isPresent()); + final List choices = maxRevisionAcvrs.get(0).contestInfoForContestResult(tinyIRV).get().choices(); + assertTrue(testUtils.equalStringLists(choices, expectedInterpretedChoices)); + } + /** * Test that submitting the given ACVR to the endpoint produces the given error, and that there are no corresponding * ACVRs stored in the database afterward. From 8894b9cba7fb988b11273ac057487bd8396d7844 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 3 Aug 2024 21:01:57 +1000 Subject: [PATCH 4/6] Some more reauditing tests - throws an exception when trying to reaudit a cvr that wasn't previously audited. --- .../corla/endpoint/ACVRUploadTests.java | 38 ++++++++++++++++++- 1 file changed, 36 insertions(+), 2 deletions(-) diff --git a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java index d3716126..924c1743 100644 --- a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java +++ b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java @@ -38,7 +38,6 @@ * Test upload of IRV audit cvrs. Includes tests of both valid and invalid IRV CVRs, and tests that * the interpreted ballots are properly stored in the database. * This makes use of TestClassWithAuth to mock authentication as Adams County. - * TODO test reaudits, both IRV and plurality (can they be mixed in one CVR?) * See ... */ public class ACVRUploadTests extends TestClassWithAuth { @@ -309,7 +308,7 @@ public class ACVRUploadTests extends TestClassWithAuth { "}"; /** - * 8. Reaudit of valid IRV vote, for CVR ID 240509; imprinted ID 1-1-1. + * 8 & 9. Reaudit of valid IRV vote, for CVR ID 240509; imprinted ID 1-1-1. */ private static final String validIRVReauditAsJson = "{" + " \"cvr_id\": 240509," + @@ -341,6 +340,38 @@ public class ACVRUploadTests extends TestClassWithAuth { " \"auditBoardIndex\": -1" + "}"; + /** + * 10. Attempt to reaudit a vote that has not yet been audited - #7, the IRV vote with typos. + * Should cause an error. + */ + private static final String IRVReauditNoPriorUpload = "{" + + " \"cvr_id\": 240515," + + " \"audit_cvr\": {" + + " \"record_type\": \"AUDITOR_ENTERED\"," + + " \"county_id\": 1," + + " \"cvr_number\": 7," + + " \"sequence_number\": 1," + + " \"scanner_id\": 1," + + " \"batch_id\": \"1\"," + + " \"record_id\": 7," + + " \"imprinted_id\": \"1-1-7\"," + + " \"uri\": \"acvr:1:1-1-7\"," + + " \"ballot_type\": \"Ballot 1 - Type 1\"," + + " \"contest_info\": [" + + " {" + + " \"contest\": 240503," + + " \"comment\": \"A comment\"," + + " \"consensus\": \"YES\"," + + " \"choices\": [" + + " ]" + + " }" + + " ]" + + " }," + + " \"reaudit\": true," + + " \"comment\": \"\"," + + " \"auditBoardIndex\": -1" + + "}"; + /** * Database init. */ @@ -451,6 +482,9 @@ void testACVRUploadAndStorage() { // Test that the previous upload (from test 8), with a vote for Alice and Chuan (validIRVReauditAsJson) is now tagged as REAUDITED. // There should be two reaudited ballots now, and the max revision should be 2. testPreviousAreReaudited(240509L, "1-1-1", List.of("Alice","Chuan"), 2, 2); + + // Tenth test: try to "re-"audit something that has not previously been successfully audited. Should throw an error. + testErrorResponse(240515L, IRVReauditNoPriorUpload, ""); } } From 9703b08211faaf5274cd8ab7cde97c2219163d43 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 3 Aug 2024 21:17:06 +1000 Subject: [PATCH 5/6] Fixed a bug in which a NullptrException was thrown when trying to reaudit a cvr that wasn't previously audited. --- .../corla/controller/ComparisonAuditController.java | 9 +++++---- .../corla/endpoint/ACVRUploadTests.java | 12 ++++++------ 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java b/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java index 06fb4929..ace90c2c 100644 --- a/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java +++ b/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java @@ -232,13 +232,14 @@ public static boolean reaudit(final CountyDashboard cdb, final String comment) { LOGGER.info("[reaudit] cvr: " + cvr.toString()); - final CVRAuditInfo cai = - Persistence.getByID(cvr.id(), CVRAuditInfo.class); - final CastVoteRecord oldAcvr = cai.acvr(); - if (null == oldAcvr) { + + // VT: If this cvr has not been audited before, I believe cai will be null. + final CVRAuditInfo cai = Persistence.getByID(cvr.id(), CVRAuditInfo.class); + if (cai == null || cai.acvr() == null) { LOGGER.error("can't reaudit a cvr that hasn't been audited"); return false; } + final CastVoteRecord oldAcvr = cai.acvr(); final Integer former_count = unaudit(cdb, cai); LOGGER.debug("[reaudit] former_count: " + former_count.toString()); diff --git a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java index 924c1743..b9eacb82 100644 --- a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java +++ b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java @@ -456,19 +456,19 @@ void testACVRUploadAndStorage() { // Expected error messages for malformed upload cvrs. String malformedACVRMsg = "malformed audit CVR upload"; - testErrorResponse(240512L, pluralityIRVAsJson, malformedACVRMsg); + testErrorResponseAndNoMatchingCvr(240512L, pluralityIRVAsJson, malformedACVRMsg); // Fifth test: upload a vote with IRV choices that are not among the valid candidates. This // should cause an error. - testErrorResponse(240513L, wrongCandidateNamesIRVAsJson, malformedACVRMsg); + testErrorResponseAndNoMatchingCvr(240513L, wrongCandidateNamesIRVAsJson, malformedACVRMsg); // Sixth test: upload a vote with IDs that do not correspond properly to the expected CVR. // This should cause an error. - testErrorResponse(240514L, IRVWithInconsistentIDsAsJson, malformedACVRMsg); + testErrorResponseAndNoMatchingCvr(240514L, IRVWithInconsistentIDsAsJson, malformedACVRMsg); // Seventh test: upload a vote that has typos preventing json deserialization. This should // cause an error. - testErrorResponse(240515L, IRVJsonDeserializationFail, malformedACVRMsg); + testErrorResponseAndNoMatchingCvr(240515L, IRVJsonDeserializationFail, malformedACVRMsg); // Eighth test: upload a reaudit ballot. // Check that the new data successfully replaces the prior upload. @@ -484,7 +484,7 @@ void testACVRUploadAndStorage() { testPreviousAreReaudited(240509L, "1-1-1", List.of("Alice","Chuan"), 2, 2); // Tenth test: try to "re-"audit something that has not previously been successfully audited. Should throw an error. - testErrorResponse(240515L, IRVReauditNoPriorUpload, ""); + testErrorResponseAndNoMatchingCvr(240515L, IRVReauditNoPriorUpload, "CVR has not previously been audited"); } } @@ -585,7 +585,7 @@ private void testPreviousAreReaudited(final long CvrId, final String expectedImp * @param CvrAsJson The upload cvr, as a json string. * @param expectedError The expected error message. */ - private void testErrorResponse(final long CvrId, final String CvrAsJson, final String expectedError) { + private void testErrorResponseAndNoMatchingCvr(final long CvrId, final String CvrAsJson, final String expectedError) { final Request request = new SparkRequestStub(CvrAsJson, new HashSet<>()); String errorBody = ""; From 15cc605f680ee3f461d7aebc725a73fc12b3bf69 Mon Sep 17 00:00:00 2001 From: vteague Date: Sat, 10 Aug 2024 09:01:53 +1000 Subject: [PATCH 6/6] Improvements from @michelleblom's review. --- .../controller/ComparisonAuditController.java | 2 +- .../corla/endpoint/ACVRUploadTests.java | 25 +++++++++++-------- 2 files changed, 15 insertions(+), 12 deletions(-) diff --git a/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java b/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java index ace90c2c..ef5b2f89 100644 --- a/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java +++ b/server/eclipse-project/src/main/java/us/freeandfair/corla/controller/ComparisonAuditController.java @@ -233,7 +233,7 @@ public static boolean reaudit(final CountyDashboard cdb, LOGGER.info("[reaudit] cvr: " + cvr.toString()); - // VT: If this cvr has not been audited before, I believe cai will be null. + // DemocracyDevelopers: If this cvr has not been audited before, cai will be null. final CVRAuditInfo cai = Persistence.getByID(cvr.id(), CVRAuditInfo.class); if (cai == null || cai.acvr() == null) { LOGGER.error("can't reaudit a cvr that hasn't been audited"); diff --git a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java index b9eacb82..8abc6c55 100644 --- a/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java +++ b/server/eclipse-project/src/test/java/au/org/democracydevelopers/corla/endpoint/ACVRUploadTests.java @@ -407,11 +407,11 @@ public void initMocks() { * 5. a vote with invalid choices (names not in the list of choices for the contest), * 6. a vote that doesn't properly correspond to the IDs it should have, * 7. an unparseable vote (typos in json data), - * 8. a reaudit (which checks that the superseded upload is market REAUDITED), and - * 9. a second reaudit with the same data (which checks that the previous reaudit is also now marked REAUDITED and that - * there are now two revisions). - * We check that it is accepted and that the right records for CVR and CVRContestInfo are - * stored in the database. + * 8. a reaudit (which checks that the superseded upload is marked REAUDITED), and + * 9. a second reaudit with the same data (which checks that the previous reaudit is also now + * marked REAUDITED and that there are now two revisions). + * We check that it is accepted (or rejected if it should be) and that the right records for CVR + * and CVRContestInfo are stored in the database. */ @Test @Transactional @@ -470,16 +470,18 @@ void testACVRUploadAndStorage() { // cause an error. testErrorResponseAndNoMatchingCvr(240515L, IRVJsonDeserializationFail, malformedACVRMsg); - // Eighth test: upload a reaudit ballot. + // Eighth test: upload a reaudited ballot. // Check that the new data successfully replaces the prior upload. testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, List.of("Alice","Chuan"), 3); - // Test that the previous upload, with a vote for Bob and Chuan (validIRVAsJson) is now tagged as REAUDITED. + // Test that the previous upload, with a vote for Bob and Chuan (validIRVAsJson) is now tagged + // as REAUDITED. testPreviousAreReaudited(240509L, "1-1-1", List.of("Bob","Chuan"), 1, 1); - // Ninth test: re-upload the same reaudit ballot, again. + // Ninth test: upload the same ballot being reaudited, again. // Check that the new data is identical (it replaces it, but it's the same). testSuccessResponse(240509L, "1-1-1", validIRVReauditAsJson, List.of("Alice","Chuan"), 3); - // Test that the previous upload (from test 8), with a vote for Alice and Chuan (validIRVReauditAsJson) is now tagged as REAUDITED. + // Test that the previous upload (from test 8), with a vote for Alice and Chuan + // (validIRVReauditAsJson) is now tagged as REAUDITED. // There should be two reaudited ballots now, and the max revision should be 2. testPreviousAreReaudited(240509L, "1-1-1", List.of("Alice","Chuan"), 2, 2); @@ -567,11 +569,12 @@ private void testPreviousAreReaudited(final long CvrId, final String expectedImp // Find the maximum revision; check that it matches the expected maximum revision (this should match the number of // reaudits). assertFalse(acvrs.isEmpty()); - OptionalLong maxRevision = acvrs.stream().mapToLong(CastVoteRecord::getRevision).max(); + final OptionalLong maxRevision = acvrs.stream().mapToLong(CastVoteRecord::getRevision).max(); assertEquals(maxRevision, OptionalLong.of(expectedMaxRevision)); // Check that there is one record with the expected revision and it has the expected vote choices. - List maxRevisionAcvrs = acvrs.stream().filter(a -> a.getRevision() == expectedMaxRevision).toList(); + final List maxRevisionAcvrs + = acvrs.stream().filter(a -> a.getRevision() == expectedMaxRevision).toList(); assertEquals(maxRevisionAcvrs.size(), 1); assertTrue(maxRevisionAcvrs.get(0).contestInfoForContestResult(tinyIRV).isPresent()); final List choices = maxRevisionAcvrs.get(0).contestInfoForContestResult(tinyIRV).get().choices();