Skip to content

Commit

Permalink
test: proof of concept 2e2 test using anvil devchain (#11020)
Browse files Browse the repository at this point in the history
* chore(test-sol/FeeCurrencyDirectory)): use `@celo-...` remapping not `../..`

* test(test-sol/FeeCurrencyDirectory)): MVP e2e test

MVP demo of an e2e test using the devchain. This is not the pattern I'll suggest, but good to see the test passes end-to-end.

* chore(foundry.toml): adds `@test-sol` remapping

* chore(test-sol/e2e): adds MVP `utils.sol`

Idea is to have a Devchain class that can be inherited by Test contracts to have access to the deployed contracts on the devchain.

* test(FeeCurrencyDirectory): MVP test using `Devchain` class

* chore(migrations_sol): adds MVP script to run e2e tests

* style(test-sol/e2e): linting

* refactor(test-sol/FeeCurrencyDirectory): moves file to `.../e2e/`

* chore(migrations_sol): use `test-sol/e2e/*` path

* chore(test-sol/FeeCurrencyDirectory): match contract name in unit and e2e test

* style(test-sol/FeeCurrencyDirectory): linting

* chore(e2e/utils): removes unused imports and more

Cleans up
Adds `TODO` comments

* test(test-sol/e2e): renames contract with "E2E..."

I'm temporarily adding the "E2E..." prefix to the contract so I can exclude this test and the integration tests during the CI run.

In a separate PR, I'll refactor the tests into a directory structure like:

```
test-sol/unit/
test-sol/e2e/
test-sol/integration/
```

That way we could run tests with something like this:

```
# unit tests
forge test --match-path "*test-sol/unit/*"

# e2e tests
forge test --match-path "*test-sol/e2e/*"

# integration tests
forge test --match-path "*test-sol/integration/*"
```

* chore(workflows/protocol_tests): excludes e2e test from workflow

I'm temporarily adding the "E2E..." prefix to the contract so I can exclude this test and the integration tests during the CI run.

In a separate PR, I'll refactor the tests into a directory structure like:

```
test-sol/unit/
test-sol/e2e/
test-sol/integration/
```

That way we could run tests with something like this:

```
# unit tests
forge test --match-path "*test-sol/unit/*"

# e2e tests
forge test --match-path "*test-sol/e2e/*"

# integration tests
forge test --match-path "*test-sol/integration/*"
```

* style(test-sol/e2e): linting

* chore(e2e): temporarily renames contract with "E2E..."

In subsequent PRs, I'll rename this more accurately.
  • Loading branch information
arthurgousset authored Jun 7, 2024
1 parent 95af1c6 commit b10b77a
Show file tree
Hide file tree
Showing 6 changed files with 85 additions and 5 deletions.
4 changes: 2 additions & 2 deletions .github/workflows/protocol_tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -94,10 +94,10 @@ jobs:
exit 1
fi
- name: Run Everything just in case something was missed
- name: Run everything just in case something was missed (excl. integration and e2e tests)
# can't use gas limit because some setUp function use more than the limit
# Excludes integration tests, because they require an anvil devchain running on the localhost.
run: forge test -vvv --no-match-contract RegistryIntegrationTest
run: forge test -vvv --no-match-contract "RegistryIntegrationTest|E2EDemo"

- name: Generate migrations
if: success() || failure()
Expand Down
3 changes: 2 additions & 1 deletion packages/protocol/foundry.toml
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,8 @@ remappings = [
'@celo-contracts-8=contracts-0.8/',
'@openzeppelin/contracts8/=lib/openzeppelin-contracts8/contracts/',
'@celo-contracts/=contracts/',
'@celo-migrations/=migrations_sol/'
'@celo-migrations/=migrations_sol/',
'@test-sol/=test-sol/'
]

no_match_test = "skip"
Expand Down
21 changes: 21 additions & 0 deletions packages/protocol/migrations_sol/run_e2e_tests_in_anvil.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
#!/usr/bin/env bash
set -euo pipefail

# Generate and run devchain
echo "Generating and running devchain before running e2e tests..."
source $PWD/migrations_sol/create_and_migrate_anvil_devchain.sh

# Run e2e tests
echo "Running e2e tests..."
forge test \
-vvv \
--match-path "*test-sol/e2e/*" \
--fork-url http://127.0.0.1:$ANVIL_PORT

# helper kill anvil
# kill $(lsof -i tcp:$ANVIL_PORT | tail -n 1 | awk '{print $2}')

echo "Killing Anvil"
if [[ -n $ANVIL_PID ]]; then
kill $ANVIL_PID
fi
4 changes: 2 additions & 2 deletions packages/protocol/test-sol/common/FeeCurrencyDirectory.t.sol
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,8 @@
pragma solidity >=0.8.7 <0.8.20;

import "celo-foundry-8/Test.sol";
import "../../contracts-0.8/common/FeeCurrencyDirectory.sol";
import "../../contracts-0.8/common/mocks/MockOracle.sol";
import "@celo-contracts-8/common/FeeCurrencyDirectory.sol";
import "@celo-contracts-8/common/mocks/MockOracle.sol";

contract FeeCurrencyDirectoryTestBase is Test {
FeeCurrencyDirectory directory;
Expand Down
23 changes: 23 additions & 0 deletions packages/protocol/test-sol/e2e/common/FeeCurrencyDirectory.t.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.7 <0.8.20;

import "celo-foundry-8/Test.sol";
import { Devchain } from "@test-sol/e2e/utils.sol";

import "@celo-contracts-8/common/FeeCurrencyDirectory.sol";

contract E2EDemo is Test, Devchain {
function test_ShouldAllowOwnerSetCurrencyConfig() public {
address token = address(1);
uint256 intrinsicGas = 21000;

vm.prank(feeCurrencyDirectory.owner());
feeCurrencyDirectory.setCurrencyConfig(token, address(sortedOracles), intrinsicGas);
FeeCurrencyDirectory.CurrencyConfig memory config = feeCurrencyDirectory.getCurrencyConfig(
token
);

assertEq(config.oracle, address(sortedOracles));
assertEq(config.intrinsicGas, intrinsicGas);
}
}
35 changes: 35 additions & 0 deletions packages/protocol/test-sol/e2e/utils.sol
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
// SPDX-License-Identifier: UNLICENSED
pragma solidity >=0.8.7 <0.8.20;

import "@celo-contracts-8/common/UsingRegistry.sol";
import "@celo-contracts/common/interfaces/IRegistry.sol";

// All core contracts that are expected to be in the Registry on the devchain
import "@celo-contracts-8/common/FeeCurrencyDirectory.sol";
import "@celo-contracts/stability/interfaces/ISortedOracles.sol";

contract Devchain is UsingRegistry {
address constant registryAddress = address(0x000000000000000000000000000000000000ce10);

// Used in exceptional circumstances when a contract is not in UsingRegistry.sol
IRegistry devchainRegistry = IRegistry(registryAddress);

// All core contracts that are expected to be in the Registry on the devchain
ISortedOracles sortedOracles;
FeeCurrencyDirectory feeCurrencyDirectory;

constructor() {
// The following line is required by UsingRegistry.sol
setRegistry(registryAddress);

// Fetch all core contracts that are expeceted to be in the Registry on the devchain
sortedOracles = getSortedOracles();
feeCurrencyDirectory = FeeCurrencyDirectory(
devchainRegistry.getAddressForStringOrDie("FeeCurrencyDirectory")
); // FeeCurrencyDirectory is not in UsingRegistry.sol

// TODO: Add missing core contracts below (see list in migrations_sol/constants.sol)
// TODO: Consider asserting that all contracts we expect are available in the Devchain class
// (see list in migrations_sol/constants.sol)
}
}

0 comments on commit b10b77a

Please sign in to comment.