Skip to content
This repository has been archived by the owner on Apr 30, 2024. It is now read-only.

New Unified Test Framework #90

Merged
merged 20 commits into from
Feb 14, 2024
Merged

New Unified Test Framework #90

merged 20 commits into from
Feb 14, 2024

Conversation

jdubpark
Copy link
Contributor

@jdubpark jdubpark commented Feb 13, 2024

Introduction

This PR introduces a new, unified testing framework, namely BaseTest.sol and DeployHelper.sol in test/foundry/utils. The former contract is to be inherited by all test contracts in unit and integration tests, where it will provide access to all contracts available on our core repo.

Through the BaseTest, a test contract can select which contracts to deploy as real contracts and which contracts to deploy as mock contracts. The framework lazy loads the deployments, so any contracts irrelevant to a test contract will not be deployed.

NOTE 1: when deploying contracts in a test, we must fully understand the dependencies of each deployed contract so that we deploy all necessary contracts. However, we don't have to deploy all dependencies (use mock instead).

NOTE 2: if facing a test error, check the full trace logs to see what errors or console2.logs are emitted. BaseTest and DeployHelper have logs to indicate both the deployment status (real/mock) and post-deployment status.

Test setUp Flow

The framework flow is:

  1. Inherit BaseTest and call BaseTest.setUp()
  2. Build deploy conditions using buildDeploy$$$Condition functions with corresponding Deploy$$$Condition structs, where "$$$" is a group of relevant contracts, such as registries and modules.
  3. Call deployConditionally() after building all deploy conditions.
  4. Call postDeploymentSetup() to set up the deployed contracts, such as initializing module addresses.

Example 1 (straightforward)

In this example, we deploy the registrationModule, disputeModule, ipResolver, arbitrationPolicySP, and royaltyPolicyLS. The post-deployment setup will set configs for these contracts, if applicable.
As a dependency, registrationModule requires a valid, deployed ipResolver (currently no mock).

function setUp() public override {
BaseTest.setUp();
buildDeployModuleCondition(
    DeployModuleCondition({
        registrationModule: true,
        disputeModule: true,
        royaltyModule: false,
        taggingModule: false,
        licensingModule: false
    })
);
buildDeployPolicyCondition(
    DeployPolicyCondition({
        arbitrationPolicySP: true,
        royaltyPolicyLS: true
    })
);
buildDeployMiscCondition(
    DeployMiscCondition({
        ipAssetRenderer: false,
        ipMetadataProvider: false,
        ipResolver: true
    })
);
deployConditionally();
postDeploymentSetup();
}

Example 2 (less straightforward)

In this example, we require three mock contracts: accessController, licensingModule, and royaltyModule. The getXXX methods retrieve existing contracts (if deployed via condition = true) OR deploy mock contracts.

function setUp() public override {
BaseTest.setUp();
buildDeployRegistryCondition(DeployRegistryCondition({ licenseRegistry: true, moduleRegistry: false }));
buildDeployModuleCondition(
    DeployModuleCondition({
        registrationModule: false,
        disputeModule: false,
        royaltyModule: false,
        taggingModule: false,
        licensingModule: true
    })
);
deployConditionally();
postDeploymentSetup();

// Call `getXXX` here to either deploy mock or use real contracted deploy via the
// deployConditionally() call above.
accessController = IAccessController(getAccessController());
licensingModule = ILicensingModule(getLicensingModule());
royaltyModule = IRoyaltyModule(getRoyaltyModule());
}

Caveat

As Example 2 shows, currently it's not possible to auto-deploy mock contracts lazily. As a future solution, instead of booleans, we should provide three options (enum) in deploy conditions: auto, mock, and real. With these options, we won't call getXXX to get a mock contract if there's no real contract deployed — the auto option will lazily deploy a mock contract.

Caution

While this framework makes deployment easier, it requires manual fixes when new contracts are introduced in existing groups, or if existing contracts get new dependencies. While this is mostly an easy intervention, dependency can require more custom logic as contracts can be deployed after the dependent contract.

Misc. Changes

  • Interface enhancements for various contracts
  • Script import fixes
  • More Mock files and reorganization

@jdubpark jdubpark requested review from leeren, Spablob and a team and removed request for leeren, Spablob and a team February 13, 2024 06:27
Copy link
Contributor

@Ramarti Ramarti left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @jdubpark, an unified test framework is a huge improvement. Always easier to start with one that that move to one, great effort.

Not for this PR, but onwards to mainnet we have to try and minimize mocking to maybe the tokens and external contracts IMO. Mocks have allowed us to work in parallel, but they are more code to maintain and make the tests arguably weaker. It will be easier with this framework.

test/foundry/IPAssetRegistry.t.sol Outdated Show resolved Hide resolved
contracts/interfaces/IAccessController.sol Outdated Show resolved Hide resolved
test/foundry/utils/BaseTest.sol Outdated Show resolved Hide resolved
@Ramarti Ramarti self-requested a review February 14, 2024 06:58
@jdubpark jdubpark merged commit b3152a3 into main Feb 14, 2024
1 check passed
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants