Skip to content

Commit

Permalink
Added tests of edge cases: no contests, and an all-STV contests cvr.
Browse files Browse the repository at this point in the history
  • Loading branch information
vteague committed Jul 31, 2024
1 parent 2451609 commit f5d7224
Show file tree
Hide file tree
Showing 5 changed files with 79 additions and 52 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -88,11 +88,6 @@ public class DominionCVRExportParserTests extends TestClassWithDatabase {
*/
private static final String badNumsRegexp = "Unexpected or uninterpretable numbers in header:.*";

/**
* Blank properties for submitting to the DominionCVRExportParser instance.
*/
private static final Properties blank = new Properties();

@BeforeClass
public static void beforeAll() {
postgres.start();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,7 @@
package au.org.democracydevelopers.corla.endpoint;

import au.org.democracydevelopers.corla.model.vote.IRVBallotInterpretation;
import au.org.democracydevelopers.corla.util.SparkRequestStub;
import au.org.democracydevelopers.corla.util.SparkResponseStub;
import au.org.democracydevelopers.corla.util.TestOnlyQueries;
import au.org.democracydevelopers.corla.util.testUtils;
import au.org.democracydevelopers.corla.util.*;
import org.mockito.*;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testcontainers.ext.ScriptUtils;
Expand All @@ -13,13 +10,11 @@
import org.testng.annotations.Test;
import spark.HaltException;
import us.freeandfair.corla.Main;
import us.freeandfair.corla.auth.AuthenticationInterface;
import us.freeandfair.corla.controller.ComparisonAuditController;
import us.freeandfair.corla.endpoint.ACVRUpload;
import us.freeandfair.corla.model.*;
import us.freeandfair.corla.persistence.Persistence;
import us.freeandfair.corla.query.CastVoteRecordQueries;
import us.freeandfair.corla.util.TestClassWithDatabase;
import org.apache.log4j.LogManager;
import org.apache.log4j.Logger;

Expand All @@ -28,25 +23,21 @@
import static org.testng.Assert.assertTrue;

import spark.Request;
import spark.Response;

import javax.transaction.Transactional;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static us.freeandfair.corla.model.Administrator.AdministratorType.COUNTY;
import static us.freeandfair.corla.model.CastVoteRecord.RecordType.AUDITOR_ENTERED;

/**
* Test upload of IRV audit cvrs. Includes tests of both valid and invalid IRV CVRs, and tests that
* the interpreted ballots are properly stored in the database.
* This makes use of TestClassWithAuth to mock authentication as Adams County.
* TODO test reaudits, both IRV and plurality (can they be mixed in one CVR?)
* See <a href="https://github.com/orgs/DemocracyDevelopers/projects/1/views/1?pane=issue&itemId=72434202">...</a>
*/
public class ACVRUploadTests extends TestClassWithDatabase {
public class ACVRUploadTests extends TestClassWithAuth {

private final static Logger LOGGER = LogManager.getLogger(ACVRUploadTests.class);

Expand All @@ -71,10 +62,6 @@ public class ACVRUploadTests extends TestClassWithDatabase {
*/
private static final long countyID = 1L;

/**
* The county we will pretend to be logged in as administrator for.
*/
private static final County county = new County(countyName, countyID);

/**
* Flag for checking whether the audit round has already been started.
Expand Down Expand Up @@ -317,12 +304,6 @@ public class ACVRUploadTests extends TestClassWithDatabase {
" \"auditBoardIndex\": -1" +
"}";

@Mock
private AuthenticationInterface auth;

@Mock
private ThreadLocal<List<LogEntry>> mockedAsm;

/**
* Database init.
*/
Expand All @@ -338,32 +319,16 @@ public static void beforeAll() {
}

/**
* Init mocked objects, which is a little complicated because we have to simulate auth for a
* county's audit board in the ACVR endpoint.
* Init mocks, particularly for authentication.
*/
@BeforeClass
public void initMocks() {
testUtils.log(LOGGER, "initMocks");

MockitoAnnotations.openMocks(this);

// Mock successful auth as a county. No need to mock the CountyDashboard retrieval from
// the database, because that is loaded in via co-counties.sql.
try {
when(auth.authenticatedCounty(any())).thenReturn(county);
when(auth.secondFactorAuthenticated(any())).thenReturn(true);
when(auth.authenticatedAdministrator(any())).thenReturn(new Administrator(
"countyadmin"+countyID, COUNTY, countyName+" County", county));
when(auth.authenticatedAs(any(), any(), any())).thenReturn(true);
when(mockedAsm.get()).thenReturn(new ArrayList<>());
} catch (Exception e) {
testUtils.log(LOGGER, "Initiating mocks didn't work.");
// Do nothing. If auth isn't properly initialized, the tests will fail.
}
// Mock successful auth as a county.
mockAuth(countyName, countyID);
}

private final Response response = new SparkResponseStub();

/**
* Basic test of proper functioning for uploaded audit CVRs, including:
* 1. a valid IRV vote
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -71,11 +71,6 @@ public class RankedBallotInterpretationReportTests extends TestClassWithDatabase
*/
static PostgreSQLContainer<?> postgres = createTestContainer();

/**
* Blank properties for submitting to the DominionCVRExportParser instance.
*/
private static final Properties blank = new Properties();

@BeforeClass
public static void beforeAll() {
postgres.start();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
package au.org.democracydevelopers.corla.util;

import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import spark.Response;
import us.freeandfair.corla.auth.AuthenticationInterface;
import us.freeandfair.corla.model.*;
import us.freeandfair.corla.util.TestClassWithDatabase;

import java.util.ArrayList;
import java.util.List;

import static org.mockito.ArgumentMatchers.any;
import static org.mockito.Mockito.when;
import static us.freeandfair.corla.model.Administrator.AdministratorType.COUNTY;

/**
* This test class is designed for testing endpoints. It mocks successful authentication to allow
* for direct calling of endpointBody(request, response).
* Some notes:
* - Currently, it only mocks the _county_ auth. TODO add state auth mock - you probably just have to
* change the AdministratorType to STATE instead of COUNTY in the call to new Administrator in initMocks,
* and obviously make the username one of the state uids in your database.
* - It is highly dependent on the mocked Spark functions in SparkRequestStub and SparkResponseStub.
* Not all the Spark functions have been implemented - if you find that the attempt to use one of
* them fails, you need to implement it in either SparkRequestStub or SparkResponseStub.
* - You will probably also still need to do some other set up of the endpoint you want to test.
* - Tests run in parallel seem to fail in strange ways - either do them sequentially, or make them
* one test. I haven't tried testing parallel runs of mocked auth for _different_ counties.
* See ACVRUploadTests for an example. Calling endpoint.before(request, response) was necessary for
* that endpoint.
*
*
*/
public abstract class TestClassWithAuth extends TestClassWithDatabase {

/**
* A blank response for use in endpoint-calling.
*/
protected final Response response = new SparkResponseStub();

@Mock
protected AuthenticationInterface auth;

@Mock
protected ThreadLocal<List<LogEntry>> mockedAsm;

/**
* Init mocked objects, particularly the authentication as the given county.
* @param countyName The name of the county - must match whatever is loaded into the test database.
* @param countyID The ID of the county - must match whatever is loaded into the test database.
*/
protected void mockAuth(String countyName, long countyID) {
final County county = new County(countyName, countyID);

MockitoAnnotations.openMocks(this);
// Mock successful auth as a county. No need to mock the CountyDashboard retrieval from
// the database, because that is loaded in via co-counties.sql.
when(auth.authenticatedCounty(any())).thenReturn(county);
when(auth.secondFactorAuthenticated(any())).thenReturn(true);
when(auth.authenticatedAdministrator(any())).thenReturn(new Administrator(
"countyadmin" + countyID, COUNTY, countyName + " County", county));
when(auth.authenticatedAs(any(), any(), any())).thenReturn(true);
when(mockedAsm.get()).thenReturn(new ArrayList<>());
}


}
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,6 @@

import java.util.Properties;

import com.google.gson.Gson;
import org.testcontainers.containers.PostgreSQLContainer;
import org.testng.annotations.AfterMethod;
import org.testng.annotations.BeforeMethod;
Expand All @@ -36,6 +35,11 @@
*/
public abstract class TestClassWithDatabase {

/**
* Blank properties for submitting to the DominionCVRExportParser instance.
*/
protected static final Properties blank = new Properties();

/**
* Begin a new transaction before each test method in the class is run.
*/
Expand Down

0 comments on commit f5d7224

Please sign in to comment.