Skip to content

Commit

Permalink
docs(testing): revisit testing docs and add more in detail info
Browse files Browse the repository at this point in the history
  • Loading branch information
ctrlc03 committed Jan 8, 2024
1 parent 91c1587 commit 6497aac
Show file tree
Hide file tree
Showing 13 changed files with 285 additions and 51 deletions.
41 changes: 41 additions & 0 deletions integrationTests/ts/__tests__/data/suites.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,47 @@
"expectedSpentVoiceCredits": [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedTotalSpentVoiceCredits": 4
},
{
"name": "10 Users test",
"description": "Should signup 10 users, submit 10 votes and tally the results",
"numUsers": 10,
"numVotesPerUser": 1,
"votes": {
"0": {
"0": { "voteOptionIndex": 0, "voteWeight": 5 }
},
"1": {
"0": { "voteOptionIndex": 0, "voteWeight": 9 }
},
"2": {
"0": { "voteOptionIndex": 5, "voteWeight": 3 }
},
"3": {
"0": { "voteOptionIndex": 3, "voteWeight": 2 }
},
"4": {
"0": { "voteOptionIndex": 0, "voteWeight": 1 }
},
"5": {
"0": { "voteOptionIndex": 9, "voteWeight": 1 }
},
"6": {
"0": { "voteOptionIndex": 4, "voteWeight": 7 }
},
"7": {
"0": { "voteOptionIndex": 7, "voteWeight": 5 }
},
"8": {
"0": { "voteOptionIndex": 3, "voteWeight": 10 }
},
"9": {
"0": { "voteOptionIndex": 8, "voteWeight": 2 }
}
},
"expectedTally": [15, 0, 0, 12, 7, 3, 0, 5, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedSpentVoiceCredits": [107, 0, 0, 104, 49, 9, 0, 25, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedTotalSpentVoiceCredits": 299
},
{
"name": "Reverse processing",
"description": "2 batches, 1 briber",
Expand Down
1 change: 0 additions & 1 deletion integrationTests/ts/__tests__/utils/interfaces.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ export interface IVote {
voteOptionIndex: number;
voteWeight: number;
nonce: number;
valid: boolean;
}

/**
Expand Down
7 changes: 2 additions & 5 deletions integrationTests/ts/__tests__/utils/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -40,7 +40,6 @@ const getTestVoteValues = (
const useVotes = votes && userIndex in votes;
let { voteOptionIndex } = defaultVote;
let { voteWeight } = defaultVote;
let valid = true;

// if we have bribers
if (bribers && userIndex in bribers) {
Expand All @@ -63,10 +62,9 @@ const getTestVoteValues = (

if (useVotes) {
voteWeight = votes[userIndex][voteIndex].voteWeight;
valid = votes[userIndex][voteIndex].valid;
}

return { voteOptionIndex, voteWeight, valid };
return { voteOptionIndex, voteWeight };
};

/**
Expand All @@ -89,12 +87,11 @@ export const genTestUserCommands = (
const votes: IVote[] = [];

for (let j = 0; j < numVotesPerUser; j += 1) {
const { voteOptionIndex, voteWeight, valid } = getTestVoteValues(i, j, numVotesPerUser, presetVotes, bribers);
const { voteOptionIndex, voteWeight } = getTestVoteValues(i, j, numVotesPerUser, presetVotes, bribers);
const vote = {
voteOptionIndex,
voteWeight,
nonce: j + 1,
valid,
};

votes.push(vote);
Expand Down
2 changes: 1 addition & 1 deletion website/versioned_docs/version-v1.x/audit.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: MACI Security Audits
description: In the summer of 2022, MACI v1 was audited by HashCloak. The audit covered both the zk-SNARK circuits and the Solidity smart contracts.
sidebar_label: Security Assessments
sidebar_position: 11
sidebar_position: 12
---

# Security Audits
Expand Down
2 changes: 1 addition & 1 deletion website/versioned_docs/version-v1.x/ci-pipeline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: CI Pipeline
description: Introduction to how MACI's CI works
sidebar_label: CI
sidebar_position: 12
sidebar_position: 13
---

# Continuous Integration (CI) Pipeline
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Coordinator local processing
description: How does the coordinator process and tallies messages locally
sidebar_label: Coordinator local processing
sidebar_position: 13
sidebar_position: 14
---

# Coordinator local processing
Expand Down
2 changes: 1 addition & 1 deletion website/versioned_docs/version-v1.x/integrating.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: Integrating MACI
description: How to integrate MACI into your application
sidebar_label: Integrating
sidebar_position: 10
sidebar_position: 11
---

# Integrating MACI
Expand Down
2 changes: 1 addition & 1 deletion website/versioned_docs/version-v1.x/key-change.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: MACI key change
description: How key change messages work
sidebar_label: Key change
sidebar_position: 15
sidebar_position: 16
---

# MACI Key Change
Expand Down
2 changes: 1 addition & 1 deletion website/versioned_docs/version-v1.x/spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
title: MACI v1.0 Specification
description: A detailed specification meant to assist auditors in reviewing MACI version 1.0
sidebar_label: Specification
sidebar_position: 14
sidebar_position: 15
---

# MACI v1.0 Specification
Expand Down
184 changes: 184 additions & 0 deletions website/versioned_docs/version-v1.x/testing-in-details.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,184 @@
---
title: MACI Testing in Details
description: How MACI tests work in details
sidebar_label: How Our Test Suites Work
sidebar_position: 10
---

# Testing

This doc extends on the [Testing](https://maci.pse.dev/docs/testing.md) doc and explains how MACI tests work in details. This information should be used by MACI's maintainers as well as contributors.

### CLI tests

MACI's CLI provides a series of commands that can be used by both the coordinator and voters, to interact with MACI, from deploying smart contracts to submitting a vote.

Currently, there are a number of test cases that are available inside the cli tests folder. The tests are split into two categories:

- e2e tests that include the entire MACI stack, from deploying the contracts to submitting a vote and tallying all results.
- e2e tests as above, but with the subsidy feature enabled.

The goal of these tests is to ensure that the MACI stack works as expected, and that the coordinator and voters can interact with the system as expected. They currently do not attempt to verify whether the tally results are expected, or that all votes were accounted for. On the other hand, they test different scenarios, mixing different numbers of voters and messages.

### Integration Tests

Integration tests follow a similar fashion of the CLI tests, though they also ensure that the tally results are as expected.

Currently, tests are defined using a JSON file, here is one example:

```json
{
"name": "Happy path",
"description": "Full tree, 4 batches, no bribers",
"numVotesPerUser": 1,
"numUsers": 15,
"expectedTally": [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedSpentVoiceCredits": [15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedTotalSpentVoiceCredits": 15
}
```

This test will generate 15 signups (as expressed in `numUsers`), and submit one vote (`numVotesPerUser`) for each of the users. As we did not provide any vote detail, it will use the default: `weight = 1`, `option = 0` for all voters. This will result of course in a tally result of 15 for option 0, and 0 for all other options.

Finally, the whole process of merging the state and message trees is performed, proofs are generated and the tally result is verified against the expected result.

#### How to implement a new test case

To add a new test cases, it is quite simple. You can amend the `integrationTests/ts/__tests__/data/suites.json` file and add your test declaration in there.

```json
{
"name": "Subsidy test",
"description": "has subsidy result",
"numUsers": 4,
"numVotesPerUser": 1,
"votes": {
"0": {
"0": { "voteOptionIndex": 0, "voteWeight": 1, "valid": true }
},
"1": {
"0": { "voteOptionIndex": 0, "voteWeight": 1, "valid": true }
},
"2": {
"0": { "voteOptionIndex": 0, "voteWeight": 1, "valid": true }
},
"3": {
"0": { "voteOptionIndex": 0, "voteWeight": 1, "valid": true }
}
},
"expectedTally": [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedSpentVoiceCredits": [4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedTotalSpentVoiceCredits": 4,
"subsidy": {
"enabled": true,
"expectedSubsidy": [117636, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
}
}
```

Let's look at the fields in detail:

- `name`: the name of the test case
- `description`: a description of the test case
- `numUsers`: the number of users to generate
- `numVotesPerUser`: the number of votes to generate for each user
- `votes`: the votes to generate. This is an object where the key is the user index, and the value is another object where the key is the message index, and the value is the vote details. If you do not provide any vote details, the default will be used: `weight = 1`, `option = 0` for all voters.
- `expectedTally`: the expected tally result for each vote option (in order)
- `expectedSpentVoiceCredits`: the expected spent voice credits for each vote option (in order)
- `expectedTotalSpentVoiceCredits`: the expected total spent voice credits
- `subsidy`: an object that contains the subsidy details. If you do not provide any subsidy details, the default will be used: `enabled = false`, `expectedSubsidy = []`. If you do provide subsidy details, you must provide both fields.

As an example, let's try to implement a test given the following criterias:

1. We want 10 users to signup
2. We want each user to publish a different vote
3. We want to verify that the tally result is as expected
4. We will not use the subsidy feature

```json
{
"name": "10 Users test",
"description": "Should signup 10 users, submit 10 votes and tally the results",
"numUsers": 10,
"numVotesPerUser": 1,
"votes": {
"0": {
"0": { "voteOptionIndex": 0, "voteWeight": 5 }
},
"1": {
"0": { "voteOptionIndex": 0, "voteWeight": 9 }
},
"2": {
"0": { "voteOptionIndex": 5, "voteWeight": 3 }
},
"3": {
"0": { "voteOptionIndex": 3, "voteWeight": 2 }
},
"4": {
"0": { "voteOptionIndex": 0, "voteWeight": 1 }
},
"5": {
"0": { "voteOptionIndex": 9, "voteWeight": 1 }
},
"6": {
"0": { "voteOptionIndex": 4, "voteWeight": 7 }
},
"7": {
"0": { "voteOptionIndex": 7, "voteWeight": 5 }
},
"8": {
"0": { "voteOptionIndex": 3, "voteWeight": 10 }
},
"9": {
"0": { "voteOptionIndex": 8, "voteWeight": 2 }
}
},
"expectedTally": [15, 0, 0, 12, 7, 3, 0, 5, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedSpentVoiceCredits": [107, 0, 0, 104, 49, 9, 0, 25, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"expectedTotalSpentVoiceCredits": 299
}
```

**Why expectedTally as above**

[(5 + 9 + 1), 0, 0, (2 + 10), 7, 3, 0, 5, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0] -> [15, 0, 0, 12, 7, 3, 0, 5, 2, 1, 0, 0, 0, 0, 0, 0, 0, 0]

**Why 299 voice credits spent**

- 5 ** 2 + 9 ** 2 + 3 ** 2 + 2 ** 2 + 1 ** 2 + 1 ** 1 + 7 ** 2 + 5 ** 2 + 10 ** 2 + 2 ** 2 = 25 + 81 + 9 + 4 + 1 + 1 + 49 + 25 + 100 + 4 = 299

**Why expectedSpentVoiceCredits as above**

[(25 + 81 + 1), 0, 0, (4 + 100), 49, 0, 25, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0] -> [107, 0, 0, 104, 49, 0, 25, 4, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]

#### MACI keys integration tests

Another test file which is found inside the integration tests folder is the `maciKeys.test.ts` file. This file contains a number of tests that are used to verify that the MACI keys work as expected. These tests are written in TypeScript and use the `mocha` and `chai` frameworks.

They are testing that between the `contracts`, `domainobjs` and `crypto` packages, the MACI keys are working correctly, and are serialized/deserialized as expected. This is particularly important to test due to different data formats for keys, especially when parsed from the smart contract events.

### Contract tests

Within the contracts folder, there are a number of tests that are used to verify that the contracts work as expected. These tests are written in TypeScript and use the `hardhat` framework.

These tests interact with all other packages, such as crypto, domainobjs and core, where mock data comes from. Their main goal is to ensure that the smart contracts have the correct parameters when deployed, privileged functions cannot be called by non-privileged users, and that the contract state is as expected after a series of operations.

### Circuits tests

Within the circuits folder, there are a number of tests that are used to verify that the circuits work as expected. These tests are written in TypeScript and use the `circom_tester` (which runs on top of `mocha` and `chai`).

These tests often use mock data from the `core` package. For instance, when testing the `processMessages` circuit, we are required to generate the parameters from the `core` packing, using the `Poll:processMessages` function. The same applies to vote tallying, where we need the `Poll:tally` function to be run first with mock users and vote messages.

All of the tests run using test parameters, usually `10, 2, 1, 2`, aside from the tests inside: [`ceremonyParam`](https://github.com/privacy-scaling-explorations/maci/blob/dev/circuits/ts/__tests__/CeremonyParams.test.ts) which use the parameters of the latest MACI ceremony. More details on the trusted setup can be found [here](https://maci.pse.dev/docs/trusted-setup).

### Core

The core package contains a number of tests that are used to verify that the core functions work as expected. These tests are written in TypeScript and use the `mocha` and `chai` frameworks.

These tests interact with the crypto and dombinobjs packages, where mock data comes from. Their main goal is to ensure that the core functions work as expected, and that the state is as expected after a series of operations.

Currently, there is a blend of e2e and unit tests, where e2e tests are used to verify that the entire MACI local processing works as expcted (users signup, publish votes, messages are processed and finally these votes are tallied). Unit tests on the other hand are used to verify that the core functions work as expected, such as `processMessage` and `tallyVotes`. You will find them in separate files, with e2e being [here](https://github.com/privacy-scaling-explorations/maci/blob/dev/core/ts/__tests__/e2e.test.ts) and unit tests in the other files.

### Domainobjs/Crypto tests

These tests are used to verify that MACI's primitives such as private keys work as expected. They are written in TypeScript and use the `mocha` and `chai` frameworks.
Loading

0 comments on commit 6497aac

Please sign in to comment.