diff --git a/pom.xml b/pom.xml
index 59c41d5a..23bb13bc 100644
--- a/pom.xml
+++ b/pom.xml
@@ -32,31 +32,16 @@
spring-boot-starter-data-jpa
3.1.3
-
- org.springframework.boot
- spring-boot-starter-validation
- 3.1.3
-
org.postgresql
postgresql
42.6.1
-
- org.springdoc
- springdoc-openapi-ui
- 1.7.0
-
org.springframework.boot
spring-boot-starter-test
test
-
- io.rest-assured
- rest-assured
- test
-
com.google.code.gson
gson
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/config/RaireConfig.java b/src/main/java/au/org/democracydevelopers/raireservice/config/RaireConfig.java
deleted file mode 100644
index 83b26fb2..00000000
--- a/src/main/java/au/org/democracydevelopers/raireservice/config/RaireConfig.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.config;
-
-import com.fasterxml.jackson.databind.ObjectMapper;
-import org.springframework.context.annotation.Bean;
-import org.springframework.context.annotation.Configuration;
-import org.springframework.web.client.RestTemplate;
-
-@Configuration
-public class RaireConfig {
- @Bean
- public RestTemplate restTemplate() {
- return new RestTemplate();
- }
-
- @Bean
- public ObjectMapper objectMapper() {
- return new ObjectMapper();
- }
-
-}
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/Assertion.java b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/Assertion.java
index a3734fd4..5dab8d5b 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/Assertion.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/Assertion.java
@@ -23,6 +23,8 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
import static au.org.democracydevelopers.raireservice.util.CSVUtils.escapeThenJoin;
import au.org.democracydevelopers.raire.assertions.AssertionAndDifficulty;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
import java.math.BigDecimal;
import java.text.DecimalFormat;
import java.util.ArrayList;
@@ -190,7 +192,7 @@ public abstract class Assertion {
*/
@Column(name = "current_risk", updatable = false, nullable = false)
@ReadOnlyProperty
- protected BigDecimal currentRisk = new BigDecimal("1.00");
+ protected BigDecimal currentRisk = BigDecimal.valueOf(1);
/**
* Default no-args constructor (required for persistence).
@@ -387,7 +389,7 @@ public BigDecimal getCurrentRisk() {
* data stored in the assertion.
*/
public abstract AssertionAndDifficulty convert(List candidates)
- throws IllegalArgumentException;
+ throws RaireServiceException;
/**
* Return as a list of strings intended for a CSV row, in the same order as the csvHeaders in
@@ -397,26 +399,38 @@ public abstract AssertionAndDifficulty convert(List candidates)
* Floating-point numbers are formatted to 4 d.p, except the (BigDecimal) current risk, which is
* given to its full precision.
* @return The assertion data, as a list of csv-escaped strings.
- */
- public List asCSVRow() {
- var fm = new DecimalFormat("0.0###");
- return List.of(
- getAssertionType(),
- winner,
- loser,
- escapeThenJoin(assumedContinuing),
- fm.format(difficulty),
- margin+"",
- fm.format(dilutedMargin),
- currentRisk.toString(),
- estimatedSamplesToAudit+"",
- optimisticSamplesToAudit+"",
- twoVoteOverCount+"",
- oneVoteOverCount+"",
- otherCount+"",
- oneVoteUnderCount+"",
- twoVoteUnderCount+""
- );
+ * @throws RaireServiceException with error code WRONG_CANDIDATE_NAMES if the winner, loser or any of
+ * the assumed_continuing candidates are not in the input candidate list.
+ */
+ public List asCSVRow(List candidates) throws RaireServiceException {
+ final String prefix = "[asCSVRow]";
+ final DecimalFormat fm = new DecimalFormat("0.0###");
+
+ if(candidates.contains(winner) && candidates.contains(loser)
+ && candidates.containsAll(assumedContinuing) ) {
+ return List.of(
+ getAssertionType(),
+ winner,
+ loser,
+ escapeThenJoin(assumedContinuing),
+ fm.format(difficulty),
+ margin + "",
+ fm.format(dilutedMargin),
+ currentRisk.toString(),
+ estimatedSamplesToAudit + "",
+ optimisticSamplesToAudit + "",
+ twoVoteOverCount + "",
+ oneVoteOverCount + "",
+ otherCount + "",
+ oneVoteUnderCount + "",
+ twoVoteUnderCount + ""
+ );
+ } else {
+ final String msg = String.format("%s Candidate list provided as parameter is inconsistent " +
+ "with assertion (winner or loser or some continuing candidate not present).", prefix);
+ logger.error(msg);
+ throw new RaireServiceException(msg, RaireErrorCode.WRONG_CANDIDATE_NAMES);
+ }
}
/**
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NEBAssertion.java b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NEBAssertion.java
index c7e6956c..647d01ab 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NEBAssertion.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NEBAssertion.java
@@ -23,6 +23,8 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
import au.org.democracydevelopers.raire.assertions.AssertionAndDifficulty;
import au.org.democracydevelopers.raire.assertions.NotEliminatedBefore;
import au.org.democracydevelopers.raireservice.service.Metadata;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
import java.util.ArrayList;
@@ -85,7 +87,7 @@ public NEBAssertion(String contestName, long universeSize, int margin, double di
/**
* {@inheritDoc}
*/
- public AssertionAndDifficulty convert(List candidates) throws IllegalArgumentException {
+ public AssertionAndDifficulty convert(List candidates) throws RaireServiceException {
final String prefix = "[convert]";
logger.debug(String.format("%s Constructing a raire-java AssertionAndDifficulty for the " +
@@ -107,7 +109,7 @@ public AssertionAndDifficulty convert(List candidates) throws IllegalArg
final String msg = String.format("%s Candidate list provided as parameter is inconsistent " +
"with assertion (winner or loser not present).", prefix);
logger.error(msg);
- throw new IllegalArgumentException(msg);
+ throw new RaireServiceException(msg, RaireErrorCode.WRONG_CANDIDATE_NAMES);
}
}
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NENAssertion.java b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NENAssertion.java
index b96d8273..6d05fe69 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NENAssertion.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/persistence/entity/NENAssertion.java
@@ -23,6 +23,8 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
import au.org.democracydevelopers.raire.assertions.AssertionAndDifficulty;
import au.org.democracydevelopers.raire.assertions.NotEliminatedNext;
import au.org.democracydevelopers.raireservice.service.Metadata;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
import jakarta.persistence.DiscriminatorValue;
import jakarta.persistence.Entity;
@@ -93,7 +95,7 @@ public NENAssertion(String contestName, long universeSize, int margin, double di
/**
* {@inheritDoc}
*/
- public AssertionAndDifficulty convert(List candidates) throws IllegalArgumentException {
+ public AssertionAndDifficulty convert(List candidates) throws RaireServiceException {
final String prefix = "[convert]";
logger.debug(String.format("%s Constructing a raire-java AssertionAndDifficulty for the " +
@@ -119,7 +121,8 @@ public AssertionAndDifficulty convert(List candidates) throws IllegalArg
else{
final String msg = String.format("%s Candidate list provided as parameter is inconsistent " +
"with assertion (winner or loser or some continuing candidate not present).", prefix);
- throw new IllegalArgumentException(msg);
+ logger.error(msg);
+ throw new RaireServiceException(msg, RaireErrorCode.WRONG_CANDIDATE_NAMES);
}
}
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/request/GenerateAssertionsRequest.java b/src/main/java/au/org/democracydevelopers/raireservice/request/GenerateAssertionsRequest.java
index 9b135f98..2f395938 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/request/GenerateAssertionsRequest.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/request/GenerateAssertionsRequest.java
@@ -53,7 +53,7 @@ public class GenerateAssertionsRequest extends ContestRequest {
/**
* The elapsed time allowed to raire to generate the assertions, in seconds.
*/
- public final float timeLimitSeconds;
+ public final double timeLimitSeconds;
/**
* All args constructor.
@@ -64,7 +64,7 @@ public class GenerateAssertionsRequest extends ContestRequest {
*/
@ConstructorProperties({"contestName", "totalAuditableBallots", "timeLimitSeconds","candidates"})
public GenerateAssertionsRequest(String contestName, int totalAuditableBallots,
- float timeLimitSeconds, List candidates) {
+ double timeLimitSeconds, List candidates) {
super(contestName, candidates);
this.totalAuditableBallots = totalAuditableBallots;
this.timeLimitSeconds = timeLimitSeconds;
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsCsvService.java b/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsCsvService.java
index a5d75629..88f37926 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsCsvService.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsCsvService.java
@@ -99,7 +99,7 @@ public String generateCSV(GetAssertionsRequest request) throws RaireServiceExcep
String preface = makePreface(request);
String extrema = findExtrema(sortedAssertions);
String headers = escapeThenJoin(csvHeaders);
- String contents = makeContents(sortedAssertions);
+ String contents = makeContents(sortedAssertions, request.candidates);
logger.debug(String.format("%s %d assertions translated to csv.", prefix, assertions.size()));
return preface + extrema + "\n\n" + headers + "\n" + contents;
@@ -266,14 +266,17 @@ private String makePreface(GetAssertionsRequest request) {
* number (not related to the database's index) that begins at 1 and increments by 1 with each row.
* @param assertions a list of assertions
* @return their concatenated csv rows.
+ * @throws RaireServiceException if the candidate names in any of the assertions are inconsistent
+ * with the request's candidate list.
*/
- private String makeContents(List assertions) {
+ private String makeContents(List assertions, List candidates)
+ throws RaireServiceException {
int index = 1;
List rows = new ArrayList<>();
for (Assertion assertion : assertions) {
- rows.add(index++ + "," + escapeThenJoin(assertion.asCSVRow()));
+ rows.add(index++ + "," + escapeThenJoin(assertion.asCSVRow(candidates)));
}
return String.join("\n", rows) + "\n";
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsJsonService.java b/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsJsonService.java
index 52ea7cef..7b2334d9 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsJsonService.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/service/GetAssertionsJsonService.java
@@ -29,6 +29,7 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
import au.org.democracydevelopers.raireservice.persistence.repository.AssertionRepository;
import au.org.democracydevelopers.raireservice.request.GetAssertionsRequest;
import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
+import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
@@ -91,8 +92,10 @@ public RaireSolution getRaireSolution(GetAssertionsRequest request)
// keeping track of the maximum difficulty and minimum margin.
logger.debug(String.format("%s Converting %d assertions into raire-java format.", prefix,
assertions.size()));
- List translated = assertions.stream().map(
- a -> a.convert(request.candidates)).toList();
+ List translated = new ArrayList<>();
+ for(Assertion a : assertions) {
+ translated.add(a.convert(request.candidates));
+ }
logger.debug(String.format("%s %d assertions translated to json.", prefix,
assertions.size()));
diff --git a/src/main/java/au/org/democracydevelopers/raireservice/service/RaireServiceException.java b/src/main/java/au/org/democracydevelopers/raireservice/service/RaireServiceException.java
index 3077c9c5..190116b5 100644
--- a/src/main/java/au/org/democracydevelopers/raireservice/service/RaireServiceException.java
+++ b/src/main/java/au/org/democracydevelopers/raireservice/service/RaireServiceException.java
@@ -43,6 +43,11 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
*/
public class RaireServiceException extends Exception {
+ /**
+ * The string "error_code" - used for retrieving it from json etc.
+ */
+ public static String ERROR_CODE_KEY = "error_code";
+
/**
* The error code - an enum used to describe what went wrong. Returned in the http response for
* colorado-rla to interpret for the user.
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/NSWValues.java b/src/test/java/au/org/democracydevelopers/raireservice/NSWValues.java
new file mode 100644
index 00000000..49fb0a89
--- /dev/null
+++ b/src/test/java/au/org/democracydevelopers/raireservice/NSWValues.java
@@ -0,0 +1,351 @@
+/*
+Copyright 2024 Democracy Developers
+
+The Raire Service is designed to connect colorado-rla and its associated database to
+the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
+
+This file is part of raire-service.
+
+raire-service is free software: you can redistribute it and/or modify it under the terms
+of the GNU Affero General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with
+raire-service. If not, see .
+*/
+
+package au.org.democracydevelopers.raireservice;
+
+import java.util.Arrays;
+import java.util.List;
+
+/**
+ * This class summarises the contest names, candidate choices, expected winners and estimated
+ * difficulties for all NSW 2021 IRV contests.
+ * Difficulties are taken from raire-java::src/test/java/au/org/democracydevelopers/raire/TestNSW
+ * which in turn tests against raire-rs.
+ * Winners are taken from the New South Wales official election results at
+ * https://pastvtr.elections.nsw.gov.au/LG2101/status/mayoral
+ * The ballotCounts are derived from the data, but double-checked for exact match with the
+ * NSWEC website.
+ *
+ */
+public class NSWValues {
+
+ // Contest Eurobodalla Mayoral
+ public static final String nameContest_1 = "Eurobodalla Mayoral";
+ public static final List choicesContest_1 = List.of("WORTHINGTON Alison","GRACE David",
+ "SMITH Gary","HATCHER Mat","HARRISON N (Tubby)","POLLOCK Rob","STARMER Karyn");
+ public static final int BallotCount_1 = 25526;
+ public static final double difficulty_1 = 23.079566003616637;
+ public static final String winnerContest_1 = "HATCHER Mat";
+
+ // Contest City of Lake Macquarie Mayoral
+ public static final String nameContest_2 = "City of Lake Macquarie Mayoral";
+ public static final List choicesContest_2 = List.of("FRASER Kay","DAWSON Rosmairi",
+ "CUBIS Luke","PAULING Jason");
+ public static final int BallotCount_2 = 130336;
+ public static final double difficulty_2 = 3.1113869658629745;
+ public static final String winnerContest_2 = "FRASER Kay";
+
+ // Contest City of Coffs Harbour Mayoral
+ public static final String nameContest_3 = "City of Coffs Harbour Mayoral";
+ public static final List choicesContest_3 = List.of("SWAN Tegan","CECATO George",
+ "ADENDORFF Michael","JUDGE Tony","PRYCE Rodger","PIKE Donna","AMOS Paul","TOWNLEY Sally",
+ "ARKAN John","CASSELL Jonathan");
+ public static final int BallotCount_3 = 45155;
+ public static final double difficulty_3 = 8.571564160971906;
+ public static final String winnerContest_3 = "AMOS Paul";
+
+ // Contest Singleton Mayoral
+ public static final String nameContest_4 = "Singleton Mayoral";
+ public static final List choicesContest_4 = List.of("MOORE Sue","THOMPSON Danny",
+ "JARRETT Tony","CHARLTON Belinda");
+ public static final int BallotCount_4 = 13755;
+ public static final double difficulty_4 = 12.118942731277533;
+ public static final String winnerContest_4 = "MOORE Sue";
+
+ // Contest City of Newcastle Mayoral
+ public static final String nameContest_5 = "City of Newcastle Mayoral";
+ public static final List choicesContest_5 = List.of("CHURCH John","NELMES Nuatali",
+ "HOLDING Rod","MACKENZIE John","O'BRIEN Steve","BARRIE Jenny");
+ public static final int BallotCount_5 = 100275;
+ public static final double difficulty_5 = 5.913487055493307;
+ public static final String winnerContest_5 = "NELMES Nuatali";
+
+ // Contest Nambucca Valley Mayoral
+ public static final String nameContest_6 = "Nambucca Valley Mayoral";
+ public static final List choicesContest_6 = List.of("JENVEY Susan","HOBAN Rhonda");
+ public static final int BallotCount_6 = 12482;
+ public static final double difficulty_6 = 2.7360806663743973;
+ public static final String winnerContest_6 = "HOBAN Rhonda";
+
+ // Contest City of Maitland Mayoral
+ public static final String nameContest_7 = "City of Maitland Mayoral";
+ public static final List choicesContest_7 = List.of("BROWN John","MITCHELL Ben",
+ "BAKER Loretta","PENFOLD Philip","SAFFARI Shahriar (Sean)","COOPER Michael","BURKE Brian");
+ public static final int BallotCount_7 = 54181;
+ public static final double difficulty_7 = 47.072980017376196;
+ public static final String winnerContest_7 = "PENFOLD Philip";
+
+ // Contest Kempsey Mayoral
+ public static final String nameContest_8 = "Kempsey Mayoral";
+ public static final List choicesContest_8 = List.of("HAUVILLE Leo","EVANS Andrew",
+ "BAIN Arthur","CAMPBELL Liz","SAUL Dean","IRWIN Troy","RAEBURN Bruce");
+ public static final int BallotCount_8 = 17585;
+ public static final double difficulty_8 = 45.43927648578811;
+ public static final String winnerContest_8 = "HAUVILLE Leo";
+
+ // Contest Canada Bay Mayoral
+ public static final String nameContest_9 = "Canada Bay Mayoral";
+ public static final List choicesContest_9 = List.of("TSIREKAS Angelo","LITTLE Julia",
+ "MEGNA Michael","JAGO Charles","RAMONDINO Daniela");
+ public static final int BallotCount_9 = 48542;
+ public static final double difficulty_9 = 8.140533288613113;
+ public static final String winnerContest_9 = "TSIREKAS Angelo";
+
+ // Contest Richmond Valley Mayoral
+ public static final String nameContest_10 = "Richmond Valley Mayoral";
+ public static final List choicesContest_10 = List.of("MUSTOW Robert","HAYES Robert");
+ public static final int BallotCount_10 = 13405;
+ public static final double difficulty_10 = 2.302868922865487;
+ public static final String winnerContest_10 = "MUSTOW Robert";
+
+ // Contest City of Sydney Mayoral
+ public static final String nameContest_11 = "City of Sydney Mayoral";
+ public static final List choicesContest_11 = List.of("VITHOULKAS Angela",
+ "WELDON Yvonne","SCOTT Linda","JARRETT Shauna","ELLSMORE Sylvie","MOORE Clover");
+ public static final int BallotCount_11 = 118511;
+ public static final double difficulty_11 = 3.6873366521468576;
+ public static final String winnerContest_11 = "MOORE Clover";
+
+ // Contest Byron Mayoral
+ public static final String nameContest_12 = "Byron Mayoral";
+ public static final List choicesContest_12 = List.of("HUNTER Alan","CLARKE Bruce",
+ "COOREY Cate","ANDERSON John","MCILRATH Christopher","LYON Michael","DEY Duncan",
+ "PUGH Asren","SWIVEL Mark");
+ public static final int BallotCount_12 = 18165;
+ public static final double difficulty_12 = 17.13679245283019;
+ public static final String winnerContest_12 = "LYON Michael";
+
+ // Contest City of Broken Hill Mayoral
+ public static final String nameContest_13 = "City of Broken Hill Mayoral";
+ public static final List choicesContest_13 = List.of("TURLEY Darriea","KENNEDY Tom",
+ "GALLAGHER Dave");
+ public static final int BallotCount_13 = 10812;
+ public static final double difficulty_13 = 3.2773567747802366;
+ public static final String winnerContest_13 = "KENNEDY Tom";
+
+ // Contest City of Shellharbour Mayoral
+ public static final String nameContest_14 = "City of Shellharbour Mayoral";
+ public static final List choicesContest_14 = List.of("HOMER Chris","SALIBA Marianne");
+ public static final int BallotCount_14 = 46273;
+ public static final double difficulty_14 = 17.83159922928709;
+ public static final String winnerContest_14 = "HOMER Chris";
+
+ // Contest City of Shoalhaven Mayoral
+ public static final String nameContest_15 = "City of Shoalhaven Mayoral";
+ public static final List choicesContest_15 = List.of("GREEN Paul","KITCHENER Mark",
+ "WHITE Patricia","WATSON Greg","DIGIGLIO Nina","FINDLEY Amanda");
+ public static final int BallotCount_15 = 67030;
+ public static final double difficulty_15 = 41.53035935563817;
+ public static final String winnerContest_15 = "FINDLEY Amanda";
+
+ // Contest Mosman Mayoral
+ public static final String nameContest_16 = "Mosman Mayoral";
+ public static final List choicesContest_16 = List.of("MOLINE Libby","BENDALL Roy",
+ "HARDING Sarah","CORRIGAN Carolyn","MENZIES Simon");
+ public static final int BallotCount_16 = 16425;
+ public static final double difficulty_16 = 4.498767460969598;
+ public static final String winnerContest_16 = "CORRIGAN Carolyn";
+
+ // Contest City of Orange Mayoral
+ public static final String nameContest_17 = "City of Orange Mayoral";
+ public static final List choicesContest_17 = List.of("HAMLING Jason","SPALDING Amanda",
+ "JONES Neil","WHITTON Jeffery","DUFFY Kevin","SMITH Lesley","MILETO Tony");
+ public static final int BallotCount_17 = 24355;
+ public static final double difficulty_17 = 50.01026694045174;
+ public static final String winnerContest_17 = "HAMLING Jason";
+
+ // Contest City of Wollongong Mayoral
+ public static final String nameContest_18 = "City of Wollongong Mayoral";
+ public static final List choicesContest_18 = List.of("GLYKIS Marie","DORAHY John",
+ "BROWN Tania","BRADBERY Gordon","ANTHONY Andrew","COX Mithra");
+ public static final int BallotCount_18 = 127240;
+ public static final double difficulty_18 = 47.72693173293323;
+ public static final String winnerContest_18 = "BRADBERY Gordon";
+
+ // Contest Port Stephens Mayoral
+ public static final String nameContest_19 = "Port Stephens Mayoral";
+ public static final List choicesContest_19 = List.of("ANDERSON Leah","PALMER Ryan");
+ public static final int BallotCount_19 = 47807;
+ public static final double difficulty_19 = 84.31569664902999;
+ public static final String winnerContest_19 = "PALMER Ryan";
+
+ // Contest Wollondilly Mayoral
+ public static final String nameContest_20 = "Wollondilly Mayoral";
+ public static final List choicesContest_20 = List.of("KHAN Robert","BANASIK Michael",
+ "DEETH Matthew","LAW Ray","GOULD Matt","HANNAN Judy");
+ public static final int BallotCount_20 = 31355;
+ public static final double difficulty_20 = 24.40077821011673;
+ public static final String winnerContest_20 = "GOULD Matt";
+
+ // Contest Hornsby Mayoral
+ public static final String nameContest_21 = "Hornsby Mayoral";
+ public static final List choicesContest_21 = List.of("HEYDE Emma","RUDDOCK Philip");
+ public static final int BallotCount_21 = 85656;
+ public static final double difficulty_21 = 6.866762866762866;
+ public static final String winnerContest_21 = "RUDDOCK Philip";
+
+ // Contest Ballina Mayoral
+ public static final String nameContest_22 = "Ballina Mayoral";
+ public static final List choicesContest_22 = List.of("WILLIAMS Keith","JOHNSON Jeff",
+ "MCCARTHY Steve","JOHNSTON Eoin","CADWALLADER Sharon");
+ public static final int BallotCount_22 = 26913;
+ public static final double difficulty_22 = 7.285598267460747;
+ public static final String winnerContest_22 = "CADWALLADER Sharon";
+
+ // Contest Bellingen Mayoral
+ public static final String nameContest_23 = "Bellingen Mayoral";
+ public static final List choicesContest_23 = List.of("ALLAN Steve","WOODWARD Andrew",
+ "KING Dominic");
+ public static final int BallotCount_23 = 8374;
+ public static final double difficulty_23 = 3.3335987261146496;
+ public static final String winnerContest_23 = "ALLAN Steve";
+
+ // Contest City of Lismore Mayoral
+ public static final String nameContest_24 = "City of Lismore Mayoral";
+ public static final List choicesContest_24 = List.of("KRIEG Steve","COOK Darlene",
+ "HEALEY Patrick","GRINDON-EKINS Vanessa","ROB Big","BIRD Elly");
+ public static final int BallotCount_24 = 26474;
+ public static final double difficulty_24 = 2.929836210712705;
+ public static final String winnerContest_24 = "KRIEG Steve";
+
+ // Contest City of Willoughby Mayoral
+ public static final String nameContest_25 = "City of Willoughby Mayoral";
+ public static final List choicesContest_25 = List.of("ROZOS Angelo","CAMPBELL Craig",
+ "TAYLOR Tanya");
+ public static final int BallotCount_25 = 37942;
+ public static final double difficulty_25 = 14.990912682734097;
+ public static final String winnerContest_25 = "TAYLOR Tanya";
+
+ // Contest The Hills Shire Mayoral
+ public static final String nameContest_26 = "The Hills Shire Mayoral";
+ public static final List choicesContest_26 = List.of("SHAHAMAT Vida","GANGEMI Peter",
+ "ROZYCKI Jerzy (George)","TRACEY Ryan","YAZDANI Ereboni (Alexia)");
+ public static final int BallotCount_26 = 105384;
+ public static final double difficulty_26 = 3.6801229221958374;
+ public static final String winnerContest_26 = "GANGEMI Peter";
+
+ // Contest City of Cessnock Mayoral
+ public static final String nameContest_27 = "City of Cessnock Mayoral";
+ public static final List choicesContest_27 = List.of("MURRAY Janet","SUVAAL Jay",
+ "MOORES John","OLSEN Ian");
+ public static final int BallotCount_27 = 36497;
+ public static final double difficulty_27 = 6.466513111268604;
+ public static final String winnerContest_27 = "SUVAAL Jay";
+
+ // Contest City of Griffith Mayoral
+ public static final String nameContest_28 = "City of Griffith Mayoral";
+ public static final List choicesContest_28 = List.of("MERCURI Rina","NAPOLI Anne",
+ "ZAPPACOSTA Dino","LA ROCCA Mariacarmina (Carmel)","CURRAN Doug");
+ public static final int BallotCount_28 = 14179;
+ public static final double difficulty_28 = 3.9320576816417083;
+ public static final String winnerContest_28 = "CURRAN Doug";
+
+ // Contest Port Macquarie-Hastings Mayoral
+ public static final String nameContest_29 = "Port Macquarie-Hastings Mayoral";
+ public static final List choicesContest_29 = List.of("PINSON Peta","GATES Steven",
+ "SHEPPARD Rachel","INTEMANN Lisa","LIPOVAC Nik");
+ public static final int BallotCount_29 = 54499;
+ public static final double difficulty_29 = 2.8524547262640008;
+ public static final String winnerContest_29 = "PINSON Peta";
+
+ // Contest City of Liverpool Mayoral
+ public static final String nameContest_30 = "City of Liverpool Mayoral";
+ public static final List choicesContest_30 = List.of("HAGARTY Nathan","MORSHED Asm",
+ "ANDJELKOVIC Milomir (Michael)","HARLE Peter","MANNOUN Ned");
+ public static final int BallotCount_30 = 115177;
+ public static final double difficulty_30 = 45.416798107255524;
+ public static final String winnerContest_30 = "MANNOUN Ned";
+
+ // Contest Uralla Mayoral
+ public static final String nameContest_31 = "Uralla Mayoral";
+ public static final List choicesContest_31 = List.of("BELL Robert","LEDGER Natasha",
+ "STRUTT Isabel");
+ public static final int BallotCount_31 = 3781;
+ public static final double difficulty_31 = 1.6297413793103448;
+ public static final String winnerContest_31 = "BELL Robert";
+
+ // Contest Hunter's Hill Mayoral
+ public static final String nameContest_32 = "Hunter's Hill Mayoral";
+ public static final List choicesContest_32 = List.of("GUAZZAROTTO David","MILES Zac",
+ "QUINN Richard","WILLIAMS Ross");
+ public static final int BallotCount_32 = 8356;
+ public static final double difficulty_32 = 38.330275229357795;
+ public static final String winnerContest_32 = "MILES Zac";
+
+ // Contest Burwood Mayoral
+ public static final String nameContest_33 = "Burwood Mayoral";
+ public static final List choicesContest_33 = List.of("HULL David","MURRAY Alan",
+ "CUTCHER Ned","FAKER John");
+ public static final int BallotCount_33 = 17797;
+ public static final double difficulty_33 = 2.5269061479483175;
+ public static final String winnerContest_33 = "FAKER John";
+
+ public static List expectedSolutionData = Arrays.asList(
+ new Expected(nameContest_1, choicesContest_1, BallotCount_1, difficulty_1, winnerContest_1),
+ new Expected(nameContest_2, choicesContest_2, BallotCount_2, difficulty_2, winnerContest_2),
+ new Expected(nameContest_3, choicesContest_3, BallotCount_3, difficulty_3, winnerContest_3),
+ new Expected(nameContest_4, choicesContest_4, BallotCount_4, difficulty_4, winnerContest_4),
+ new Expected(nameContest_5, choicesContest_5, BallotCount_5, difficulty_5, winnerContest_5),
+ new Expected(nameContest_6, choicesContest_6, BallotCount_6, difficulty_6, winnerContest_6),
+ new Expected(nameContest_7, choicesContest_7, BallotCount_7, difficulty_7, winnerContest_7),
+ new Expected(nameContest_8, choicesContest_8, BallotCount_8, difficulty_8, winnerContest_8),
+ new Expected(nameContest_9, choicesContest_9, BallotCount_9, difficulty_9, winnerContest_9),
+ new Expected(nameContest_10, choicesContest_10, BallotCount_10, difficulty_10, winnerContest_10),
+ new Expected(nameContest_11, choicesContest_11, BallotCount_11, difficulty_11, winnerContest_11),
+ new Expected(nameContest_12, choicesContest_12, BallotCount_12, difficulty_12, winnerContest_12),
+ new Expected(nameContest_13, choicesContest_13, BallotCount_13, difficulty_13, winnerContest_13),
+ new Expected(nameContest_14, choicesContest_14, BallotCount_14, difficulty_14, winnerContest_14),
+ new Expected(nameContest_15, choicesContest_15, BallotCount_15, difficulty_15, winnerContest_15),
+ new Expected(nameContest_16, choicesContest_16, BallotCount_16, difficulty_16, winnerContest_16),
+ new Expected(nameContest_17, choicesContest_17, BallotCount_17, difficulty_17, winnerContest_17),
+ new Expected(nameContest_18, choicesContest_18, BallotCount_18, difficulty_18, winnerContest_18),
+ new Expected(nameContest_19, choicesContest_19, BallotCount_19, difficulty_19, winnerContest_19),
+ new Expected(nameContest_20, choicesContest_20, BallotCount_20, difficulty_20, winnerContest_20),
+ new Expected(nameContest_21, choicesContest_21, BallotCount_21, difficulty_21, winnerContest_21),
+ new Expected(nameContest_22, choicesContest_22, BallotCount_22, difficulty_22, winnerContest_22),
+ new Expected(nameContest_23, choicesContest_23, BallotCount_23, difficulty_23, winnerContest_23),
+ new Expected(nameContest_24, choicesContest_24, BallotCount_24, difficulty_24, winnerContest_24),
+ new Expected(nameContest_25, choicesContest_25, BallotCount_25, difficulty_25, winnerContest_25),
+ new Expected(nameContest_26, choicesContest_26, BallotCount_26, difficulty_26, winnerContest_26),
+ new Expected(nameContest_27, choicesContest_27, BallotCount_27, difficulty_27, winnerContest_27),
+ new Expected(nameContest_28, choicesContest_28, BallotCount_28, difficulty_28, winnerContest_28),
+ new Expected(nameContest_29, choicesContest_29, BallotCount_29, difficulty_29, winnerContest_29),
+ new Expected(nameContest_30, choicesContest_30, BallotCount_30, difficulty_30, winnerContest_30),
+ new Expected(nameContest_31, choicesContest_31, BallotCount_31, difficulty_31, winnerContest_31),
+ new Expected(nameContest_32, choicesContest_32, BallotCount_32, difficulty_32, winnerContest_32),
+ new Expected(nameContest_33, choicesContest_33, BallotCount_33, difficulty_33, winnerContest_33)
+ );
+
+ /**
+ * Collected data about a contest that raire has solved
+ * @param contestName the name of the contest
+ * @param choices the candidate names
+ * @param ballotCount the total auditable ballots
+ * @param difficulty the expected difficulty
+ * @param winner the expected winner
+ */
+ public record Expected (
+ String contestName,
+ List choices,
+ int ballotCount,
+ double difficulty,
+ String winner
+ ) {}
+}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPITests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIErrorTests.java
similarity index 93%
rename from src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPITests.java
rename to src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIErrorTests.java
index 693b4840..aad3bff3 100644
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPITests.java
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIErrorTests.java
@@ -20,14 +20,13 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
package au.org.democracydevelopers.raireservice.controller;
-import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.TIMEOUT_CHECKING_WINNER;
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.WRONG_CANDIDATE_NAMES;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import au.org.democracydevelopers.raireservice.testUtils;
import org.apache.commons.lang3.StringUtils;
import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
@@ -46,24 +45,30 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
import org.springframework.test.annotation.DirtiesContext.ClassMode;
import org.springframework.test.context.ActiveProfiles;
-
/**
- * Tests for generate-assertions endpoint. This class automatically fires up the RAIRE Microservice
- * on a random port, then runs a series of (at this stage) very basic tests. Currently, we check for
- * proper input validation, and check that one valid trivial request succeeds.
+ * Tests for appropriate responses to bad requests to the generate-assertions endpoint. This class
+ * automatically fires up the RAIRE Microservice on a random port. Currently, we check for
+ * proper input validation.
* The list of tests is similar to GenerateAssertionsRequestTests.java, and also to
- * GetAssertionsAPITests.java when the same test is relevant to both endpoints. Note that you have
- * to run the *whole class*. Individual tests do not work separately because they don't
- * initiate the microservice on their own. Contests which will be used for validity testing are
- * pre-loaded into the database using src/test/resources/data.sql.
+ * GetAssertionsAPITests.java when the same test is relevant to both endpoints.
+ * Contests which will be used for validity testing are
+ * preloaded into the database using src/test/resources/data.sql.
+ * Tests include:
+ * - null, missing or whitespace contest name,
+ * - non-IRV contests, mixed IRV-plurality contests or contests not in the database,
+ * - null, missing or whitespace candidate names,
+ * - candidate names that are valid but do not include all the candidates mentioned in votes in the
+ * database,
+ * - missing, negative or zero values for numerical inputs (totalAuditableBallots and
+ * timeLimitSeconds).
*/
@ActiveProfiles("test-containers")
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GenerateAssertionsAPITests {
+public class GenerateAssertionsAPIErrorTests {
- private static final Logger logger = LoggerFactory.getLogger(GenerateAssertionsAPITests.class);
+ private static final Logger logger = LoggerFactory.getLogger(GenerateAssertionsAPIErrorTests.class);
private final static HttpHeaders httpHeaders = new HttpHeaders();
private final static String baseURL = "http://localhost:";
@@ -455,28 +460,23 @@ public void generateAssertionsWithNegativeTimeLimitIsAnError() {
}
/**
- * A test of the error responses. This test is a placeholder, which succeeds with the dummy
- * assertionGenerator currently implemented, but will need to be expanded to deal with real
- * error cases.
- * TODO when real AssertionGenerator class is implemented, write tests of each error state,
- * See Issue github.com/DemocracyDevelopers/raire-service/issues/65
- * e.g. tied winners. See Issue.
+ * A GenerateAssertions request with a candidate list that is valid, but the votes in the database
+ * contain at least one candidate who is not in the expected candidate list. This is an error.
*/
@Test
- @Disabled
- public void testErrorHeaderResponses() {
- testUtils.log(logger, "testErrorHeaderResponses");
+ public void wrongCandidatesIsAnError() {
+ testUtils.log(logger, "wrongCandidatesIsAnError");
String url = "http://localhost:" +port + generateAssertionsEndpoint;
String requestAsJson =
"{\"timeLimitSeconds\":10.0,\"totalAuditableBallots\":100,"
- +"\"contestName\":\"Ballina Mayoral\",\"candidates\":[\"Alice\",\"Bob\"]}";
+ +"\"contestName\":\"Ballina One Vote Contest\",\"candidates\":[\"Alice\",\"Bob\",\"Chuan\"]}";
HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
assertTrue(response.getStatusCode().is5xxServerError());
- assertEquals(TIMEOUT_CHECKING_WINNER.toString(),
+ assertEquals(WRONG_CANDIDATE_NAMES.toString(),
response.getHeaders().getFirst("error_code"));
}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIKnownTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIKnownTests.java
new file mode 100644
index 00000000..1cbdf4b9
--- /dev/null
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIKnownTests.java
@@ -0,0 +1,453 @@
+/*
+Copyright 2024 Democracy Developers
+
+The Raire Service is designed to connect colorado-rla and its associated database to
+the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
+
+This file is part of raire-service.
+
+raire-service is free software: you can redistribute it and/or modify it under the terms
+of the GNU Affero General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with
+raire-service. If not, see .
+*/
+
+package au.org.democracydevelopers.raireservice.controller;
+
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.ERROR_CODE_KEY;
+import static au.org.democracydevelopers.raireservice.testUtils.correctAssertionData;
+import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import au.org.democracydevelopers.raire.RaireSolution;
+import au.org.democracydevelopers.raire.algorithm.RaireResult;
+import au.org.democracydevelopers.raire.assertions.AssertionAndDifficulty;
+import au.org.democracydevelopers.raire.assertions.NotEliminatedBefore;
+import au.org.democracydevelopers.raireservice.request.GenerateAssertionsRequest;
+import au.org.democracydevelopers.raireservice.request.GetAssertionsRequest;
+import au.org.democracydevelopers.raireservice.response.GenerateAssertionsResponse;
+import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
+import au.org.democracydevelopers.raireservice.testUtils;
+import au.org.democracydevelopers.raireservice.util.DoubleComparator;
+import java.math.BigDecimal;
+import java.util.Arrays;
+import java.util.List;
+import java.util.Optional;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Tests to validate the behaviour of the Assertion generation API on a collection of simple contest with
+ * human-computable assertions. Relevant data is preloaded into the test database from
+ * src/test/resources/known_testcases_votes.sql.
+ * The test are a subset of those in GenerateAssertionsServiceKnownTests.java. They include
+ * - The examples from the Guide To Raire Vol 2. Exact matching for Ex. 2 and some for Ex. 1.
+ * - A cross-county version of the simple example.
+ * - A request for the simple example with twice the totalAuditableBallots as ballots in the database,
+ * to test that the diluted margin and difficulties change by a factor of 2, but absolute margin
+ * stays the same
+ * - A request for the simple example with fewer totalAuditableBallots than there are in the database,
+ * to check that there's an appropriate error response.
+ * Note for anyone comparing this directly with GenerateAssertionsServiceKnownTests: the
+ * test for wrong candidate names is in GenerateAssertionsAPIErrorTests, along with various other
+ * tests involving invalid request data.
+ * TODO The GenerateAssertionsServiceTest contains tests of proper overwriting when assertion
+ * generation is requested but assertions are already in the database. This is not yet complete in
+ * this class, pending a decision about how to block assertion regeneration when appropriate.
+ * See (https://github.com/DemocracyDevelopers/raire-service/issues/70)
+ * In each case, the test
+ * - makes a request for assertion generation through the API,
+ * - checks for the right winner,
+ * - requests the assertion data through the get-assertions API (JSON),
+ * - verifies the expected difficulty,
+ * and checks for the expected data.
+ */
+@ActiveProfiles("known-testcases")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureTestDatabase(replace = Replace.NONE)
+@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
+public class GenerateAssertionsAPIKnownTests {
+
+ private static final Logger logger = LoggerFactory.getLogger(GenerateAssertionsAPIKnownTests.class);
+ private final static String baseURL = "http://localhost:";
+ private final static String generateAssertionsEndpoint = "/raire/generate-assertions";
+
+ // Get assertions endpoint - used for testing that they were generated properly.
+ private final static String getAssertionsEndpoint = "/raire/get-assertions-json";
+ private static final int DEFAULT_TIME_LIMIT = 5;
+ private static final BigDecimal DEFAULT_RISK_LIMIT = BigDecimal.valueOf(0.03);
+ private static final DoubleComparator doubleComparator = new DoubleComparator();
+
+ @LocalServerPort
+ private int port;
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ /**
+ * Names of contests, to match preloaded data.
+ */
+ private static final String oneNEBAssertionContest = "Sanity Check NEB Assertion Contest";
+ private static final String oneNENAssertionContest = "Sanity Check NEN Assertion Contest";
+ private static final String NEBNENAssertionContest = "Sanity Check NEB NEN Assertion Contest";
+ private static final String ThreeAssertionContest = "Sanity Check 3 Assertion Contest";
+ private static final String guideToRaireExample1 = "Guide To Raire Example 1";
+ private static final String guideToRaireExample2 = "Guide To Raire Example 2";
+ private static final String simpleContest = "Simple Contest";
+ private static final String crossCountySimpleContest = "Cross-county Simple Contest";
+
+ /**
+ * Array of candidates: Alice, Bob, Chuan, Diego.
+ */
+ private static final String[] aliceBobChuanDiego = {"Alice", "Bob", "Chuan", "Diego"};
+
+ /**
+ * Array of candidates: Alice, Chuan, Bob.
+ */
+ private static final String[] aliceChuanBob = {"Alice", "Chuan", "Bob"};
+
+ /**
+ * Test the first example in the Guide to Raire Part 2.
+ * The test data has 1/500 of the votes, so divide margins by 500.
+ * The difficulties should be the same, because both numerator and denominator should be divided by 500.
+ * We do not test the NEN assertions because the ones in the Guide have some redundancy.
+ * Test assertion: Chuan NEB Bob.
+ * Margin is 4000, but data is divided by 500, so 8. Difficulty is 3.375 as in the Guide.
+ * Diluted margin is 8/27 = 0.296...
+ */
+ @Test
+ @Transactional
+ public void testGuideToRairePart2Example1() {
+ testUtils.log(logger, "testGuideToRairePart2Example1");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+
+ GenerateAssertionsRequest request = new GenerateAssertionsRequest(guideToRaireExample1,
+ 27, DEFAULT_TIME_LIMIT, Arrays.stream(aliceBobChuanDiego).toList());
+
+
+ // Request for the assertions to be generated.
+ ResponseEntity response = restTemplate.postForEntity(generateUrl,
+ request, GenerateAssertionsResponse.class);
+
+ // Check that generation is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), "Chuan");
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(guideToRaireExample1,
+ Arrays.stream(aliceBobChuanDiego).toList(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check for the right metadata
+ assertTrue(getResponse.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertTrue(correctMetadata(Arrays.stream(aliceBobChuanDiego).toList(), guideToRaireExample1,
+ DEFAULT_RISK_LIMIT, getResponse.getBody().metadata, Double.class));
+
+ // There should be one NEB assertion: Chaun NEB Bob
+ List assertions = Arrays.stream(getResponse.getBody().solution.Ok.assertions).toList();
+ Optional nebMaybeAssertion = assertions.stream()
+ .filter(a -> a.assertion instanceof NotEliminatedBefore).findFirst();
+ assertTrue(nebMaybeAssertion.isPresent());
+ assertTrue(correctAssertionData("NEB", 8, 27/8.0, 2,1, List.of(), 1.0,
+ nebMaybeAssertion.get()));
+ }
+
+ /**
+ * Exact matching of the assertions described in the Guide to Raire Example 2.
+ * The test data has 1/1000 of the votes, so divide margins by 1000.
+ * The difficulties should be the same, because both numerator and denominator should be divided by 1000.
+ */
+ @Test
+ @Transactional
+ void testGuideToRairePart2Example2() {
+ testUtils.log(logger, "testGuideToRairePart2Example2");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+ GenerateAssertionsRequest request = new GenerateAssertionsRequest(guideToRaireExample2,
+ 41, 5, Arrays.stream(aliceChuanBob).toList());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response
+ = restTemplate.postForEntity(generateUrl, request, GenerateAssertionsResponse.class);
+
+ // Check that the response is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), "Chuan");
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(guideToRaireExample2,
+ Arrays.stream(aliceChuanBob).toList(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check for the right metadata.
+ assertTrue(getResponse.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertTrue(correctMetadata(Arrays.stream(aliceChuanBob).toList(), guideToRaireExample2,
+ DEFAULT_RISK_LIMIT, getResponse.getBody().metadata, Double.class));
+
+ // Check for the right results: two assertions, margin 9 and difficulty 4.6.
+ RaireResult raireResult = getResponse.getBody().solution.Ok;
+ AssertionAndDifficulty[] assertions = raireResult.assertions;
+ assertEquals(9, raireResult.margin);
+ assertEquals(0, doubleComparator.compare(41.0/9, raireResult.difficulty));
+ checkGuideToRaireExample2Assertions(assertions);
+ }
+
+ /**
+ * Simple contest. The votes are
+ * 2 (A,B)
+ * 2 (B)
+ * 1 (C,A).
+ * The assertions should be
+ * A NEB C
+ * - Margin 1, diluted margin 1/5 = 0.2, difficulty 5/1 = 5.
+ * A NEN B | {A,B} continuing.
+ * - Margin 1, diluted margin 1/5 = 0.2, difficulty 5/1 = 5.
+ * Note that A NEB B is not true.
+ * This is the single-county case.
+ */
+ @Test
+ @Transactional
+ public void simpleContestSingleCounty() {
+ testUtils.log(logger, "simpleContestSingleCounty");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+
+ GenerateAssertionsRequest request = new GenerateAssertionsRequest(simpleContest,
+ 5, 5, Arrays.stream(aliceChuanBob).toList());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response
+ = restTemplate.postForEntity(generateUrl, request, GenerateAssertionsResponse.class);
+
+ // Check that the response is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), "Alice");
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(simpleContest,
+ Arrays.stream(aliceChuanBob).toList(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check for the right metadata.
+ assertTrue(getResponse.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertTrue(correctMetadata(Arrays.stream(aliceChuanBob).toList(), simpleContest,
+ DEFAULT_RISK_LIMIT, getResponse.getBody().metadata, Double.class));
+
+ // Check for the right results: two assertions, margin 9 and difficulty 4.6.
+ RaireResult raireResult = getResponse.getBody().solution.Ok;
+ AssertionAndDifficulty[] assertions = raireResult.assertions;
+ assertEquals(1, raireResult.margin);
+ assertEquals(0, doubleComparator.compare(5.0, raireResult.difficulty));
+ checkSimpleContestAssertions(assertions, 1);
+ }
+
+ /**
+ * The same simple contest, but across two counties. Nothing should change.
+ */
+ @Test
+ @Transactional
+ public void simpleContestCrossCounty() {
+ testUtils.log(logger, "simpleContestCrossCounty");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+
+ GenerateAssertionsRequest request = new GenerateAssertionsRequest(crossCountySimpleContest,
+ 5, 5, Arrays.stream(aliceChuanBob).toList());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response
+ = restTemplate.postForEntity(generateUrl, request, GenerateAssertionsResponse.class);
+
+ // Check that the response is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), "Alice");
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(crossCountySimpleContest,
+ Arrays.stream(aliceChuanBob).toList(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check for the right metadata.
+ assertTrue(getResponse.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertTrue(correctMetadata(Arrays.stream(aliceChuanBob).toList(), crossCountySimpleContest,
+ DEFAULT_RISK_LIMIT, getResponse.getBody().metadata, Double.class));
+
+ // Check for the right results: two assertions, margin 9 and difficulty 4.6.
+ RaireResult raireResult = getResponse.getBody().solution.Ok;
+ AssertionAndDifficulty[] assertions = raireResult.assertions;
+ assertEquals(1, raireResult.margin);
+ assertEquals(0, doubleComparator.compare(5.0, raireResult.difficulty));
+ checkSimpleContestAssertions(assertions, 1);
+ }
+
+ /**
+ * Single-county simple contest again.
+ * Doubling the totalAuditableBallots to 10 doubles the difficulty, and halves the diluted margin,
+ * but does not change the absolute margins.
+ * The actual test data is still the same, with 5 ballots - we just set totalAuditableBallots in
+ * the request to 10.
+ * We now have 10 totalAuditableBallots, so we expect:
+ * A NEB B: Margin 1, diluted margin 1/10 = 0.1, difficulty 10/1 = 10.
+ * A NEN B | {A,B} continuing: Margin 1, diluted margin 1/10 = 0.1, difficulty 10/1 = 10.
+ * Exactly the same as the simpleContest test above, but now we have 10 totalAuditableBallots
+ * and a difficultyFactor=2 in the call to checkSimpleContestAssertions.
+ */
+ @Test
+ @Transactional
+ public void simpleContestSingleCountyDoubleBallots() {
+ testUtils.log(logger, "simpleContestSingleCountyDoubleBallots");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+
+ // Tell raire that the totalAuditableBallots is double the number in the database
+ // for this contest.
+ GenerateAssertionsRequest request = new GenerateAssertionsRequest(simpleContest,
+ 10, 5, Arrays.stream(aliceChuanBob).toList());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response
+ = restTemplate.postForEntity(generateUrl, request, GenerateAssertionsResponse.class);
+
+ // Check that the response is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), "Alice");
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(simpleContest,
+ Arrays.stream(aliceChuanBob).toList(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check for the right metadata.
+ assertTrue(getResponse.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertTrue(correctMetadata(Arrays.stream(aliceChuanBob).toList(), simpleContest,
+ DEFAULT_RISK_LIMIT, getResponse.getBody().metadata, Double.class));
+
+ // Check for the right results: two assertions, margin 9 and difficulty 4.6.
+ RaireResult raireResult = getResponse.getBody().solution.Ok;
+ AssertionAndDifficulty[] assertions = raireResult.assertions;
+ assertEquals(1, raireResult.margin);
+ assertEquals(0, doubleComparator.compare(10.0, raireResult.difficulty));
+
+ // Difficulty factor 2 to match the doubled totalAuditableBallots.
+ checkSimpleContestAssertions(assertions, 2);
+ }
+
+ /**
+ * Insufficient totalAuditableBallots causes the right raire error to be returned.
+ * This test case has 5 ballots, so 2 totalAuditableBallots is an error.
+ */
+ @Test
+ @Transactional
+ public void simpleContestSingleCountyInsufficientBallotsError() {
+ testUtils.log(logger, "simpleContestSingleCountyInsufficientBallotsError");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+
+ GenerateAssertionsRequest notEnoughBallotsRequest = new GenerateAssertionsRequest(simpleContest,
+ 2, 5, Arrays.stream(aliceChuanBob).toList());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response
+ = restTemplate.postForEntity(generateUrl, notEnoughBallotsRequest, String.class);
+
+ assertTrue(response.getStatusCode().is5xxServerError());
+ assertEquals(RaireErrorCode.INVALID_TOTAL_AUDITABLE_BALLOTS.toString(),
+ response.getHeaders().getFirst(ERROR_CODE_KEY));
+ }
+
+ /**
+ * Check the data for the simple contests. Note that the winner and loser indices
+ * are dependent on the order of the input candidate list, which in all the test
+ * that use it are Alice, Chuan, Bob.
+ * @param assertionAndDifficulties the assertions returned by API
+ * @param difficultyFactor factor by which the difficulty should be multiplied (because of larger
+ * universe size).
+ */
+ private void checkSimpleContestAssertions(AssertionAndDifficulty[] assertionAndDifficulties,
+ double difficultyFactor) {
+ assertEquals(2, assertionAndDifficulties.length);
+ int nebIndex;
+
+ if(assertionAndDifficulties[0].assertion instanceof NotEliminatedBefore) {
+ nebIndex = 0;
+ } else {
+ nebIndex = 1;
+ }
+
+ // There should be one NEB assertion: Alice NEB Chuan
+ // Margin 1, diluted margin 0.2, difficulty 5.
+ assertTrue(correctAssertionData("NEB", 1, 5*difficultyFactor,
+ 0,1, List.of(), 1.0, assertionAndDifficulties[nebIndex]));
+
+ // There should be one NEN assertion: Chuan > Bob if only {Chuan,Bob} remain.
+ // Margin is 9,000, but data is divided by 1000, so 9. Difficulty is 41/9 = 4.5555...,
+ // rounded to 4.6 in the Guide.
+ // Diluted margin is 9/41 = 0.219512195...
+ assertTrue(correctAssertionData("NEN", 1, 5*difficultyFactor,
+ 0, 2, List.of(0,2), 1.0, assertionAndDifficulties[1-nebIndex]));
+ }
+
+ /**
+ * Checks for exact match with the Guide To Raire Part 2, example 2.
+ * Same as GenerateAssertionsServiceKnownTests::checkGuideToRaireExample2Assertions, except that
+ * it inputs an array of raire-java::AssertionAndDifficulty.
+ */
+ void checkGuideToRaireExample2Assertions(AssertionAndDifficulty[] assertionAndDifficulties) {
+ assertEquals(2, assertionAndDifficulties.length);
+ int nebIndex;
+
+ if(assertionAndDifficulties[0].assertion instanceof NotEliminatedBefore) {
+ nebIndex = 0;
+ } else {
+ nebIndex = 1;
+ }
+
+ // There should be one NEB assertion: Chaun NEB Alice
+ // Margin is 10,000, but data is divided by 1000, so 10. Difficulty is 4.1 as in the Guide.
+ // Diluted Margin is 10/41.
+ assertTrue(correctAssertionData("NEB", 10, 4.1,
+ 1,0, List.of(), 1.0, assertionAndDifficulties[nebIndex]));
+
+ // There should be one NEN assertion: Chuan > Bob if only {Chuan,Bob} remain.
+ // Margin is 9,000, but data is divided by 1000, so 9. Difficulty is 41/9 = 4.5555...,
+ // rounded to 4.6 in the Guide.
+ // Diluted margin is 9/41 = 0.219512195...
+ assertTrue(correctAssertionData("NEN", 9, 41.0/9,
+ 1, 2, List.of(1,2), 1.0, assertionAndDifficulties[1-nebIndex]));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPINSWTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPINSWTests.java
new file mode 100644
index 00000000..903aa2db
--- /dev/null
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPINSWTests.java
@@ -0,0 +1,119 @@
+/*
+Copyright 2024 Democracy Developers
+
+The Raire Service is designed to connect colorado-rla and its associated database to
+the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
+
+This file is part of raire-service.
+
+raire-service is free software: you can redistribute it and/or modify it under the terms
+of the GNU Affero General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with
+raire-service. If not, see .
+*/
+
+package au.org.democracydevelopers.raireservice.controller;
+
+import static au.org.democracydevelopers.raireservice.NSWValues.expectedSolutionData;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import au.org.democracydevelopers.raire.RaireSolution;
+import au.org.democracydevelopers.raireservice.NSWValues.Expected;
+import au.org.democracydevelopers.raireservice.request.GenerateAssertionsRequest;
+import au.org.democracydevelopers.raireservice.request.GetAssertionsRequest;
+import au.org.democracydevelopers.raireservice.response.GenerateAssertionsResponse;
+import au.org.democracydevelopers.raireservice.testUtils;
+import au.org.democracydevelopers.raireservice.util.DoubleComparator;
+import java.math.BigDecimal;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.test.context.junit.jupiter.EnabledIf;
+
+/**
+ * Tests to validate the behaviour of Assertion generation on NSW 2021 Mayoral election data.
+ * Data is loaded in from src/test/resources/NSW2021Data/
+ * These tests all pass, but can be disabled because loading in all the NSW data takes a long time.
+ */
+@ActiveProfiles("nsw-testcases")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureTestDatabase(replace = Replace.NONE)
+@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
+@EnabledIf(value = "${test-strategy.run-nsw-tests}", loadContext = true)
+public class GenerateAssertionsAPINSWTests {
+
+ private static final Logger logger = LoggerFactory.getLogger(GenerateAssertionsAPINSWTests.class);
+ private final static String baseURL = "http://localhost:";
+ private final static String generateAssertionsEndpoint = "/raire/generate-assertions";
+
+ // Get assertions endpoint - used for testing that they were generated properly.
+ private final static String getAssertionsEndpoint = "/raire/get-assertions-json";
+ private static final int DEFAULT_TIME_LIMIT = 5;
+ private static final BigDecimal DEFAULT_RISK_LIMIT = BigDecimal.valueOf(0.03);
+ private static final DoubleComparator doubleComparator = new DoubleComparator();
+
+ @LocalServerPort
+ private int port;
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ /**
+ * Iterate through all the NSW example data,
+ * - request assertion generation through the API,
+ * - check for the right winner,
+ * - request the assertion data through the get-assertions API (JSON)
+ * - verify the expected difficulty.
+ */
+ @Test
+ public void checkAllNSWByAPI() {
+ testUtils.log(logger, "checkAllNSWByAPI");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+ String getUrl = baseURL + port + getAssertionsEndpoint;
+
+ for(Expected expected : expectedSolutionData) {
+ testUtils.log(logger, "checkAllNSWByAPI: contest "+expected.contestName());
+ GenerateAssertionsRequest generateRequest = new GenerateAssertionsRequest(
+ expected.contestName(), expected.ballotCount(), DEFAULT_TIME_LIMIT, expected.choices());
+
+ // Request for the assertions to be generated.
+ ResponseEntity response = restTemplate.postForEntity(generateUrl,
+ generateRequest, GenerateAssertionsResponse.class);
+
+ // Check that generation is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(response.getBody());
+ assertEquals(response.getBody().winner(), expected.winner());
+
+ // Request the assertions
+ GetAssertionsRequest getRequest = new GetAssertionsRequest(expected.contestName(),
+ expected.choices(), DEFAULT_RISK_LIMIT);
+ ResponseEntity getResponse = restTemplate.postForEntity(getUrl, getRequest,
+ RaireSolution.class);
+
+ // Check that the retrieved assertions have the right overall difficulty.
+ assertTrue(response.getStatusCode().is2xxSuccessful());
+ assertNotNull(getResponse.getBody());
+ assertEquals(0, doubleComparator.compare(expected.difficulty(),
+ getResponse.getBody().solution.Ok.difficulty));
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIWickedTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIWickedTests.java
new file mode 100644
index 00000000..1a207c9d
--- /dev/null
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GenerateAssertionsAPIWickedTests.java
@@ -0,0 +1,166 @@
+/*
+Copyright 2024 Democracy Developers
+
+The Raire Service is designed to connect colorado-rla and its associated database to
+the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
+
+This file is part of raire-service.
+
+raire-service is free software: you can redistribute it and/or modify it under the terms
+of the GNU Affero General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with
+raire-service. If not, see .
+*/
+
+package au.org.democracydevelopers.raireservice.controller;
+
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.TIED_WINNERS;
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.TIMEOUT_CHECKING_WINNER;
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.TIMEOUT_FINDING_ASSERTIONS;
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.ERROR_CODE_KEY;
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import au.org.democracydevelopers.raireservice.request.GenerateAssertionsRequest;
+import au.org.democracydevelopers.raireservice.testUtils;
+import java.util.List;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Tests to validate the behavior of Assertion generation on a collection of particularly nasty
+ * test cases designed to elicit errors. These kinds of errors _are_ expected to happen occasionally
+ * in normal operation, if the input data is particularly challenging.
+ * This has the same tests as GenerateAssertionsServiceWickedTests.java. Relevant data is preloaded
+ * into the test database from src/test/resources/known_testcases_votes.sql.
+ * This includes
+ * - a contest with tied winners,
+ * - a contest that times out trying to find the winners (there are 20 and they are all tied),
+ * - a contest (Byron Mayor '21) that has enough candidates to time out generating assertions (when
+ * given a very short timeout).
+ */
+@ActiveProfiles("known-testcases")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureTestDatabase(replace = Replace.NONE)
+@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
+public class GenerateAssertionsAPIWickedTests {
+
+ private static final Logger logger = LoggerFactory.getLogger(
+ GenerateAssertionsAPIWickedTests.class);
+ private final static String baseURL = "http://localhost:";
+ private final static String generateAssertionsEndpoint = "/raire/generate-assertions";
+
+ /**
+ * Names of contests, to match preloaded data.
+ */
+ private static final String tiedWinnersContest = "Tied Winners Contest";
+ private static final String ByronMayoral = "Byron Mayoral";
+ private static final String timeOutCheckingWinnersContest = "Time out checking winners contest";
+
+ /**
+ * Candidate lists for the preloaded contests.
+ */
+ private static final List aliceChuanBob = List.of("Alice", "Chuan", "Bob");
+ private static final List choicesByron = List.of("HUNTER Alan", "CLARKE Bruce",
+ "COOREY Cate", "ANDERSON John", "MCILRATH Christopher", "LYON Michael", "DEY Duncan",
+ "PUGH Asren", "SWIVEL Mark");
+ private static final List timeoutCheckingWinnersChoices = List.of("A", "B", "C", "D", "E",
+ "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T");
+
+
+ /**
+ * The API requests appropriate for each preloaded contest. Those intended to produce a timeout
+ * have a particularly small timeLimit.
+ */
+ private final static GenerateAssertionsRequest tiedWinnersRequest
+ = new GenerateAssertionsRequest(tiedWinnersContest, 2, 5,
+ aliceChuanBob);
+ private final static GenerateAssertionsRequest ByronShortTimeoutRequest
+ = new GenerateAssertionsRequest(ByronMayoral, 18165, 0.001,
+ choicesByron);
+ private final static GenerateAssertionsRequest checkingWinnersTimeoutRequest
+ = new GenerateAssertionsRequest(timeOutCheckingWinnersContest, 20,
+ 0.001, timeoutCheckingWinnersChoices);
+
+ @LocalServerPort
+ private int port;
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ /**
+ * Tied winners results in raire-java returning a TiedWinners RaireError. This is a super-simple
+ * election with two candidates with one vote each.
+ */
+ @Test
+ @Transactional
+ void tiedWinnersGivesTiedWinnersError() {
+ testUtils.log(logger, "tiedWinnersGivesTiedWinnersError");
+
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+
+ // Request for the assertions to be generated.
+ ResponseEntity response = restTemplate.postForEntity(generateUrl, tiedWinnersRequest,
+ String.class);
+
+ // Check that generation is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is5xxServerError());
+ assertEquals(TIED_WINNERS.toString(), response.getHeaders().getFirst(ERROR_CODE_KEY));
+ }
+
+ /**
+ * A huge number of tied winners results in raire-java returning a TimeOutCheckingWinners
+ * error. This election has 20 candidates who are all tied.
+ */
+ @Test
+ @Transactional
+ void twentyTiedWinnersGivesTimeOutCheckingWinnersError() {
+ testUtils.log(logger, "twentyTiedWinnersGivesTimeOutCheckingWinnersError");
+
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+
+ // Request for the assertions to be generated.
+ ResponseEntity response = restTemplate.postForEntity(generateUrl,
+ checkingWinnersTimeoutRequest, String.class);
+
+ // Check that generation is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is5xxServerError());
+ assertEquals(TIMEOUT_CHECKING_WINNER.toString(), response.getHeaders().getFirst(ERROR_CODE_KEY));
+ }
+
+ /**
+ * Byron Mayoral times out generating assertions when given a very very short timeout.
+ */
+ @Test
+ @Transactional
+ void ByronWithShortTimeoutGivesTimeoutGeneratingAssertionsError() {
+ testUtils.log(logger, "ByronWithShortTimeoutGivesTimeoutGeneratingAssertionsError");
+ String generateUrl = baseURL + port + generateAssertionsEndpoint;
+
+ // Request for the assertions to be generated.
+ ResponseEntity response = restTemplate.postForEntity(generateUrl,
+ ByronShortTimeoutRequest, String.class);
+
+ // Check that generation is successful and we got the right winner.
+ assertTrue(response.getStatusCode().is5xxServerError());
+ assertEquals(TIMEOUT_FINDING_ASSERTIONS.toString(), response.getHeaders().getFirst(ERROR_CODE_KEY));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsCSVAPITests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPICsvTests.java
similarity index 86%
rename from src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsCSVAPITests.java
rename to src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPICsvTests.java
index d0956af1..d67bd7fc 100644
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsCSVAPITests.java
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPICsvTests.java
@@ -20,6 +20,8 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
package au.org.democracydevelopers.raireservice.controller;
+import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.WRONG_CANDIDATE_NAMES;
+import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
@@ -57,9 +59,9 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsCSVAPITests {
+public class GetAssertionsAPICsvTests {
- private static final Logger logger = LoggerFactory.getLogger(GetAssertionsCSVAPITests.class);
+ private static final Logger logger = LoggerFactory.getLogger(GetAssertionsAPICsvTests.class);
private final static HttpHeaders httpHeaders = new HttpHeaders();
private final static String baseURL = "http://localhost:";
@@ -69,7 +71,7 @@ public class GetAssertionsCSVAPITests {
= List.of("Annoying, Alice", "\"Breaking, Bob\"", "Challenging, Chuan", "O'Difficult, Diego");
private final static String trickyCharactersAsJson =
- "\"candidates\":[\"Annoying, Alice\",\"Breaking, Bob\",\"Challenging, Chuan\",\"O'Difficult, Diego\"]}";
+ "\"candidates\":[\"Annoying, Alice\",\"\\\"Breaking, Bob\\\"\",\"Challenging, Chuan\",\"O'Difficult, Diego\"]}";
@LocalServerPort
private int port;
@@ -88,8 +90,8 @@ public static void before() {
* maxima and minima have been manually computed to make sure they're correct.
*/
@Test
- public void testValidRequestWithNoAssertions() {
- testUtils.log(logger, "testValidRequestWithNoAssertions");
+ public void testValidRequestWithLotsOfTies() {
+ testUtils.log(logger, "testValidRequestWithLotsOfTies");
String url = baseURL + port + getAssertionsEndpoint;
String requestAsJson =
@@ -163,9 +165,8 @@ public void testCharacterEscapingForCSVExport() {
public void testCSVDemoContest() {
testUtils.log(logger, "testCSVDemoContest");
String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson =
- "{\"riskLimit\":0.10,\"contestName\":\"CSV Demo Contest\","
- + candidatesAsJson;
+ String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"CSV Demo Contest\","
+ + candidatesAsJson;
HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
@@ -191,4 +192,23 @@ public void testCSVDemoContest() {
"2,NEN,Diego,Chuan,\"Alice,Chuan,Diego\",6.1,100,0.1,0.05,45,45,0,0,0,0,0\n"
));
}
+
+ /**
+ * A request with candidates who are inconsistent with the assertions in the database is an error.
+ */
+ @Test
+ public void wrongCandidatesIsAnError() {
+ testUtils.log(logger, "wrongCandidatesIsAnError");
+ String url = baseURL + port + getAssertionsEndpoint;
+
+ String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"CSV Demo Contest\","
+ + "\"candidates\":[\"Alicia\",\"Boba\",\"Chuan\",\"Diego\"]}";
+
+ HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
+ ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
+
+ assertTrue(response.getStatusCode().is5xxServerError());
+ assertEquals(WRONG_CANDIDATE_NAMES.toString(),
+ response.getHeaders().getFirst("error_code"));
+ }
}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTestsJsonAndCsv.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorJsonAndCsvTests.java
similarity index 99%
rename from src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTestsJsonAndCsv.java
rename to src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorJsonAndCsvTests.java
index 20c13142..6c4475a3 100644
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTestsJsonAndCsv.java
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorJsonAndCsvTests.java
@@ -60,9 +60,9 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsAPIErrorTestsJsonAndCsv {
+public class GetAssertionsAPIErrorJsonAndCsvTests {
- private static final Logger logger = LoggerFactory.getLogger(GetAssertionsAPIErrorTestsJsonAndCsv.class);
+ private static final Logger logger = LoggerFactory.getLogger(GetAssertionsAPIErrorJsonAndCsvTests.class);
private final static HttpHeaders httpHeaders = new HttpHeaders();
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTests.java
deleted file mode 100644
index 8d25ead0..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIErrorTests.java
+++ /dev/null
@@ -1,399 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.controller;
-
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.Objects;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.HttpStatusCode;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-import org.apache.commons.lang3.StringUtils;
-
-/**
- * Tests for get-assertions endpoint. This class automatically fires up the RAIRE Microservice on a random
- * port, then runs a series of (at this stage) very basic tests. Currently we check for proper input
- * validation, and check that one valid trivial request succeeds for each endpoint.
- * The list of tests is similar to GetAssertionsRequestTests.java, and also to GenerateAssertionsAPITests.java
- * when the same test is relevant to both endpoints.
- * Note that you have to run the *whole class*. Individual tests do not work separately because they don't
- * initiate the microservice on their own.
- * Contests which will be used for validity testing are preloaded into the database using
- * src/test/resources/data.sql.
- */
-@ActiveProfiles("test-containers")
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsAPIErrorTests {
-
- private static final Logger logger = LoggerFactory.getLogger(GetAssertionsAPIErrorTests.class);
-
- private final static HttpHeaders httpHeaders = new HttpHeaders();
-
- private final static String baseURL = "http://localhost:";
- private final static String getAssertionsEndpoint = "/raire/get-assertions-json";
-
- @LocalServerPort
- private int port;
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @BeforeAll
- public static void before() {
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- }
-
-
- /**
- * A valid request for a contest that exists but has no assertions. Returns the correct error
- * code and message.
- */
- @Test
- public void testValidRequestWithNoAssertions() {
- testUtils.log(logger, "testValidRequestWithNoAssertions");
- String url = "http://localhost:" + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Ballina Mayoral\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is5xxServerError());
- assertEquals(RaireErrorCode.NO_ASSERTIONS_PRESENT.toString(),
- Objects.requireNonNull(response.getHeaders().get("error_code")).getFirst());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(),
- "No assertions have been generated for the contest"));
- }
-
- /**
- * This is really just a test that the testing is working. There's no mapping for the plain
- * localhost response, so when the microservice is running it just returns a default error. We
- * check for 404.
- */
- @Test
- public void testErrorForNonFunctioningEndpoint() {
- testUtils.log(logger, "testErrorForNonFunctioningEndpoint");
- ResponseEntity response = restTemplate.postForEntity(baseURL + port + "/",
- new HttpEntity<>("", httpHeaders), String.class);
- assertTrue(response.getStatusCode().isSameCodeAs(HttpStatusCode.valueOf(404)));
- }
-
- /**
- * Calling the getAssertions endpoint with no header and no data produces an error.
- */
- @Test
- public void getAssertionsNoBodyError() {
- testUtils.log(logger, "getAssertionsNoBodyError");
- ResponseEntity response = restTemplate.postForEntity(baseURL + port +
- getAssertionsEndpoint, new HttpEntity<>("", new HttpHeaders()), String.class);
- assertTrue(response.getStatusCode().is4xxClientError());
- }
-
- /**
- * The getAssertions endpoint, with correct headers but no data, should produce "Bad Request".
- */
- @Test
- public void testGetAssertionsBadRequest() {
- testUtils.log(logger, "testGetAssertionsBadRequest");
- String url = baseURL + port + getAssertionsEndpoint;
-
- HttpEntity request = new HttpEntity<>("", httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(Objects.requireNonNull(response.getBody()).contains("Bad Request"));
- }
-
- /**
- * The getAssertions endpoint, called with a nonexistent contest, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithNonExistentContestIsAnError() {
- testUtils.log(logger, "getAssertionsWithNonExistentContestIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Nonexistent Contest\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "No such contest"));
-
- }
-
- /**
- * The getAssertions endpoint, called with a valid plurality contest, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithPluralityContestIsAnError() {
- testUtils.log(logger, "getAssertionsWithPluralityContestIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Valid Plurality Contest\","
- +"\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Not comprised of all IRV"));
- }
-
- /**
- * The getAssertions endpoint, called with a mixed IRV and non-IRV contest, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithMixedIRVPluralityContestIsAnError() {
- testUtils.log(logger, "getAssertionsWithMixedIRVPluralityContestIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Invalid Mixed Contest\","
- +"\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Not comprised of all IRV"));
-
- }
-
- /**
- * The getAssertions endpoint, called with a missing contest name, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithMissingContestNameIsAnError() {
- testUtils.log(logger, "getAssertionsWithMissingContestNameIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.05,\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "No contest name"));
- }
-
- /**
- * The getAssertions endpoint, called with a null contest name, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithNullContestNameIsAnError() {
- testUtils.log(logger, "getAssertionsWithNullContestNameIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.05,\"contestName\":null,\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "No contest name"));
- }
-
- /**
- * The getAssertions endpoint, called with an empty contest name, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithEmptyContestNameIsAnError() {
- testUtils.log(logger, "getAssertionsWithEmptyContestNameIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.05,\"contestName\":\"\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "No contest name"));
- }
-
- /**
- * The getAssertions endpoint, called with an all-whitespace contest name, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithWhitespaceContestNameIsAnError() {
- testUtils.log(logger, "getAssertionsWithWhitespaceContestNameIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\" \",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "No contest name"));
- }
-
- /**
- * The getAssertions endpoint, called with a missing candidate list, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithMissingCandidateListIsAnError() {
- testUtils.log(logger, "getAssertionsWithMissingCandidateListIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.05,\"contestName\":\"Ballina Mayoral\"}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Bad candidate list"));
- }
-
- /**
- * The getAssertions endpoint, called with a null candidate list, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithNullCandidateListIsAnError() {
- testUtils.log(logger, "getAssertionsWithNullCandidateListIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Ballina Mayoral\",\"candidates\":null}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Bad candidate list"));
- }
-
- /**
- * The getAssertions endpoint, called with an empty candidate list, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithEmptyCandidateListIsAnError() {
- testUtils.log(logger, "getAssertionsWithEmptyCandidateListIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Ballina Mayoral\",\"candidates\":[]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Bad candidate list"));
- }
-
- /**
- * The getAssertions endpoint, called with a whitespace candidate name, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithWhitespaceCandidateNameIsAnError() {
- testUtils.log(logger, "getAssertionsWithWhitespaceCandidateNameIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"Ballina Mayoral\","
- +"\"candidates\":[\"Alice\",\" \"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Bad candidate list"));
- }
-
- /**
- * The getAssertions endpoint, called with a missing risk limit, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithMissingRiskLimitIsAnError() {
- testUtils.log(logger, "getAssertionsWithMissingRiskLimitIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"contestName\":\"Ballina Mayoral\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Null or negative risk limit"));
- }
-
- /**
- * The getAssertions endpoint, called with a null risk limit, returns a meaningful error.
- */
- @Test
- public void getAssertionsWithNullRiskLimitIsAnError() {
- testUtils.log(logger, "getAssertionsWithNullRiskLimitIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":null,\"contestName\":\"Ballina Mayoral\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Null or negative risk limit"));
- }
-
- /**
- * The getAssertions endpoint, called with a negative risk limit, returns a meaningful error.
- * (Note that a value >=1 is vacuously met but not invalid.)
- */
- @Test
- public void getAssertionsWithNegativeRiskLimitIsAnError() {
- testUtils.log(logger, "getAssertionsWithNegativeRiskLimitIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":-0.05,\"contestName\":\"Ballina Mayoral\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is4xxClientError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(), "Null or negative risk limit"));
- }
-}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsJson.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIJsonTests.java
similarity index 76%
rename from src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsJson.java
rename to src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIJsonTests.java
index ea3fa4a1..26950601 100644
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsJson.java
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsAPIJsonTests.java
@@ -21,14 +21,19 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
package au.org.democracydevelopers.raireservice.controller;
import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.WRONG_CANDIDATE_NAMES;
-import static au.org.democracydevelopers.raireservice.testUtils.correctIndexedAPIAssertionData;
+import static au.org.democracydevelopers.raireservice.testUtils.correctAssertionData;
import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
import static au.org.democracydevelopers.raireservice.testUtils.correctSolutionData;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertFalse;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
+import au.org.democracydevelopers.raire.RaireSolution;
+import au.org.democracydevelopers.raireservice.request.GetAssertionsRequest;
import au.org.democracydevelopers.raireservice.testUtils;
+import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;
@@ -65,10 +70,10 @@ the raire assertion generation engine (https://github.com/DemocracyDevelopers/ra
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@AutoConfigureTestDatabase(replace = Replace.NONE)
@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsValidAPIRequestTestsJson {
+public class GetAssertionsAPIJsonTests {
private static final Logger logger = LoggerFactory.getLogger(
- GetAssertionsValidAPIRequestTestsJson.class);
+ GetAssertionsAPIJsonTests.class);
private final static HttpHeaders httpHeaders = new HttpHeaders();
private final static String baseURL = "http://localhost:";
@@ -92,8 +97,8 @@ public static void before() {
/**
- * The getAssertions endpoint, valid request. Currently just checking that the serialization correctly
- * ignores time_to_find_assertions.
+ * The getAssertions endpoint, valid request. Currently just checking that the serialization
+ * correctly ignores time_to_find_assertions.
*/
@Test
public void getAssertionsWithOneNEBContest() {
@@ -119,26 +124,26 @@ void retrieveAssertionsExistentContestOneNEBAssertion() {
testUtils.log(logger, "retrieveAssertionsExistentContestOneNEBAssertion");
String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\"]}";
+ // Make the request.
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNEBAssertionContest,
+ List.of("Alice","Bob"), BigDecimal.valueOf(0.1));
+ ResponseEntity response
+ = restTemplate.postForEntity(url, request, RaireSolution.class);
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest, 0.1,
- response.getBody()));
+ // The metadata has been constructed appropriately.
+ assertNotNull(response.getBody());
+ assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest, BigDecimal.valueOf(0.1),
+ response.getBody().metadata, Double.class));
// The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
+ assertNull(response.getBody().solution.Err);
// Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(320,1.1, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEB", 320, 1.1, 0,
- 1, new ArrayList<>(), 1.0, response.getBody(),0));
+ assertTrue(correctSolutionData(320,1.1, 1, response.getBody().solution.Ok));
+ // We expect one NEB assertion with the following data.
+ assertTrue(correctAssertionData("NEB", 320, 1.1, 0,
+ 1, new ArrayList<>(), 1.0, response.getBody().solution.Ok.assertions[0]));
}
/**
@@ -150,25 +155,24 @@ void retrieveAssertionsExistentContestOneNENAssertion() {
testUtils.log(logger, "retrieveAssertionsExistentContestOneNENAssertion");
String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNENAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNENAssertionContest,
+ List.of("Alice","Bob","Charlie","Diego"),BigDecimal.valueOf(0.1));
+ ResponseEntity response = restTemplate.postForEntity(url, request, RaireSolution.class);
// The metadata has been constructed appropriately
+ assertNotNull(response.getBody());
assertTrue(correctMetadata(List.of("Alice","Bob","Charlie","Diego"),oneNENAssertionContest,
- 0.1, response.getBody()));
+ BigDecimal.valueOf(0.1), response.getBody().metadata, Double.class));
// The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
+ assertNull(response.getBody().solution.Err);
// Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(240, 3.01, 1, response.getBody()));
+ assertTrue(correctSolutionData(240, 3.01, 1, response.getBody().solution.Ok));
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEN",240,3.01, 0,
- 2, List.of(0,1,3,2), 1.0, response.getBody(),0));
+ // We expect one NEN assertion with the following data.
+ assertTrue(correctAssertionData("NEN",240,3.01, 0,
+ 2, List.of(0,1,3,2), 1.0, response.getBody().solution.Ok.assertions[0]));
}
/**
@@ -182,11 +186,10 @@ void retrieveAssertionsIncorrectCandidateNamesIsAnError() {
testUtils.log(logger, "retrieveAssertionsIncorrectCandidateNamesIsAnError");
String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBOneNENAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNEBOneNENAssertionContest,
+ List.of("Alice","Bob","Charlie","Diego"),BigDecimal.valueOf(0.1));
+ ResponseEntity response
+ = restTemplate.postForEntity(url, request, String.class);
assertTrue(response.getStatusCode().is5xxServerError());
assertTrue(StringUtils.containsIgnoreCase(response.getBody(),
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressAPIJsonAndCsvTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressAPIJsonAndCsvTests.java
new file mode 100644
index 00000000..14c5f5c5
--- /dev/null
+++ b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressAPIJsonAndCsvTests.java
@@ -0,0 +1,309 @@
+/*
+Copyright 2024 Democracy Developers
+
+The Raire Service is designed to connect colorado-rla and its associated database to
+the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
+
+This file is part of raire-service.
+
+raire-service is free software: you can redistribute it and/or modify it under the terms
+of the GNU Affero General Public License as published by the Free Software Foundation, either
+version 3 of the License, or (at your option) any later version.
+
+raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
+without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
+See the GNU Affero General Public License for more details.
+
+You should have received a copy of the GNU Affero General Public License along with
+raire-service. If not, see .
+*/
+
+package au.org.democracydevelopers.raireservice.controller;
+
+import static au.org.democracydevelopers.raireservice.testUtils.correctAssertionData;
+import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
+import static au.org.democracydevelopers.raireservice.testUtils.correctSolutionData;
+import static org.junit.jupiter.api.Assertions.assertNotNull;
+import static org.junit.jupiter.api.Assertions.assertNull;
+import static org.junit.jupiter.api.Assertions.assertTrue;
+
+import au.org.democracydevelopers.raire.RaireSolution;
+import au.org.democracydevelopers.raireservice.request.GetAssertionsRequest;
+import au.org.democracydevelopers.raireservice.testUtils;
+import java.math.BigDecimal;
+import java.util.ArrayList;
+import java.util.List;
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import org.slf4j.Logger;
+import org.slf4j.LoggerFactory;
+import org.springframework.beans.factory.annotation.Autowired;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
+import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
+import org.springframework.boot.test.context.SpringBootTest;
+import org.springframework.boot.test.web.client.TestRestTemplate;
+import org.springframework.boot.test.web.server.LocalServerPort;
+import org.springframework.http.HttpEntity;
+import org.springframework.http.HttpHeaders;
+import org.springframework.http.MediaType;
+import org.springframework.http.ResponseEntity;
+import org.springframework.test.annotation.DirtiesContext;
+import org.springframework.test.annotation.DirtiesContext.ClassMode;
+import org.springframework.test.context.ActiveProfiles;
+import org.springframework.transaction.annotation.Transactional;
+
+/**
+ * Tests for get-assertions endpoint. This class automatically fires up the RAIRE Microservice on a
+ * random port, then runs a series of tests for correct responses to valid requests.
+ * The list of tests is similar to - and in most cases identical to - the tests in
+ * GetAssertionsInProgressServiceTestsJsonAndCsv.java.
+ * Contests which will be used for validity testing are preloaded into the database using
+ * src/test/resources/data.sql.
+ */
+@ActiveProfiles("assertions-in-progress")
+@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
+@AutoConfigureTestDatabase(replace = Replace.NONE)
+@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
+public class GetAssertionsInProgressAPIJsonAndCsvTests {
+
+ private static final Logger logger = LoggerFactory.getLogger(
+ GetAssertionsInProgressAPIJsonAndCsvTests.class);
+
+ private final static HttpHeaders httpHeaders = new HttpHeaders();
+ private final static String baseURL = "http://localhost:";
+ private final static String getAssertionsJsonEndpoint = "/raire/get-assertions-json";
+ private final static String getAssertionsCsvEndpoint = "/raire/get-assertions-csv";
+ private final static String oneNEBAssertionContest = "One NEB Assertion Contest";
+ private final static String oneNENAssertionContest = "One NEN Assertion Contest";
+ private final static String oneNEBOneNENAssertionContest = "One NEN NEB Assertion Contest";
+
+ @LocalServerPort
+ private int port;
+
+ @Autowired
+ private TestRestTemplate restTemplate;
+
+ @BeforeAll
+ public static void before() {
+ httpHeaders.setContentType(MediaType.APPLICATION_JSON);
+ }
+
+
+ /**
+ * Retrieve assertions for a contest that has one NEB assertion (audit in progress). (JSON)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsExistentContestOneNEBAssertionJSON() {
+ testUtils.log(logger, "retrieveAssertionsExistentContestOneNEBAssertionJSON");
+ String url = baseURL + port + getAssertionsJsonEndpoint;
+
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNEBAssertionContest,
+ List.of("Alice","Bob"), BigDecimal.valueOf(0.1));
+
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ RaireSolution.class);
+
+ // The metadata has been constructed appropriately
+ assertNotNull(response.getBody());
+ assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest,
+ BigDecimal.valueOf(0.1), response.getBody().metadata, Double.class));
+
+ // The RaireSolution contains a RaireResultOrError, but the error should be null.
+ assertNull(response.getBody().solution.Err);
+
+ // Check the contents of the RaireResults within the RaireSolution.
+ assertTrue(correctSolutionData(320,1.1, 1,
+ response.getBody().solution.Ok));
+
+ // We expect one NEB assertion with the following data.
+ assertTrue(correctAssertionData("NEB", 320, 1.1, 0, 1,
+ new ArrayList<>(), 0.5, response.getBody().solution.Ok.assertions[0]));
+
+ }
+
+ /**
+ * Retrieve assertions for a contest that has one NEB assertion (audit in progress). (CSV)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsExistentContestOneNEBAssertionCSV() {
+ testUtils.log(logger, "retrieveAssertionsExistentContestOneNEBAssertionCSV");
+ String url = baseURL + port + getAssertionsCsvEndpoint;
+
+ String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
+ oneNEBAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\"]}";
+
+ HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
+ String csv = restTemplate.postForEntity(url, request, String.class).getBody();
+
+ assertNotNull(csv);
+ assertTrue(csv.contains("Contest name,One NEB Assertion Contest\n"));
+ assertTrue(csv.contains("Candidates,\"Alice,Bob\""));
+ assertTrue(csv.contains("Extreme item,Value,Assertion IDs\n"));
+ assertTrue(csv.contains("Margin,320,\"1\"\n"));
+ assertTrue(csv.contains("Diluted margin,0.32,\"1\"\n"));
+ assertTrue(csv.contains("Raire difficulty,1.1,\"1\"\n"));
+ assertTrue(csv.contains("Current risk,0.50,\"1\"\n"));
+ assertTrue(csv.contains("Optimistic samples to audit,111,\"1\"\n"));
+ assertTrue(csv.contains("Estimated samples to audit,111,\"1\"\n"));
+ assertTrue(csv.contains(
+ "ID,Type,Winner,Loser,Assumed continuing,Difficulty,Margin,Diluted margin,Risk,"
+ + "Estimated samples to audit,Optimistic samples to audit,Two vote over count,"
+ + "One vote over count,Other discrepancy count,One vote under count,"
+ + "Two vote under count\n"));
+ assertTrue(csv.contains("1,NEB,Alice,Bob,,1.1,320,0.32,0.50,111,111,0,0,0,0,0\n"));
+ }
+
+ /**
+ * Retrieve assertions for a contest that has one NEN assertion (audit in progress). (JSON)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsExistentContestOneNENAssertionJSON() {
+ testUtils.log(logger, "retrieveAssertionsExistentContestOneNENAssertionJSON");
+ String url = baseURL + port + getAssertionsJsonEndpoint;
+
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNENAssertionContest,
+ List.of("Alice","Bob","Charlie","Diego"), BigDecimal.valueOf(0.1));
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ RaireSolution.class);
+
+ // The metadata has been constructed appropriately
+ assertNotNull(response.getBody());
+ assertTrue(
+ correctMetadata(List.of("Alice", "Bob", "Charlie", "Diego"), oneNENAssertionContest,
+ BigDecimal.valueOf(0.1), response.getBody().metadata, Double.class));
+
+ // The RaireSolution contains a RaireResultOrError, but the error should be null.
+ assertNull(response.getBody().solution.Err);
+
+ // Check the contents of the RaireResults within the RaireSolution.
+ assertTrue(correctSolutionData(240, 3.01, 1,
+ response.getBody().solution.Ok));
+
+ // We expect one assertion with the following data.
+ assertTrue(correctAssertionData("NEN", 240, 3.01, 0, 2,
+ List.of(0, 1, 3, 2), 0.2, response.getBody().solution.Ok.assertions[0]));
+ }
+
+ /**
+ * Retrieve assertions for a contest that has one NEN assertion (audit in progress). (CSV)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsExistentContestOneNENAssertionCSV() {
+ testUtils.log(logger, "retrieveAssertionsExistentContestOneNENAssertionCSV");
+ String url = baseURL + port + getAssertionsCsvEndpoint;
+
+ String requestAsJson =
+ "{\"riskLimit\":0.10,\"contestName\":\"" + oneNENAssertionContest
+ + "\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
+
+ HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
+ String csv = restTemplate.postForEntity(url, request, String.class).getBody();
+
+ assertNotNull(csv);
+ assertTrue(csv.contains("Contest name,One NEN Assertion Contest\n"));
+ assertTrue(csv.contains("Candidates,\"Alice,Bob,Charlie,Diego\""));
+ assertTrue(csv.contains("Extreme item,Value,Assertion IDs\n"));
+ assertTrue(csv.contains("Margin,240,\"1\"\n"));
+ assertTrue(csv.contains("Diluted margin,0.12,\"1\"\n"));
+ assertTrue(csv.contains("Raire difficulty,3.01,\"1\"\n"));
+ assertTrue(csv.contains("Current risk,0.20,\"1\"\n"));
+ assertTrue(csv.contains("Optimistic samples to audit,201,\"1\"\n"));
+ assertTrue(csv.contains("Estimated samples to audit,245,\"1\"\n"));
+ assertTrue(csv.contains(
+ "ID,Type,Winner,Loser,Assumed continuing,Difficulty,Margin,Diluted margin,Risk,"
+ + "Estimated samples to audit,Optimistic samples to audit,Two vote over count,"
+ + "One vote over count,Other discrepancy count,One vote under count,"
+ + "Two vote under count\n"));
+ assertTrue(csv.contains(
+ "1,NEN,Alice,Charlie,\"Alice,Charlie,Diego,Bob\",3.01,240,0.12,0.20,245,201,0,1,2,0,0\n"
+ ));
+ }
+
+ /**
+ * Retrieve assertions for a contest that has one NEN and one NEB assertion (audit in progress).
+ * (JSON)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsOneNENOneNEBAssertionInProgressJSON() {
+ testUtils.log(logger, "retrieveAssertionsOneNENOneNEBAssertionInProgressJSON");
+ String url = baseURL + port + getAssertionsJsonEndpoint;
+
+ // Make the request.
+ GetAssertionsRequest request = new GetAssertionsRequest(oneNEBOneNENAssertionContest,
+ List.of("Liesl","Wendell","Amanda","Chuan"), BigDecimal.valueOf(0.05));
+ ResponseEntity response = restTemplate.postForEntity(url, request,
+ RaireSolution.class);
+
+ // The metadata has been constructed appropriately.
+ assertNotNull(response.getBody());
+ assertTrue(correctMetadata(List.of("Liesl", "Wendell", "Amanda", "Chuan"),
+ oneNEBOneNENAssertionContest, BigDecimal.valueOf(0.05), response.getBody().metadata,
+ Double.class));
+
+ // The RaireSolution contains a RaireResultOrError, but the error should be null.
+ assertNull(response.getBody().solution.Err);
+
+ // Check the contents of the RaireResults within the RaireSolution.
+ assertTrue(correctSolutionData(112, 3.17, 2,
+ response.getBody().solution.Ok));
+
+ // We expect two assertions with the following data, but we don't necessarily know what order
+ // they're in. So check for their presence at either position.
+ assertTrue(
+ correctAssertionData("NEB", 112, 0.1, 2, 0,
+ new ArrayList<>(), 0.08, response.getBody().solution.Ok.assertions[0]) ||
+ correctAssertionData("NEB", 112, 0.1, 2, 0,
+ new ArrayList<>(), 0.08, response.getBody().solution.Ok.assertions[1])
+ );
+
+ assertTrue(
+ correctAssertionData("NEN", 560, 3.17, 2, 1,
+ List.of(0, 1, 2), 0.7, response.getBody().solution.Ok.assertions[0]) ||
+ correctAssertionData("NEN", 560, 3.17, 2, 1,
+ List.of(0, 1, 2), 0.7, response.getBody().solution.Ok.assertions[1])
+ );
+ }
+
+ /**
+ * Retrieve assertions for a contest that has one NEN and one NEB assertion (audit in progress).
+ * (CSV)
+ */
+ @Test
+ @Transactional
+ void retrieveAssertionsOneNENOneNEBAssertionInProgressCSV() {
+ testUtils.log(logger, "retrieveAssertionsOneNENOneNEBAssertionInProgressCSV");
+ String url = baseURL + port + getAssertionsCsvEndpoint;
+
+ String requestAsJson =
+ "{\"riskLimit\":0.05,\"contestName\":\"" + oneNEBOneNENAssertionContest
+ + "\",\"candidates\":[\"Liesl\",\"Wendell\",\"Amanda\",\"Chuan\"]}";
+
+ HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
+ String csv = restTemplate.postForEntity(url, request, String.class).getBody();
+
+ assertNotNull(csv);
+ assertTrue(csv.contains("Contest name,One NEN NEB Assertion Contest\n"));
+ assertTrue(csv.contains("Candidates,\"Liesl,Wendell,Amanda,Chuan\""));
+ assertTrue(csv.contains("Extreme item,Value,Assertion IDs\n"));
+ assertTrue(csv.contains("Margin,112,\"1\"\n"));
+ assertTrue(csv.contains("Diluted margin,0.1,\"1\"\n"));
+ assertTrue(csv.contains("Raire difficulty,3.17,\"2\"\n"));
+ assertTrue(csv.contains("Current risk,0.70,\"2\"\n"));
+ assertTrue(csv.contains("Optimistic samples to audit,200,\"2\"\n"));
+ assertTrue(csv.contains("Estimated samples to audit,300,\"2\"\n"));
+ assertTrue(csv.contains(
+ "ID,Type,Winner,Loser,Assumed continuing,Difficulty,Margin,Diluted margin,Risk,"
+ + "Estimated samples to audit,Optimistic samples to audit,Two vote over count,"
+ + "One vote over count,Other discrepancy count,One vote under count,"
+ + "Two vote under count\n"));
+ assertTrue(csv.contains("1,NEB,Amanda,Liesl,,0.1,112,0.1,0.08,27,20,2,0,0,1,0\n"));
+ assertTrue(csv.contains(
+ "2,NEN,Amanda,Wendell,\"Liesl,Wendell,Amanda\",3.17,560,0.5,0.70,300,200,0,2,0,0,1\n"
+ ));
+ }
+}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTests.java
deleted file mode 100644
index 7e338bfa..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTests.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.controller;
-
-import static au.org.democracydevelopers.raireservice.testUtils.correctIndexedAPIAssertionData;
-import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
-import static au.org.democracydevelopers.raireservice.testUtils.correctSolutionData;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Tests for get-assertions endpoint. This class automatically fires up the RAIRE Microservice on a random
- * port, then runs a series of tests for correct responses to valid requests.
- * The list of tests is similar to - and in most cases identical to - the GetAssertionsJsonServiceTests.
- * Note that you have to run the *whole class*. Individual tests do not work separately because they don't
- * initiate the microservice on their own.
- * Contests which will be used for validity testing are pre-loaded into the database using
- * src/test/resources/data.sql.
- */
-@ActiveProfiles("assertions-in-progress")
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsInProgressValidAPIRequestTests {
-
- private static final Logger logger = LoggerFactory.getLogger(
- GetAssertionsInProgressValidAPIRequestTests.class);
-
- private final static HttpHeaders httpHeaders = new HttpHeaders();
- private final static String baseURL = "http://localhost:";
- private final static String getAssertionsJsonEndpoint = "/raire/get-assertions-json";
- private final static String oneNEBAssertionContest = "One NEB Assertion Contest";
- private final static String oneNENAssertionContest = "One NEN Assertion Contest";
- private final static String oneNEBOneNENAssertionContest = "One NEN NEB Assertion Contest";
-
- @LocalServerPort
- private int port;
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @BeforeAll
- public static void before() {
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- }
-
-
- /**
- * Retrieve assertions for a contest that has one NEB assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonExistentContestOneNEBAssertion() {
- testUtils.log(logger, "retrieveAssertionsAsJsonExistentContestOneNEBAssertion");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest, 0.1,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(320,1.1, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEB", 320, 1.1, 0,
- 1, new ArrayList<>(), 0.5, response.getBody(),0));
-
- }
-
- /**
- * Retrieve assertions for a contest that has one NEN assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonExistentContestOneNENAssertion() {
- testUtils.log(logger, "retrieveAssertionsAsJsonExistentContestOneNENAssertion");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.10,\"contestName\":\"" + oneNENAssertionContest
- + "\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(
- correctMetadata(List.of("Alice", "Bob", "Charlie", "Diego"), oneNENAssertionContest, 0.1,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(240, 3.01, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEN", 240, 3.01, 0, 2,
- List.of(0, 1, 3, 2), 0.2, response.getBody(), 0));
- }
-
- /**
- * Retrieve assertions for a contest that has one NEN and one NEB assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonOneNENOneNEBAssertionInProgress() {
- testUtils.log(logger, "retrieveAssertionsAsJsonOneNENOneNEBAssertionInProgress");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"" + oneNEBOneNENAssertionContest
- + "\",\"candidates\":[\"Liesl\",\"Wendell\",\"Amanda\",\"Chuan\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Liesl", "Wendell", "Amanda", "Chuan"),
- oneNEBOneNENAssertionContest, 0.05,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(112, 3.17, 2, response.getBody()));
-
- // We expect two assertions with the following data, but we don't necessarily know what order they're in.
- // So check for their presence at either position.
- assertTrue(
- correctIndexedAPIAssertionData("NEB", 112, 0.1, 2, 0,
- new ArrayList<>(), 0.08, response.getBody(), 0) ||
- correctIndexedAPIAssertionData("NEB", 112, 0.1, 2, 0,
- new ArrayList<>(), 0.08, response.getBody(), 1)
- );
-
- assertTrue(
- correctIndexedAPIAssertionData("NEN", 560, 3.17, 2, 1,
- List.of(0, 1, 2), 0.7, response.getBody(), 0) ||
- correctIndexedAPIAssertionData("NEN", 560, 3.17, 2, 1,
- List.of(0, 1, 2), 0.7, response.getBody(), 1)
- );
- }
-}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTestsJsonAndCsv.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTestsJsonAndCsv.java
deleted file mode 100644
index 779ff335..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsInProgressValidAPIRequestTestsJsonAndCsv.java
+++ /dev/null
@@ -1,195 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.controller;
-
-import static au.org.democracydevelopers.raireservice.testUtils.correctIndexedAPIAssertionData;
-import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
-import static au.org.democracydevelopers.raireservice.testUtils.correctSolutionData;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.ArrayList;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Tests for get-assertions endpoint. This class automatically fires up the RAIRE Microservice on a random
- * port, then runs a series of tests for correct responses to valid requests.
- * The list of tests is similar to - and in most cases identical to - the GetAssertionsJsonServiceTests.
- * Note that you have to run the *whole class*. Individual tests do not work separately because they don't
- * initiate the microservice on their own.
- * Contests which will be used for validity testing are pre-loaded into the database using
- * src/test/resources/data.sql.
- */
-@ActiveProfiles("assertions-in-progress")
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsInProgressValidAPIRequestTestsJsonAndCsv {
-
- private static final Logger logger = LoggerFactory.getLogger(
- GetAssertionsInProgressValidAPIRequestTestsJsonAndCsv.class);
-
- private final static HttpHeaders httpHeaders = new HttpHeaders();
- private final static String baseURL = "http://localhost:";
- private final static String getAssertionsJsonEndpoint = "/raire/get-assertions-json";
- private final static String oneNEBAssertionContest = "One NEB Assertion Contest";
- private final static String oneNENAssertionContest = "One NEN Assertion Contest";
- private final static String oneNEBOneNENAssertionContest = "One NEN NEB Assertion Contest";
-
- @LocalServerPort
- private int port;
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @BeforeAll
- public static void before() {
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- }
-
-
- /**
- * Retrieve assertions for a contest that has one NEB assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonExistentContestOneNEBAssertion() {
- testUtils.log(logger, "retrieveAssertionsAsJsonExistentContestOneNEBAssertion");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest, 0.1,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(320,1.1, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEB", 320, 1.1, 0,
- 1, new ArrayList<>(), 0.5, response.getBody(),0));
-
- }
-
- /**
- * Retrieve assertions for a contest that has one NEN assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonExistentContestOneNENAssertion() {
- testUtils.log(logger, "retrieveAssertionsAsJsonExistentContestOneNENAssertion");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.10,\"contestName\":\"" + oneNENAssertionContest
- + "\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(
- correctMetadata(List.of("Alice", "Bob", "Charlie", "Diego"), oneNENAssertionContest, 0.1,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(240, 3.01, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEN", 240, 3.01, 0, 2,
- List.of(0, 1, 3, 2), 0.2, response.getBody(), 0));
- }
-
- /**
- * Retrieve assertions for a contest that has one NEN and one NEB assertion (audit in progress).
- */
- @Test
- @Transactional
- void retrieveAssertionsAsJsonOneNENOneNEBAssertionInProgress() {
- testUtils.log(logger, "retrieveAssertionsAsJsonOneNENOneNEBAssertionInProgress");
- String url = baseURL + port + getAssertionsJsonEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.05,\"contestName\":\"" + oneNEBOneNENAssertionContest
- + "\",\"candidates\":[\"Liesl\",\"Wendell\",\"Amanda\",\"Chuan\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Liesl", "Wendell", "Amanda", "Chuan"),
- oneNEBOneNENAssertionContest, 0.05,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(112, 3.17, 2, response.getBody()));
-
- // We expect two assertions with the following data, but we don't necessarily know what order they're in.
- // So check for their presence at either position.
- assertTrue(
- correctIndexedAPIAssertionData("NEB", 112, 0.1, 2, 0,
- new ArrayList<>(), 0.08, response.getBody(), 0) ||
- correctIndexedAPIAssertionData("NEB", 112, 0.1, 2, 0,
- new ArrayList<>(), 0.08, response.getBody(), 1)
- );
-
- assertTrue(
- correctIndexedAPIAssertionData("NEN", 560, 3.17, 2, 1,
- List.of(0, 1, 2), 0.7, response.getBody(), 0) ||
- correctIndexedAPIAssertionData("NEN", 560, 3.17, 2, 1,
- List.of(0, 1, 2), 0.7, response.getBody(), 1)
- );
- }
-}
\ No newline at end of file
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTests.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTests.java
deleted file mode 100644
index f9990347..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTests.java
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.controller;
-
-import static au.org.democracydevelopers.raireservice.testUtils.correctIndexedAPIAssertionData;
-import static au.org.democracydevelopers.raireservice.testUtils.correctMetadata;
-import static au.org.democracydevelopers.raireservice.testUtils.correctSolutionData;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertFalse;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode;
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.ArrayList;
-import java.util.List;
-import java.util.Objects;
-import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Tests for get-assertions endpoint. This class automatically fires up the RAIRE Microservice on a
- * random port, then runs a series of tests for correct responses to valid requests.
- * The list of tests is similar to - and in most cases identical to - the GetAssertionsJsonServiceTests.
- * Note that you have to run the *whole class*. Individual tests do not work separately because they
- * don't initiate the microservice on their own.
- * Contests which will be used for validity testing are preloaded into the database using
- * src/test/resources/data.sql.
- */
-@ActiveProfiles("simple-assertions")
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsValidAPIRequestTests {
-
- private static final Logger logger = LoggerFactory.getLogger(
- GetAssertionsValidAPIRequestTests.class);
-
- private final static HttpHeaders httpHeaders = new HttpHeaders();
- private final static String baseURL = "http://localhost:";
- private final static String getAssertionsEndpoint = "/raire/get-assertions-json";
-
- private final static String oneNEBAssertionContest = "One NEB Assertion Contest";
- private final static String oneNENAssertionContest = "One NEN Assertion Contest";
- private final static String oneNEBOneNENAssertionContest = "One NEN NEB Assertion Contest";
-
-
- @LocalServerPort
- private int port;
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @BeforeAll
- public static void before() {
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- }
-
-
- /**
- * The getAssertions endpoint, valid request. Currently just checking that the serialization correctly
- * ignores time_to_find_assertions.
- */
- @Test
- public void getAssertionsWithOneNEBContest() {
- testUtils.log(logger, "getAssertionsWithOneNEBContest");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.05,\"contestName\":\"" + oneNEBAssertionContest
- +"\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is2xxSuccessful());
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "time_to_find_assertions"));
- }
-
- /**
- * Retrieve assertions for a contest that has one NEB assertion.
- */
- @Test
- @Transactional
- void retrieveAssertionsExistentContestOneNEBAssertion() {
- testUtils.log(logger, "retrieveAssertionsExistentContestOneNEBAssertion");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Alice","Bob"), oneNEBAssertionContest, 0.1,
- response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(320,1.1, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEB", 320, 1.1, 0,
- 1, new ArrayList<>(), 1.0, response.getBody(),0));
-
- }
-
- /**
- * Retrieve assertions for a contest that has one NEN assertion.
- */
- @Test
- @Transactional
- void retrieveAssertionsExistentContestOneNENAssertion() {
- testUtils.log(logger, "retrieveAssertionsExistentContestOneNENAssertion");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNENAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- // The metadata has been constructed appropriately
- assertTrue(correctMetadata(List.of("Alice","Bob","Charlie","Diego"),oneNENAssertionContest,
- 0.1, response.getBody()));
-
- // The RaireSolution contains a RaireResultOrError, but the error should be null.
- assertFalse(StringUtils.containsIgnoreCase(response.getBody(), "Error"));
-
- // Check the contents of the RaireResults within the RaireSolution.
- assertTrue(correctSolutionData(240, 3.01, 1, response.getBody()));
-
- // We expect one assertion with the following data.
- assertTrue(correctIndexedAPIAssertionData("NEN",240,3.01, 0,
- 2, List.of(0,1,3,2), 1.0, response.getBody(),0));
- }
-
- /**
- * Retrieve assertions for a contest where the request has been set up with incorrect
- * candidate names for the given contest.
- * This is a valid request in the sense that it passes Request.Validate(), but should later fail.
- */
- @Test
- @Transactional
- void retrieveAssertionsIncorrectCandidateNamesIsAnError() {
- testUtils.log(logger, "retrieveAssertionsIncorrectCandidateNamesIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"" +
- oneNEBOneNENAssertionContest+"\",\"candidates\":[\"Alice\",\"Bob\",\"Charlie\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is5xxServerError());
- assertTrue(StringUtils.containsIgnoreCase(response.getBody(),
- "candidate list provided as parameter is inconsistent"));
- assertEquals(RaireErrorCode.INTERNAL_ERROR.toString(),
- Objects.requireNonNull(response.getHeaders().get("error_code")).getFirst());
- }
-}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsCsv.java b/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsCsv.java
deleted file mode 100644
index ab7ee16d..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/controller/GetAssertionsValidAPIRequestTestsCsv.java
+++ /dev/null
@@ -1,213 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.controller;
-
-import static au.org.democracydevelopers.raireservice.service.RaireServiceException.RaireErrorCode.WRONG_CANDIDATE_NAMES;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertNotNull;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.List;
-import org.apache.commons.lang3.StringUtils;
-import org.junit.jupiter.api.BeforeAll;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.boot.test.web.client.TestRestTemplate;
-import org.springframework.boot.test.web.server.LocalServerPort;
-import org.springframework.http.HttpEntity;
-import org.springframework.http.HttpHeaders;
-import org.springframework.http.MediaType;
-import org.springframework.http.ResponseEntity;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-
-/**
- * Tests for get-assertions endpoint with the csv request. This class automatically fires up the
- * RAIRE Microservice on a random port, then runs a series of tests.
- * The tests are essentially the same as those in GetAssertionsCSVTests.java, but we're checking for
- * correct API output rather than checking the service directly.
- * Contests which will be used for validity testing are preloaded into the database using
- * src/test/resources/simple_assertions_csv_challenges.sql.
- */
-@ActiveProfiles("csv-challenges")
-@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-public class GetAssertionsValidAPIRequestTestsCsv {
-
- private static final Logger logger = LoggerFactory.getLogger(GetAssertionsValidAPIRequestTestsCsv.class);
-
- private final static HttpHeaders httpHeaders = new HttpHeaders();
- private final static String baseURL = "http://localhost:";
- private final static String getAssertionsEndpoint = "/raire/get-assertions-csv";
- private final static String candidatesAsJson = "\"candidates\":[\"Alice\",\"Bob\",\"Chuan\",\"Diego\"]}";
- private final static List trickyCharacters
- = List.of("Annoying, Alice", "\"Breaking, Bob\"", "Challenging, Chuan", "O'Difficult, Diego");
-
- private final static String trickyCharactersAsJson =
- "\"candidates\":[\"Annoying, Alice\",\"\\\"Breaking, Bob\\\"\",\"Challenging, Chuan\",\"O'Difficult, Diego\"]}";
-
- @LocalServerPort
- private int port;
-
-
- @Autowired
- private TestRestTemplate restTemplate;
-
- @BeforeAll
- public static void before() {
- httpHeaders.setContentType(MediaType.APPLICATION_JSON);
- }
-
- /**
- * Test proper csv file generation of assertions when those assertions have lots of ties. These
- * maxima and minima have been manually computed to make sure they're correct.
- */
- @Test
- public void testValidRequestWithNoAssertions() {
- testUtils.log(logger, "testValidRequestWithNoAssertions");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson =
- "{\"riskLimit\":0.10,\"contestName\":\"Lots of assertions with ties Contest\","
- + candidatesAsJson;
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is2xxSuccessful());
- String output = response.getBody();
-
- assertNotNull(output);
- assertTrue(output.contains("Contest name, Lots of assertions with ties Contest\n"));
- assertTrue(output.contains("Candidates, \"Alice, Bob, Chuan, Diego\"\n\n"));
- assertTrue(output.contains("Extreme item, Value, Assertion IDs"));
- assertTrue(output.contains("Margin, 220, \"2, 5, 6\""));
- assertTrue(output.contains("Diluted margin, 0.22, \"2, 5, 6\""));
- assertTrue(output.contains("Raire difficulty, 3.1, 3"));
- assertTrue(output.contains("Current risk, 0.23, \"2, 3\""));
- assertTrue(output.contains("Optimistic samples to audit, 910, 4"));
- assertTrue(output.contains("Estimated samples to audit, 430, \"2, 5\"\n\n"));
- assertTrue(output.contains(
- "ID, Type, Winner, Loser, Assumed continuing, Difficulty, Margin, Diluted margin, Risk, "
- + "Estimated samples to audit, Optimistic samples to audit, Two vote over count, "
- + "One vote over count, Other discrepancy count, One vote under count, "
- + "Two vote under count\n"
- ));
- assertTrue(output.contains("1, NEB, Alice, Bob, , 2.1, 320, 0.32, 0.04, 110, 100, 0, 0, 0, 0, 0\n"));
- assertTrue(output.contains("2, NEB, Chuan, Bob, , 1.1, 220, 0.22, 0.23, 430, 200, 0, 0, 0, 0, 0\n"));
- assertTrue(output.contains("3, NEB, Diego, Chuan, , 3.1, 320, 0.32, 0.23, 50, 110, 0, 0, 0, 0, 0\n"));
- assertTrue(output.contains(
- "4, NEN, Alice, Bob, \"Alice, Bob, Chuan\", 2.0, 420, 0.42, 0.04, 320, 910, 0, 0, 0, 0, 0\n"
- ));
- assertTrue(output.contains(
- "5, NEN, Alice, Diego, \"Alice, Diego\", 1.1, 220, 0.22, 0.07, 430, 210, 0, 0, 0, 0, 0\n"
- ));
- assertTrue(output.contains(
- "6, NEN, Alice, Bob, \"Alice, Bob, Diego\", 1.2, 220, 0.22, 0.04, 400, 110, 0, 0, 0, 0, 0\n"
- ));
- }
-
- /**
- * Test for difficult characters in candidate names, including ' and " and ,
- */
- @Test
- public void testCharacterEscapingForCSVExport() {
- testUtils.log(logger, "testCharacterEscapingForCSVExport");
- String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson =
- "{\"riskLimit\":0.10,\"contestName\":\"Lots of tricky characters Contest\","
- + trickyCharactersAsJson;
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is2xxSuccessful());
- String output = response.getBody();
-
- assertNotNull(output);
- assertTrue(StringUtils.containsIgnoreCase(output, trickyCharacters.get(0)));
- assertTrue(StringUtils.containsIgnoreCase(output, trickyCharacters.get(1)));
- assertTrue(StringUtils.containsIgnoreCase(output, trickyCharacters.get(2)));
- assertTrue(StringUtils.containsIgnoreCase(output, trickyCharacters.get(3)));
- }
-
- /**
- * A simple test for correct generation on a simple test case with one assertion of each type.
- */
- @Test
- public void testCSVDemoContest() {
- testUtils.log(logger, "testCSVDemoContest");
- String url = baseURL + port + getAssertionsEndpoint;
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"CSV Demo Contest\","
- + candidatesAsJson;
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
- String output = response.getBody();
-
- assertNotNull(output);
- assertTrue(output.contains("Contest name, CSV Demo Contest\n"));
- assertTrue(output.contains("Candidates, \"Alice, Bob, Chuan, Diego\"\n\n"));
- assertTrue(output.contains("Extreme item, Value, Assertion IDs\n"));
- assertTrue(output.contains("Margin, 100, 2\n"));
- assertTrue(output.contains("Diluted margin, 0.1, 2\n"));
- assertTrue(output.contains("Raire difficulty, 6.1, 2\n"));
- assertTrue(output.contains("Current risk, 0.06, 1\n"));
- assertTrue(output.contains("Optimistic samples to audit, 45, 2\n"));
- assertTrue(output.contains("Estimated samples to audit, 55, 1\n"));
- assertTrue(output.contains(
- "ID, Type, Winner, Loser, Assumed continuing, Difficulty, Margin, Diluted margin, Risk, "
- + "Estimated samples to audit, Optimistic samples to audit, Two vote over count, "
- + "One vote over count, Other discrepancy count, One vote under count, "
- + "Two vote under count\n"));
- assertTrue(output.contains("1, NEB, Bob, Alice, , 5.1, 112, 0.112, 0.06, 55, 35, 0, 2, 0, 0, 0\n"));
- assertTrue(output.contains(
- "2, NEN, Diego, Chuan, \"Alice, Chuan, Diego\", 6.1, 100, 0.1, 0.05, 45, 45, 0, 0, 0, 0, 0\n"
- ));
- }
-
- /**
- * A request with candidates who are inconsistent with the assertions in the database is an error.
- */
- @Test
- public void wrongCandidatesIsAnError() {
- testUtils.log(logger, "wrongCandidatesIsAnError");
- String url = baseURL + port + getAssertionsEndpoint;
-
- String requestAsJson = "{\"riskLimit\":0.10,\"contestName\":\"CSV Demo Contest\","
- + "\"candidates\":[\"Alicia\",\"Boba\",\"Chuan\",\"Diego\"]}";
-
- HttpEntity request = new HttpEntity<>(requestAsJson, httpHeaders);
- ResponseEntity response = restTemplate.postForEntity(url, request, String.class);
-
- assertTrue(response.getStatusCode().is5xxServerError());
- assertEquals(WRONG_CANDIDATE_NAMES.toString(),
- response.getHeaders().getFirst("error_code"));
- }
-}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/persistence/repository/AssertionRepositoryInProgressTests.java b/src/test/java/au/org/democracydevelopers/raireservice/persistence/repository/AssertionRepositoryInProgressTests.java
index 540e6af3..d409588f 100644
--- a/src/test/java/au/org/democracydevelopers/raireservice/persistence/repository/AssertionRepositoryInProgressTests.java
+++ b/src/test/java/au/org/democracydevelopers/raireservice/persistence/repository/AssertionRepositoryInProgressTests.java
@@ -107,7 +107,7 @@ void retrieveAssertionsOneNEBAssertionConvert() throws RaireServiceException {
assertEquals(1, ((NotEliminatedBefore)aad.assertion).loser);
// Check that current risk is 0.5
- assertEquals(0, BigDecimal.valueOf(0.50).compareTo(
+ assertEquals(0, BigDecimal.valueOf(0.5).compareTo(
((BigDecimal)aad.status.get(Metadata.STATUS_RISK))));
}
@@ -131,7 +131,7 @@ void retrieveAssertionsOneNENAssertionInProgress() throws RaireServiceException
"Alice", "Charlie", List.of("Alice", "Charlie", "Diego", "Bob"),
Map.of(13L, 1, 14L, 0, 15L, 0), 245,
201, 0, 0, 1,
- 0, 2, BigDecimal.valueOf(0.20),
+ 0, 2, BigDecimal.valueOf(0.2),
"One NEN Assertion Contest", r));
}
@@ -161,7 +161,7 @@ void retrieveAssertionsOneNENOneNEBAssertionInProgress() throws RaireServiceExce
"Amanda", "Wendell", List.of("Liesl", "Wendell", "Amanda"),
Map.of(13L, 1, 14L, 1, 15L, -2), 300,
200, 1, 0, 2,
- 0, 0, BigDecimal.valueOf(0.70),
+ 0, 0, BigDecimal.valueOf(0.7),
"One NEN NEB Assertion Contest", r2));
}
}
diff --git a/src/test/java/au/org/democracydevelopers/raireservice/service/GenerateAssertionsOnNSWTests.java b/src/test/java/au/org/democracydevelopers/raireservice/service/GenerateAssertionsOnNSWTests.java
deleted file mode 100644
index 2a5e048e..00000000
--- a/src/test/java/au/org/democracydevelopers/raireservice/service/GenerateAssertionsOnNSWTests.java
+++ /dev/null
@@ -1,1662 +0,0 @@
-/*
-Copyright 2024 Democracy Developers
-
-The Raire Service is designed to connect colorado-rla and its associated database to
-the raire assertion generation engine (https://github.com/DemocracyDevelopers/raire-java).
-
-This file is part of raire-service.
-
-raire-service is free software: you can redistribute it and/or modify it under the terms
-of the GNU Affero General Public License as published by the Free Software Foundation, either
-version 3 of the License, or (at your option) any later version.
-
-raire-service is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY;
-without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
-See the GNU Affero General Public License for more details.
-
-You should have received a copy of the GNU Affero General Public License along with
-raire-service. If not, see .
-*/
-
-package au.org.democracydevelopers.raireservice.service;
-
-
-import static au.org.democracydevelopers.raireservice.testUtils.difficultyMatchesMax;
-import static org.junit.jupiter.api.Assertions.assertEquals;
-import static org.junit.jupiter.api.Assertions.assertTrue;
-
-import au.org.democracydevelopers.raire.RaireSolution.RaireResultOrError;
-import au.org.democracydevelopers.raireservice.persistence.entity.Assertion;
-import au.org.democracydevelopers.raireservice.persistence.repository.AssertionRepository;
-import au.org.democracydevelopers.raireservice.persistence.repository.CVRContestInfoRepository;
-import au.org.democracydevelopers.raireservice.request.GenerateAssertionsRequest;
-import au.org.democracydevelopers.raireservice.testUtils;
-import java.util.List;
-import org.junit.jupiter.api.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.springframework.beans.factory.annotation.Autowired;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase;
-import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace;
-import org.springframework.boot.test.context.SpringBootTest;
-import org.springframework.test.annotation.DirtiesContext;
-import org.springframework.test.annotation.DirtiesContext.ClassMode;
-import org.springframework.test.context.ActiveProfiles;
-import org.springframework.test.context.junit.jupiter.EnabledIf;
-import org.springframework.transaction.annotation.Transactional;
-
-/**
- * Tests to validate the behaviour of Assertion generation on NSW 2021 Mayoral election data.
- * Data is loaded in from src/test/resources/NSW2021Data/
- * These tests all pass, but are disabled because loading in all the NSW data takes a long time.
- */
-@ActiveProfiles("nsw-testcases")
-@SpringBootTest
-@AutoConfigureTestDatabase(replace = Replace.NONE)
-@DirtiesContext(classMode = ClassMode.AFTER_CLASS)
-@EnabledIf(value = "${test-strategy.run-nsw-tests}", loadContext = true)
-public class GenerateAssertionsOnNSWTests {
-
- private static final Logger logger = LoggerFactory.getLogger(GenerateAssertionsOnNSWTests.class);
-
- @Autowired
- private CVRContestInfoRepository cvrContestInfoRepository;
-
- @Autowired
- AssertionRepository assertionRepository;
-
- @Autowired
- GenerateAssertionsService generateAssertionsService;
-
- private static final int DEFAULT_TIME_LIMIT=5;
-
- /**
- * Expected data for each NSW contest.
- * Difficulties are taken from raire-java::src/test/java/au/org/democracydevelopers/raire/TestNSW
- * which in turn tests against raire-rs.
- * Winners are taken from the New South Wales official election results at
- * https://pastvtr.elections.nsw.gov.au/LG2101/status/mayoral
- * The ballotCounts are derived from the data, but double-checked for exact match with the
- * NSWEC website.
- */
- // Contest Eurobodalla Mayoral
- private static final String nameContest_1 = "Eurobodalla Mayoral";
- private static final List choicesContest_1 = List.of("WORTHINGTON Alison","GRACE David",
- "SMITH Gary","HATCHER Mat","HARRISON N (Tubby)","POLLOCK Rob","STARMER Karyn");
- private static final int ballotCountContest_1 = 25526;
- private static final double difficultyContest_1 = 23.079566003616637;
- private static final String winnerContest_1 = "HATCHER Mat";
-
- // Contest City of Lake Macquarie Mayoral
- private static final String nameContest_2 = "City of Lake Macquarie Mayoral";
- private static final List choicesContest_2 = List.of("FRASER Kay","DAWSON Rosmairi",
- "CUBIS Luke","PAULING Jason");
- private static final int ballotCountContest_2 = 130336;
- private static final double difficultyContest_2 = 3.1113869658629745;
- private static final String winnerContest_2 = "FRASER Kay";
-
- // Contest City of Coffs Harbour Mayoral
- private static final String nameContest_3 = "City of Coffs Harbour Mayoral";
- private static final List choicesContest_3 = List.of("SWAN Tegan","CECATO George",
- "ADENDORFF Michael","JUDGE Tony","PRYCE Rodger","PIKE Donna","AMOS Paul","TOWNLEY Sally",
- "ARKAN John","CASSELL Jonathan");
- private static final int ballotCountContest_3 = 45155;
- private static final double difficultyContest_3 = 8.571564160971906;
- private static final String winnerContest_3 = "AMOS Paul";
-
- // Contest Singleton Mayoral
- private static final String nameContest_4 = "Singleton Mayoral";
- private static final List choicesContest_4 = List.of("MOORE Sue","THOMPSON Danny",
- "JARRETT Tony","CHARLTON Belinda");
- private static final int ballotCountContest_4 = 13755;
- private static final double difficultyContest_4 = 12.118942731277533;
- private static final String winnerContest_4 = "MOORE Sue";
-
- // Contest City of Newcastle Mayoral
- private static final String nameContest_5 = "City of Newcastle Mayoral";
- private static final List choicesContest_5 = List.of("CHURCH John","NELMES Nuatali",
- "HOLDING Rod","MACKENZIE John","O'BRIEN Steve","BARRIE Jenny");
- private static final int ballotCountContest_5 = 100275;
- private static final double difficultyContest_5 = 5.913487055493307;
- private static final String winnerContest_5 = "NELMES Nuatali";
-
- // Contest Nambucca Valley Mayoral
- private static final String nameContest_6 = "Nambucca Valley Mayoral";
- private static final List choicesContest_6 = List.of("JENVEY Susan","HOBAN Rhonda");
- private static final int ballotCountContest_6 = 12482;
- private static final double difficultyContest_6 = 2.7360806663743973;
- private static final String winnerContest_6 = "HOBAN Rhonda";
-
- // Contest City of Maitland Mayoral
- private static final String nameContest_7 = "City of Maitland Mayoral";
- private static final List choicesContest_7 = List.of("BROWN John","MITCHELL Ben",
- "BAKER Loretta","PENFOLD Philip","SAFFARI Shahriar (Sean)","COOPER Michael","BURKE Brian");
- private static final int ballotCountContest_7 = 54181;
- private static final double difficultyContest_7 = 47.072980017376196;
- private static final String winnerContest_7 = "PENFOLD Philip";
-
- // Contest Kempsey Mayoral
- private static final String nameContest_8 = "Kempsey Mayoral";
- private static final List choicesContest_8 = List.of("HAUVILLE Leo","EVANS Andrew",
- "BAIN Arthur","CAMPBELL Liz","SAUL Dean","IRWIN Troy","RAEBURN Bruce");
- private static final int ballotCountContest_8 = 17585;
- private static final double difficultyContest_8 = 45.43927648578811;
- private static final String winnerContest_8 = "HAUVILLE Leo";
-
- // Contest Canada Bay Mayoral
- private static final String nameContest_9 = "Canada Bay Mayoral";
- private static final List choicesContest_9 = List.of("TSIREKAS Angelo","LITTLE Julia",
- "MEGNA Michael","JAGO Charles","RAMONDINO Daniela");
- private static final int ballotCountContest_9 = 48542;
- private static final double difficultyContest_9 = 8.140533288613113;
- private static final String winnerContest_9 = "TSIREKAS Angelo";
-
- // Contest Richmond Valley Mayoral
- private static final String nameContest_10 = "Richmond Valley Mayoral";
- private static final List choicesContest_10 = List.of("MUSTOW Robert","HAYES Robert");
- private static final int ballotCountContest_10 = 13405;
- private static final double difficultyContest_10 = 2.302868922865487;
- private static final String winnerContest_10 = "MUSTOW Robert";
-
- // Contest City of Sydney Mayoral
- private static final String nameContest_11 = "City of Sydney Mayoral";
- private static final List choicesContest_11 = List.of("VITHOULKAS Angela",
- "WELDON Yvonne","SCOTT Linda","JARRETT Shauna","ELLSMORE Sylvie","MOORE Clover");
- private static final int ballotCountContest_11 = 118511;
- private static final double difficultyContest_11 = 3.6873366521468576;
- private static final String winnerContest_11 = "MOORE Clover";
-
- // Contest Byron Mayoral
- private static final String nameContest_12 = "Byron Mayoral";
- private static final List choicesContest_12 = List.of("HUNTER Alan","CLARKE Bruce",
- "COOREY Cate","ANDERSON John","MCILRATH Christopher","LYON Michael","DEY Duncan",
- "PUGH Asren","SWIVEL Mark");
- private static final int ballotCountContest_12 = 18165;
- private static final double difficultyContest_12 = 17.13679245283019;
- private static final String winnerContest_12 = "LYON Michael";
-
- // Contest City of Broken Hill Mayoral
- private static final String nameContest_13 = "City of Broken Hill Mayoral";
- private static final List choicesContest_13 = List.of("TURLEY Darriea","KENNEDY Tom",
- "GALLAGHER Dave");
- private static final int ballotCountContest_13 = 10812;
- private static final double difficultyContest_13 = 3.2773567747802366;
- private static final String winnerContest_13 = "KENNEDY Tom";
-
- // Contest City of Shellharbour Mayoral
- private static final String nameContest_14 = "City of Shellharbour Mayoral";
- private static final List choicesContest_14 = List.of("HOMER Chris","SALIBA Marianne");
- private static final int ballotCountContest_14 = 46273;
- private static final double difficultyContest_14 = 17.83159922928709;
- private static final String winnerContest_14 = "HOMER Chris";
-
- // Contest City of Shoalhaven Mayoral
- private static final String nameContest_15 = "City of Shoalhaven Mayoral";
- private static final List choicesContest_15 = List.of("GREEN Paul","KITCHENER Mark",
- "WHITE Patricia","WATSON Greg","DIGIGLIO Nina","FINDLEY Amanda");
- private static final int ballotCountContest_15 = 67030;
- private static final double difficultyContest_15 = 41.53035935563817;
- private static final String winnerContest_15 = "FINDLEY Amanda";
-
- // Contest Mosman Mayoral
- private static final String nameContest_16 = "Mosman Mayoral";
- private static final List choicesContest_16 = List.of("MOLINE Libby","BENDALL Roy",
- "HARDING Sarah","CORRIGAN Carolyn","MENZIES Simon");
- private static final int ballotCountContest_16 = 16425;
- private static final double difficultyContest_16 = 4.498767460969598;
- private static final String winnerContest_16 = "CORRIGAN Carolyn";
-
- // Contest City of Orange Mayoral
- private static final String nameContest_17 = "City of Orange Mayoral";
- private static final List choicesContest_17 = List.of("HAMLING Jason","SPALDING Amanda",
- "JONES Neil","WHITTON Jeffery","DUFFY Kevin","SMITH Lesley","MILETO Tony");
- private static final int ballotCountContest_17 = 24355;
- private static final double difficultyContest_17 = 50.01026694045174;
- private static final String winnerContest_17 = "HAMLING Jason";
-
- // Contest City of Wollongong Mayoral
- private static final String nameContest_18 = "City of Wollongong Mayoral";
- private static final List choicesContest_18 = List.of("GLYKIS Marie","DORAHY John",
- "BROWN Tania","BRADBERY Gordon","ANTHONY Andrew","COX Mithra");
- private static final int ballotCountContest_18 = 127240;
- private static final double difficultyContest_18 = 47.72693173293323;
- private static final String winnerContest_18 = "BRADBERY Gordon";
-
- // Contest Port Stephens Mayoral
- private static final String nameContest_19 = "Port Stephens Mayoral";
- private static final List choicesContest_19 = List.of("ANDERSON Leah","PALMER Ryan");
- private static final int ballotCountContest_19 = 47807;
- private static final double difficultyContest_19 = 84.31569664902999;
- private static final String winnerContest_19 = "PALMER Ryan";
-
- // Contest Wollondilly Mayoral
- private static final String nameContest_20 = "Wollondilly Mayoral";
- private static final List choicesContest_20 = List.of("KHAN Robert","BANASIK Michael",
- "DEETH Matthew","LAW Ray","GOULD Matt","HANNAN Judy");
- private static final int ballotCountContest_20 = 31355;
- private static final double difficultyContest_20 = 24.40077821011673;
- private static final String winnerContest_20 = "GOULD Matt";
-
- // Contest Hornsby Mayoral
- private static final String nameContest_21 = "Hornsby Mayoral";
- private static final List choicesContest_21 = List.of("HEYDE Emma","RUDDOCK Philip");
- private static final int ballotCountContest_21 = 85656;
- private static final double difficultyContest_21 = 6.866762866762866;
- private static final String winnerContest_21 = "RUDDOCK Philip";
-
- // Contest Ballina Mayoral
- private static final String nameContest_22 = "Ballina Mayoral";
- private static final List choicesContest_22 = List.of("WILLIAMS Keith","JOHNSON Jeff",
- "MCCARTHY Steve","JOHNSTON Eoin","CADWALLADER Sharon");
- private static final int ballotCountContest_22 = 26913;
- private static final double difficultyContest_22 = 7.285598267460747;
- private static final String winnerContest_22 = "CADWALLADER Sharon";
-
- // Contest Bellingen Mayoral
- private static final String nameContest_23 = "Bellingen Mayoral";
- private static final List choicesContest_23 = List.of("ALLAN Steve","WOODWARD Andrew",
- "KING Dominic");
- private static final int ballotCountContest_23 = 8374;
- private static final double difficultyContest_23 = 3.3335987261146496;
- private static final String winnerContest_23 = "ALLAN Steve";
-
- // Contest City of Lismore Mayoral
- private static final String nameContest_24 = "City of Lismore Mayoral";
- private static final List choicesContest_24 = List.of("KRIEG Steve","COOK Darlene",
- "HEALEY Patrick","GRINDON-EKINS Vanessa","ROB Big","BIRD Elly");
- private static final int ballotCountContest_24 = 26474;
- private static final double difficultyContest_24 = 2.929836210712705;
- private static final String winnerContest_24 = "KRIEG Steve";
-
- // Contest City of Willoughby Mayoral
- private static final String nameContest_25 = "City of Willoughby Mayoral";
- private static final List choicesContest_25 = List.of("ROZOS Angelo","CAMPBELL Craig",
- "TAYLOR Tanya");
- private static final int ballotCountContest_25 = 37942;
- private static final double difficultyContest_25 = 14.990912682734097;
- private static final String winnerContest_25 = "TAYLOR Tanya";
-
- // Contest The Hills Shire Mayoral
- private static final String nameContest_26 = "The Hills Shire Mayoral";
- private static final List choicesContest_26 = List.of("SHAHAMAT Vida","GANGEMI Peter",
- "ROZYCKI Jerzy (George)","TRACEY Ryan","YAZDANI Ereboni (Alexia)");
- private static final int ballotCountContest_26 = 105384;
- private static final double difficultyContest_26 = 3.6801229221958374;
- private static final String winnerContest_26 = "GANGEMI Peter";
-
- // Contest City of Cessnock Mayoral
- private static final String nameContest_27 = "City of Cessnock Mayoral";
- private static final List choicesContest_27 = List.of("MURRAY Janet","SUVAAL Jay",
- "MOORES John","OLSEN Ian");
- private static final int ballotCountContest_27 = 36497;
- private static final double difficultyContest_27 = 6.466513111268604;
- private static final String winnerContest_27 = "SUVAAL Jay";
-
- // Contest City of Griffith Mayoral
- private static final String nameContest_28 = "City of Griffith Mayoral";
- private static final List choicesContest_28 = List.of("MERCURI Rina","NAPOLI Anne",
- "ZAPPACOSTA Dino","LA ROCCA Mariacarmina (Carmel)","CURRAN Doug");
- private static final int ballotCountContest_28 = 14179;
- private static final double difficultyContest_28 = 3.9320576816417083;
- private static final String winnerContest_28 = "CURRAN Doug";
-
- // Contest Port Macquarie-Hastings Mayoral
- private static final String nameContest_29 = "Port Macquarie-Hastings Mayoral";
- private static final List choicesContest_29 = List.of("PINSON Peta","GATES Steven",
- "SHEPPARD Rachel","INTEMANN Lisa","LIPOVAC Nik");
- private static final int ballotCountContest_29 = 54499;
- private static final double difficultyContest_29 = 2.8524547262640008;
- private static final String winnerContest_29 = "PINSON Peta";
-
- // Contest City of Liverpool Mayoral
- private static final String nameContest_30 = "City of Liverpool Mayoral";
- private static final List choicesContest_30 = List.of("HAGARTY Nathan","MORSHED Asm",
- "ANDJELKOVIC Milomir (Michael)","HARLE Peter","MANNOUN Ned");
- private static final int ballotCountContest_30 = 115177;
- private static final double difficultyContest_30 = 45.416798107255524;
- private static final String winnerContest_30 = "MANNOUN Ned";
-
- // Contest Uralla Mayoral
- private static final String nameContest_31 = "Uralla Mayoral";
- private static final List choicesContest_31 = List.of("BELL Robert","LEDGER Natasha",
- "STRUTT Isabel");
- private static final int ballotCountContest_31 = 3781;
- private static final double difficultyContest_31 = 1.6297413793103448;
- private static final String winnerContest_31 = "BELL Robert";
-
- // Contest Hunter's Hill Mayoral
- private static final String nameContest_32 = "Hunter's Hill Mayoral";
- private static final List choicesContest_32 = List.of("GUAZZAROTTO David","MILES Zac",
- "QUINN Richard","WILLIAMS Ross");
- private static final int ballotCountContest_32 = 8356;
- private static final double difficultyContest_32 = 38.330275229357795;
- private static final String winnerContest_32 = "MILES Zac";
-
- // Contest Burwood Mayoral
- private static final String nameContest_33 = "Burwood Mayoral";
- private static final List choicesContest_33 = List.of("HULL David","MURRAY Alan",
- "CUTCHER Ned","FAKER John");
- private static final int ballotCountContest_33 = 17797;
- private static final double difficultyContest_33 = 2.5269061479483175;
- private static final String winnerContest_33 = "FAKER John";
-
- /**
- * Contest 1.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest1() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest1");
- List retrieved = cvrContestInfoRepository.getCVRs(1, 1);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_1.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 1.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest1() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest1");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_1,
- ballotCountContest_1, DEFAULT_TIME_LIMIT, choicesContest_1);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_1, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_1);
- assertTrue(difficultyMatchesMax(difficultyContest_1, assertions));
- }
-
- /**
- * Contest 2.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest2() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest2");
- List retrieved = cvrContestInfoRepository.getCVRs(2, 2);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_2.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 2.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest2() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest2");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_2,
- ballotCountContest_2, DEFAULT_TIME_LIMIT, choicesContest_2);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_2, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_2);
- assertTrue(difficultyMatchesMax(difficultyContest_2, assertions));
- }
-
- /**
- * Contest 3.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest3() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest3");
- List retrieved = cvrContestInfoRepository.getCVRs(3, 3);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_3.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 3.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest3() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest3");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_3,
- ballotCountContest_3, DEFAULT_TIME_LIMIT, choicesContest_3);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_3, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_3);
- assertTrue(difficultyMatchesMax(difficultyContest_3, assertions));
- }
-
- /**
- * Contest 4.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest4() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest4");
- List retrieved = cvrContestInfoRepository.getCVRs(4, 4);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_4.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 4.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest4() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest4");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_4,
- ballotCountContest_4, DEFAULT_TIME_LIMIT, choicesContest_4);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_4, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_4);
- assertTrue(difficultyMatchesMax(difficultyContest_4, assertions));
- }
-
- /**
- * Contest 5.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest5() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest5");
- List retrieved = cvrContestInfoRepository.getCVRs(5, 5);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_5.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 5.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest5() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest5");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_5,
- ballotCountContest_5, DEFAULT_TIME_LIMIT, choicesContest_5);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_5, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_5);
- assertTrue(difficultyMatchesMax(difficultyContest_5, assertions));
- }
-
- /**
- * Contest 6.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest6() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest6");
- List retrieved = cvrContestInfoRepository.getCVRs(6, 6);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_6.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 6.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest6() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest6");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_6,
- ballotCountContest_6, DEFAULT_TIME_LIMIT, choicesContest_6);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_6, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_6);
- assertTrue(difficultyMatchesMax(difficultyContest_6, assertions));
- }
-
- /**
- * Contest 7.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest7() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest7");
- List retrieved = cvrContestInfoRepository.getCVRs(7, 7);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_7.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 7.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest7() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest7");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_7,
- ballotCountContest_7, DEFAULT_TIME_LIMIT, choicesContest_7);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_7, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_7);
- assertTrue(difficultyMatchesMax(difficultyContest_7, assertions));
- }
-
- /**
- * Contest 8.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest8() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest8");
- List retrieved = cvrContestInfoRepository.getCVRs(8, 8);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_8.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 8.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest8() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest8");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_8,
- ballotCountContest_8, DEFAULT_TIME_LIMIT, choicesContest_8);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_8, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_8);
- assertTrue(difficultyMatchesMax(difficultyContest_8, assertions));
- }
-
- /**
- * Contest 9.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest9() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest9");
- List retrieved = cvrContestInfoRepository.getCVRs(9, 9);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_9.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 9.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest9() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest9");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_9,
- ballotCountContest_9, DEFAULT_TIME_LIMIT, choicesContest_9);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_9, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_9);
- assertTrue(difficultyMatchesMax(difficultyContest_9, assertions));
- }
-
- /**
- * Contest 10.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest10() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest10");
- List retrieved = cvrContestInfoRepository.getCVRs(10, 10);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_10.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 10.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest10() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest10");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_10,
- ballotCountContest_10, DEFAULT_TIME_LIMIT, choicesContest_10);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_10, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_10);
- assertTrue(difficultyMatchesMax(difficultyContest_10, assertions));
- }
-
- /**
- * Contest 11.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest11() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest11");
- List retrieved = cvrContestInfoRepository.getCVRs(11, 11);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_11.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 11.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest11() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest11");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_11,
- ballotCountContest_11, DEFAULT_TIME_LIMIT, choicesContest_11);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_11, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_11);
- assertTrue(difficultyMatchesMax(difficultyContest_11, assertions));
- }
-
- /**
- * Contest 12.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest12() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest12");
- List retrieved = cvrContestInfoRepository.getCVRs(12, 12);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_12.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 12.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest12() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest12");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_12,
- ballotCountContest_12, DEFAULT_TIME_LIMIT, choicesContest_12);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_12, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_12);
- assertTrue(difficultyMatchesMax(difficultyContest_12, assertions));
- }
-
- /**
- * Contest 13.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest13() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest13");
- List retrieved = cvrContestInfoRepository.getCVRs(13, 13);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_13.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 13.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest13() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest13");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_13,
- ballotCountContest_13, DEFAULT_TIME_LIMIT, choicesContest_13);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_13, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_13);
- assertTrue(difficultyMatchesMax(difficultyContest_13, assertions));
- }
-
- /**
- * Contest 14.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest14() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest14");
- List retrieved = cvrContestInfoRepository.getCVRs(14, 14);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_14.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 14.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest14() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest14");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_14,
- ballotCountContest_14, DEFAULT_TIME_LIMIT, choicesContest_14);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_14, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_14);
- assertTrue(difficultyMatchesMax(difficultyContest_14, assertions));
- }
-
- /**
- * Contest 15.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest15() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest15");
- List retrieved = cvrContestInfoRepository.getCVRs(15, 15);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_15.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 15.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest15() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest15");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_15,
- ballotCountContest_15, DEFAULT_TIME_LIMIT, choicesContest_15);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_15, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_15);
- assertTrue(difficultyMatchesMax(difficultyContest_15, assertions));
- }
-
- /**
- * Contest 16.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest16() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest16");
- List retrieved = cvrContestInfoRepository.getCVRs(16, 16);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_16.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 16.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest16() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest16");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_16,
- ballotCountContest_16, DEFAULT_TIME_LIMIT, choicesContest_16);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_16, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_16);
- assertTrue(difficultyMatchesMax(difficultyContest_16, assertions));
- }
-
- /**
- * Contest 17.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest17() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest17");
- List retrieved = cvrContestInfoRepository.getCVRs(17, 17);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_17.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 17.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest17() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest17");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_17,
- ballotCountContest_17, DEFAULT_TIME_LIMIT, choicesContest_17);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_17, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_17);
- assertTrue(difficultyMatchesMax(difficultyContest_17, assertions));
- }
-
- /**
- * Contest 18.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest18() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest18");
- List retrieved = cvrContestInfoRepository.getCVRs(18, 18);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_18.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 18.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest18() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest18");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_18,
- ballotCountContest_18, DEFAULT_TIME_LIMIT, choicesContest_18);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_18, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_18);
- assertTrue(difficultyMatchesMax(difficultyContest_18, assertions));
- }
-
- /**
- * Contest 19.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest19() {
- testUtils.log(logger, "");
- List retrieved = cvrContestInfoRepository.getCVRs(19, 19);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_19.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 19.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest19() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest19");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_19,
- ballotCountContest_19, DEFAULT_TIME_LIMIT, choicesContest_19);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_19, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_19);
- assertTrue(difficultyMatchesMax(difficultyContest_19, assertions));
- }
-
- /**
- * Contest 20.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest20() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest20");
- List retrieved = cvrContestInfoRepository.getCVRs(20, 20);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_20.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 20.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest20() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest20");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_20,
- ballotCountContest_20, DEFAULT_TIME_LIMIT, choicesContest_20);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_20, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_20);
- assertTrue(difficultyMatchesMax(difficultyContest_20, assertions));
- }
-
- /**
- * Contest 21.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest21() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest21");
- List retrieved = cvrContestInfoRepository.getCVRs(21, 21);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_21.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 21.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest21() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest21");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_21,
- ballotCountContest_21, DEFAULT_TIME_LIMIT, choicesContest_21);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_21, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_21);
- assertTrue(difficultyMatchesMax(difficultyContest_21, assertions));
- }
-
- /**
- * Contest 22.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest22() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest22");
- List retrieved = cvrContestInfoRepository.getCVRs(22, 22);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_22.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 22.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest22() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest22");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_22,
- ballotCountContest_22, DEFAULT_TIME_LIMIT, choicesContest_22);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_22, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_22);
- assertTrue(difficultyMatchesMax(difficultyContest_22, assertions));
- }
-
- /**
- * Contest 23.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest23() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest23");
- List retrieved = cvrContestInfoRepository.getCVRs(23, 23);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_23.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 23.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest23() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest23");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_23,
- ballotCountContest_23, DEFAULT_TIME_LIMIT, choicesContest_23);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_23, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_23);
- assertTrue(difficultyMatchesMax(difficultyContest_23, assertions));
- }
-
- /**
- * Contest 24.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest24() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest24");
- List retrieved = cvrContestInfoRepository.getCVRs(24, 24);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_24.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 24.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest24() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest24");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_24,
- ballotCountContest_24, DEFAULT_TIME_LIMIT, choicesContest_24);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_24, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_24);
- assertTrue(difficultyMatchesMax(difficultyContest_24, assertions));
- }
-
- /**
- * Contest 25.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest25() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest25");
- List retrieved = cvrContestInfoRepository.getCVRs(25, 25);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_25.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 25.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest25() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest25");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_25,
- ballotCountContest_25, DEFAULT_TIME_LIMIT, choicesContest_25);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_25, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_25);
- assertTrue(difficultyMatchesMax(difficultyContest_25, assertions));
- }
-
- /**
- * Contest 26.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest26() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest26");
- List retrieved = cvrContestInfoRepository.getCVRs(26, 26);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_26.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 26.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest26() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest26");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_26,
- ballotCountContest_26, DEFAULT_TIME_LIMIT, choicesContest_26);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_26, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_26);
- assertTrue(difficultyMatchesMax(difficultyContest_26, assertions));
- }
-
- /**
- * Contest 27.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest27() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest27");
- List retrieved = cvrContestInfoRepository.getCVRs(27, 27);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_27.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 27.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest27() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest27");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_27,
- ballotCountContest_27, DEFAULT_TIME_LIMIT, choicesContest_27);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_27, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_27);
- assertTrue(difficultyMatchesMax(difficultyContest_27, assertions));
- }
-
- /**
- * Contest 28.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest28() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest28");
- List retrieved = cvrContestInfoRepository.getCVRs(28, 28);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_28.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 28.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest28() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest28");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_28,
- ballotCountContest_28, DEFAULT_TIME_LIMIT, choicesContest_28);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_28, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_28);
- assertTrue(difficultyMatchesMax(difficultyContest_28, assertions));
- }
-
- /**
- * Contest 29.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest29() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest29");
- List retrieved = cvrContestInfoRepository.getCVRs(29, 29);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_29.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 29.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest29() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest29");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_29,
- ballotCountContest_29, DEFAULT_TIME_LIMIT, choicesContest_29);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_29, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_29);
- assertTrue(difficultyMatchesMax(difficultyContest_29, assertions));
- }
-
- /**
- * Contest 30.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest30() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest30");
- List retrieved = cvrContestInfoRepository.getCVRs(30, 30);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_30.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 30.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest30() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest30");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_30,
- ballotCountContest_30, DEFAULT_TIME_LIMIT, choicesContest_30);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_30, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List assertions = assertionRepository.findByContestName(nameContest_30);
- assertTrue(difficultyMatchesMax(difficultyContest_30, assertions));
- }
-
- /**
- * Contest 31.
- * Sanity check to make sure that the first vote's first preference has one of the candidate names
- * we expect for that contest.
- */
- @Test
- @Transactional
- void firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest31() {
- testUtils.log(logger, "firstPreferenceOfFirstVoteHasAnExpectedCandidateName_contest31");
- List retrieved = cvrContestInfoRepository.getCVRs(31, 31);
- String retrievedFirstChoice = retrieved.getFirst()[0];
- assertTrue(choicesContest_31.contains(retrievedFirstChoice));
- }
-
- /**
- * Contest 31.
- * Generate assertions. Check the winner.
- * Then check the difficulty, to ensure it matches what is generated by raire-java directly (which in
- * turn has been tested against raire-rs).
- * @throws RaireServiceException when an error occurs in assertion generation.
- */
- @Test
- @Transactional
- public void checkDifficulty_contest31() throws RaireServiceException {
- testUtils.log(logger, "checkDifficulty_contest31");
- GenerateAssertionsRequest request = new GenerateAssertionsRequest(nameContest_31,
- ballotCountContest_31, DEFAULT_TIME_LIMIT, choicesContest_31);
-
- // Generate assertions.
- RaireResultOrError response = generateAssertionsService.generateAssertions(request);
- generateAssertionsService.persistAssertions(response.Ok, request);
-
- // Check winners.
- assertEquals(winnerContest_31, request.candidates.get(response.Ok.winner));
-
- // Check difficulty.
- List