Skip to content

Commit 9f83d68

Browse files
[NONEVM-3216] Setup coverage reports for timelock/mcms (#459)
* ref: use generateRandomContractId instead of crc32 * feat: init blockchain once per test * test: mcms and timelock test coverage * fix: name
1 parent 0c00768 commit 9f83d68

26 files changed

+522
-195
lines changed

contracts/tests/ccip/feequoter/FeeQuoter.getValidatedFee.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -414,7 +414,7 @@ describe('FeeQuoter GetValidatedFee', () => {
414414
})
415415
})
416416

417-
skip('should revert when fee token not supported', async () => {
417+
it.skip('should revert when fee token not supported', async () => {
418418
const notAFeeToken = FeeQuoterSetup.CUSTOM_TOKEN.token
419419

420420
const message: rt.CCIPSend = {

contracts/tests/ccip/onramp/OnRamp.setDynamicConfig.spec.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@ describe('OnRamp - set Dynamic Config', () => {
120120

121121
afterAll(async () => {
122122
if (process.env['COVERAGE'] === 'true') {
123-
coverage.generateCoverageArtifacts(blockchain, 'onramp_set-dynamic_config_tests', [
123+
await coverage.generateCoverageArtifacts(blockchain, 'onramp_set-dynamic_config_tests', [
124124
{
125125
code: await onramp.getCode(),
126126
name: 'onramp',

contracts/tests/coverage/coverage.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@ import { compile } from '@ton/blueprint'
22
import { Cell } from '@ton/core'
33
import { Blockchain } from '@ton/sandbox'
44
import { mkdirSync, writeFileSync } from 'fs'
5+
import { mcms } from '../../wrappers/mcms'
56

67
export const CoverageContractName = {
78
router: 'router',
@@ -12,6 +13,8 @@ export const CoverageContractName = {
1213
send_executor: 'send_executor',
1314
receive_executor: 'receive_executor',
1415
deployable: 'deployable',
16+
mcms: 'mcms',
17+
timelock: 'timelock',
1518
} as const
1619
export type CoverageConfigNames = keyof typeof CoverageContractName
1720

contracts/tests/coverage/scriptMergeCoverageIntoHtmlReports.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,8 @@ const onRampSuffix = `${coverage.CoverageContractName.onramp}.json`
1111
const sendExecutorSuffix = `${coverage.CoverageContractName.send_executor}.json`
1212
const receiveExecutorSuffix = `${coverage.CoverageContractName.receive_executor}.json`
1313
const deployableSuffix = `${coverage.CoverageContractName.deployable}.json`
14+
const mcmsSuffix = `${coverage.CoverageContractName.mcms}.json`
15+
const timelockSuffix = `${coverage.CoverageContractName.timelock}.json`
1416

1517
const offRampCoverageResults: Coverage[] = []
1618
const routerCoverageResults: Coverage[] = []
@@ -20,6 +22,8 @@ const onrampCoverageResults: Coverage[] = []
2022
const sendExecutorCoverageResults: Coverage[] = []
2123
const receiveExecutorCoverageResults: Coverage[] = []
2224
const deployableCoverageResults: Coverage[] = []
25+
const mcmsCoverageResults: Coverage[] = []
26+
const timelockCoverageResults: Coverage[] = []
2327

2428
const coverageDir = './.coverage'
2529

@@ -53,6 +57,12 @@ for (const file of files) {
5357
} else if (file.endsWith(deployableSuffix)) {
5458
const coverage = Coverage.fromJson(readFileSync(filePath, 'utf-8'))
5559
deployableCoverageResults.push(coverage)
60+
} else if (file.endsWith(mcmsSuffix)) {
61+
const coverage = Coverage.fromJson(readFileSync(filePath, 'utf-8'))
62+
mcmsCoverageResults.push(coverage)
63+
} else if (file.endsWith(timelockSuffix)) {
64+
const coverage = Coverage.fromJson(readFileSync(filePath, 'utf-8'))
65+
timelockCoverageResults.push(coverage)
5666
}
5767
}
5868

@@ -70,6 +80,8 @@ const onRampMerged = mergeResults(onrampCoverageResults)
7080
const sendExecutorMerged = mergeResults(sendExecutorCoverageResults)
7181
const receiveExecutorMerged = mergeResults(receiveExecutorCoverageResults)
7282
const deployableMerged = mergeResults(deployableCoverageResults)
83+
const mcmsMerged = mergeResults(mcmsCoverageResults)
84+
const timelockMerged = mergeResults(timelockCoverageResults)
7385

7486
// Generate HTML reports
7587
if (offRampMerged) {
@@ -135,3 +147,16 @@ if (deployableMerged) {
135147
)
136148
console.log('Generated deployable-coverage.html')
137149
}
150+
151+
if (mcmsMerged) {
152+
writeFileSync(`./.coverage/${coverage.CoverageContractName.mcms}.html`, mcmsMerged.report('html'))
153+
console.log('Generated mcms-coverage.html')
154+
}
155+
156+
if (timelockMerged) {
157+
writeFileSync(
158+
`./.coverage/${coverage.CoverageContractName.timelock}.html`,
159+
timelockMerged.report('html'),
160+
)
161+
console.log('Generated timelock-coverage.html')
162+
}

contracts/tests/lib/funding/WithdrawableSpec.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -432,7 +432,7 @@ export function newWithdrawableSpec<TContract extends withdrawable.Interface>(
432432
)
433433
const initialBalance = (await suiteSetup.blockchain.getContract(contract.address)).balance
434434

435-
testDrain(initialBalance, undefined, 5n, suiteSetup, contract)
435+
await testDrain(initialBalance, undefined, 5n, suiteSetup, contract)
436436
})
437437

438438
/**
@@ -447,7 +447,7 @@ export function newWithdrawableSpec<TContract extends withdrawable.Interface>(
447447
const initialBalance = (await suiteSetup.blockchain.getContract(contract.address)).balance
448448
const customReserve = customReserveAboveDefault(initialBalance)
449449

450-
testDrain(initialBalance, customReserve, 15n, suiteSetup, contract)
450+
await testDrain(initialBalance, customReserve, 15n, suiteSetup, contract)
451451
})
452452

453453
/**
@@ -462,7 +462,7 @@ export function newWithdrawableSpec<TContract extends withdrawable.Interface>(
462462
const initialBalance = (await suiteSetup.blockchain.getContract(contract.address)).balance
463463
const customReserve = customReserveBelowDefault()
464464

465-
testDrain(initialBalance, customReserve, 16n, suiteSetup, contract)
465+
await testDrain(initialBalance, customReserve, 16n, suiteSetup, contract)
466466
})
467467

468468
/**

contracts/tests/mcms/BaseTest.ts

Lines changed: 49 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,9 @@
11
import '@ton/test-utils'
2-
3-
import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'
2+
import { Blockchain, BlockchainSnapshot, SandboxContract, TreasuryContract } from '@ton/sandbox'
43
import { Cell, toNano, beginCell } from '@ton/core'
5-
import { compile } from '@ton/blueprint'
6-
import { crc32 } from 'zlib'
74

8-
import { asSnakeData } from '../../src/utils'
5+
import { asSnakeData, generateRandomContractId } from '../../src/utils'
6+
import * as coverage from '../coverage/coverage'
97

108
import { mcms, rbactl } from '../../wrappers/mcms'
119
import { ac } from '../../wrappers/lib/access'
@@ -46,11 +44,16 @@ export class BaseTestSetup {
4644
acc: TestAccounts
4745
bind: TestContracts
4846

49-
constructor() {
47+
readonly testSuite: string
48+
testID = 0
49+
snapshot: BlockchainSnapshot
50+
51+
constructor(testSuite: string) {
5052
this.blockchain = null as any
5153
this.code = null as any
5254
this.acc = null as any
5355
this.bind = null as any
56+
this.testSuite = testSuite
5457
}
5558

5659
static async compileContracts(): Promise<TestCode> {
@@ -88,6 +91,11 @@ export class BaseTestSetup {
8891
vmLogs: 'none',
8992
debugLogs: true,
9093
}
94+
if (process.env['COVERAGE'] === 'true') {
95+
this.blockchain.enableCoverage()
96+
this.blockchain.verbosity.print = false
97+
this.blockchain.verbosity.vmLogs = 'vm_logs_verbose'
98+
}
9199

92100
// Set up accounts
93101
this.acc = {
@@ -113,7 +121,7 @@ export class BaseTestSetup {
113121
/**
114122
* Setup the timelock contract with RBAC configuration
115123
*/
116-
async setupTimelockContract(testId: string): Promise<void> {
124+
async setupTimelockContract(): Promise<void> {
117125
const rbacStorage: ac.ContractData = {
118126
roles: ac.builder.data.rolesDict(
119127
new Map([
@@ -162,7 +170,7 @@ export class BaseTestSetup {
162170
}
163171

164172
const data = {
165-
id: crc32(`mcms.timelock.${testId}`),
173+
id: Number(generateRandomContractId()),
166174
minDelay: BaseTestSetup.MIN_DELAY,
167175
executorRoleCheckEnabled: true,
168176
opPendingInfo: {
@@ -184,9 +192,9 @@ export class BaseTestSetup {
184192
/**
185193
* Setup the counter contract
186194
*/
187-
async setupCounterContract(testId: string): Promise<void> {
195+
async setupCounterContract(): Promise<void> {
188196
const data = {
189-
id: BigInt(crc32(`mcms.counter.${testId}`)),
197+
id: generateRandomContractId(),
190198
value: 0,
191199
ownable: {
192200
owner: this.bind.timelock.address,
@@ -256,15 +264,20 @@ export class BaseTestSetup {
256264
})
257265
}
258266

259-
/**
260-
* Complete setup for all contracts - convenience method that combines all setup steps
261-
*/
262-
async setupAll(testId: string): Promise<void> {
263-
await this.initializeBlockchain()
264-
await this.setupTimelockContract(testId)
265-
await this.deployTimelockContract()
266-
await this.setupCounterContract(testId)
267-
await this.deployCounterContract()
267+
static async beforeAll(testsuite: string): Promise<BaseTestSetup> {
268+
const self = new BaseTestSetup(testsuite)
269+
self.code = await BaseTestSetup.compileContracts()
270+
await self.initializeBlockchain()
271+
await self.setupTimelockContract()
272+
await self.deployTimelockContract()
273+
await self.setupCounterContract()
274+
await self.deployCounterContract()
275+
self.snapshot = self.blockchain.snapshot()
276+
return self
277+
}
278+
279+
async beforeEach() {
280+
await this.blockchain.loadFrom(this.snapshot)
268281
}
269282

270283
/**
@@ -273,4 +286,21 @@ export class BaseTestSetup {
273286
warpTime(period: number) {
274287
this.blockchain.now = this.blockchain.now!! + period
275288
}
289+
290+
async generateCoverageArtifacts(): Promise<void> {
291+
await coverage.generateCoverageArtifacts(
292+
this.blockchain,
293+
`rbac_${this.testSuite}_${this.testID++}`,
294+
[
295+
{
296+
code: this.code.mcms,
297+
name: 'mcms',
298+
},
299+
{
300+
code: this.code.timelock,
301+
name: 'timelock',
302+
},
303+
],
304+
)
305+
}
276306
}

contracts/tests/mcms/Integration.spec.ts

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2,18 +2,17 @@ import '@ton/test-utils'
22

33
import { Blockchain, SandboxContract, TreasuryContract } from '@ton/sandbox'
44
import { Address, Cell, toNano } from '@ton/core'
5-
import { compile } from '@ton/blueprint'
65
import { SigningKey, randomBytes, computeAddress } from 'ethers'
76

8-
import { asSnakeData } from '../../src/utils'
7+
import { asSnakeData, generateRandomContractId } from '../../src/utils'
8+
import * as coverage from '../coverage/coverage'
99

1010
import { mcms } from '../../wrappers/mcms'
1111
import { rbactl } from '../../wrappers/mcms'
1212
import { ac } from '../../wrappers/lib/access'
1313
import * as counter from '../../wrappers/examples/Counter'
1414
import * as ownable2step from '../../wrappers/libraries/access/Ownable2Step'
1515

16-
import { crc32 } from 'zlib'
1716
import { merkleProof } from '../../src/mcms'
1817

1918
describe('MCMS - IntegrationTest', () => {
@@ -67,8 +66,16 @@ describe('MCMS - IntegrationTest', () => {
6766

6867
let signerKeyPairs: SigningKey[] = []
6968

70-
beforeEach(async () => {
69+
beforeAll(async () => {
7170
blockchain = await Blockchain.create()
71+
if (process.env['COVERAGE'] === 'true') {
72+
blockchain.enableCoverage()
73+
blockchain.verbosity.print = false
74+
blockchain.verbosity.vmLogs = 'vm_logs_verbose'
75+
}
76+
})
77+
78+
beforeEach(async () => {
7279
blockchain.now = Math.floor(Date.now() / 1000) // set to current unix timestamp
7380

7481
// Set up accounts
@@ -94,7 +101,7 @@ describe('MCMS - IntegrationTest', () => {
94101
bind.mcmsPropose = blockchain.openContract(
95102
mcms.ContractClient.newFrom(
96103
mcms.builder.data.contractDataEmpty(
97-
crc32('mcms.mcms.test-integration-propose'),
104+
Number(generateRandomContractId()),
98105
acc.deployer.address,
99106
),
100107
code.mcms,
@@ -104,7 +111,7 @@ describe('MCMS - IntegrationTest', () => {
104111
bind.mcmsVeto = blockchain.openContract(
105112
mcms.ContractClient.newFrom(
106113
mcms.builder.data.contractDataEmpty(
107-
crc32('mcms.mcms.test-integration-veto'),
114+
Number(generateRandomContractId()),
108115
acc.deployer.address,
109116
),
110117
code.mcms,
@@ -114,7 +121,7 @@ describe('MCMS - IntegrationTest', () => {
114121
bind.mcmsBypass = blockchain.openContract(
115122
mcms.ContractClient.newFrom(
116123
mcms.builder.data.contractDataEmpty(
117-
crc32('mcms.mcms.test-integration-bypass'),
124+
Number(generateRandomContractId()),
118125
acc.deployer.address,
119126
),
120127
code.mcms,
@@ -172,7 +179,7 @@ describe('MCMS - IntegrationTest', () => {
172179
}
173180

174181
const data = {
175-
id: crc32('mcms.timelock.test-integration'), // unique ID for this instance
182+
id: Number(generateRandomContractId()),
176183
minDelay: MIN_DELAY,
177184
executorRoleCheckEnabled: true,
178185
opPendingInfo: {
@@ -190,7 +197,7 @@ describe('MCMS - IntegrationTest', () => {
190197
// Set up Counter contract
191198
{
192199
const data = {
193-
id: crc32('mcms.counter.test-integration'), // unique ID for this instance
200+
id: Number(generateRandomContractId()),
194201
value: 0,
195202
ownable: {
196203
owner: bind.timelock.address,
@@ -1169,4 +1176,19 @@ describe('MCMS - IntegrationTest', () => {
11691176

11701177
proposePredecessor = callsHash
11711178
}, 20_000) // test can take a while
1179+
1180+
afterAll(async () => {
1181+
if (process.env['COVERAGE'] === 'true') {
1182+
await coverage.generateCoverageArtifacts(blockchain, 'rbac_mcms_integration', [
1183+
{
1184+
code: code.timelock,
1185+
name: 'timelock',
1186+
},
1187+
{
1188+
code: code.mcms,
1189+
name: 'mcms',
1190+
},
1191+
])
1192+
}
1193+
})
11721194
})

0 commit comments

Comments
 (0)