|
37 | 37 | // |
38 | 38 | // Here's a simple example of using the runtime to execute a changeset: |
39 | 39 | // |
40 | | -// import ( |
41 | | -// "testing" |
| 40 | +// import ( |
| 41 | +// "testing" |
42 | 42 | // |
43 | | -// "github.com/stretchr/testify/require" |
| 43 | +// "github.com/stretchr/testify/require" |
44 | 44 | // |
45 | | -// testenv "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/environment" |
46 | | -// "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime" |
47 | | -// ) |
48 | | -// |
49 | | -// func TestMyDeployment(t *testing.T) { |
50 | | -// // Test environment with a simulated EVM blockchain |
51 | | -// loader := testenv.NewLoader() |
52 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 1)) |
53 | | -// require.NoError(t, err) |
| 45 | +// testenv "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/environment" |
| 46 | +// "github.com/smartcontractkit/chainlink-deployments-framework/engine/test/runtime" |
| 47 | +// ) |
54 | 48 | // |
55 | | -// // Create runtime instance |
56 | | -// runtime := NewFromEnvironment(*env) |
| 49 | +// func TestMyDeployment(t *testing.T) { |
| 50 | +// // Create runtime instance with a simulated EVM blockchain |
| 51 | +// runtime := New(t.Context(), WithEnvOpts( |
| 52 | +// testenv.WithEVMSimulatedN(t, 1) |
| 53 | +// )) |
57 | 54 | // |
58 | | -// // Execute a changeset |
59 | | -// task := ChangesetTask(myChangeset, MyChangesetConfig{ |
60 | | -// Parameter1: "value1", |
61 | | -// Parameter2: 42, |
62 | | -// }) |
| 55 | +// // Execute a changeset |
| 56 | +// task := ChangesetTask(myChangeset, MyChangesetConfig{ |
| 57 | +// Parameter1: "value1", |
| 58 | +// Parameter2: 42, |
| 59 | +// }) |
63 | 60 | // |
64 | | -// err := runtime.Exec(task) |
65 | | -// require.NoError(t, err) |
| 61 | +// err := runtime.Exec(task) |
| 62 | +// require.NoError(t, err) |
66 | 63 | // |
67 | | -// // Verify deployment results |
68 | | -// addrs, err := runtime.State().DataStore.Addresses().Fetch() |
69 | | -// require.NoError(t, err) |
70 | | -// assert.Len(t, addrs, 1) |
71 | | -// } |
| 64 | +// // Verify deployment results |
| 65 | +// addrs, err := runtime.State().DataStore.Addresses().Fetch() |
| 66 | +// require.NoError(t, err) |
| 67 | +// assert.Len(t, addrs, 1) |
| 68 | +// } |
72 | 69 | // |
73 | 70 | // # Sequential Changeset Execution |
74 | 71 | // |
|
77 | 74 | // will include the data of the previous changesets execution. |
78 | 75 | // |
79 | 76 | // func TestMultiStepDeployment(t *testing.T) { |
80 | | -// // Load test environment with multiple EVM chains |
81 | | -// loader := testenv.NewLoader() |
82 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 1)) |
83 | | -// require.NoError(t, err) |
84 | | -// |
85 | | -// runtime := NewFromEnvironment(*env) |
| 77 | +// // Create runtime instance with a simulated EVM blockchain |
| 78 | +// runtime := New(t.Context(), WithEnvOpts( |
| 79 | +// testenv.WithEVMSimulatedN(t, 1) |
| 80 | +// )) |
86 | 81 | // |
87 | 82 | // // Define the first changeset |
88 | 83 | // coreTask := ChangesetTask(coreChangeset, CoreConfig{}) |
|
106 | 101 | // The engine/test/environment package provides various blockchain loading options: |
107 | 102 | // |
108 | 103 | // // EVM simulated blockchains (fast, in-memory) |
109 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 2)) |
| 104 | +// env, err := testenv.New(ctx, testenv.WithEVMSimulatedN(t, 2)) |
110 | 105 | // |
111 | 106 | // // Specific chain selectors |
112 | | -// env, err := loader.Load(t, testenv.WithEVMSimulated(t, []uint64{ |
| 107 | +// env, err := testenv.New(ctx, testenv.WithEVMSimulated(t, []uint64{ |
113 | 108 | // chainsel.ETHEREUM_TESTNET_SEPOLIA.Selector, |
114 | 109 | // chainsel.POLYGON_TESTNET_MUMBAI.Selector, |
115 | 110 | // })) |
116 | 111 | // |
117 | 112 | // // Multiple blockchain types |
118 | | -// env, err := loader.Load(t, |
| 113 | +// env, err := testenv.New(ctx, |
119 | 114 | // testenv.WithEVMSimulatedN(t, 1), |
120 | 115 | // testenv.WithSolanaContainerN(t, 1, "/path/to/programs", programIDs), |
121 | 116 | // testenv.WithTonContainerN(t, 1), |
|
126 | 121 | // ChainID: 1337, |
127 | 122 | // BlockTime: time.Second, |
128 | 123 | // } |
129 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedWithConfigN(t, 1, cfg)) |
| 124 | +// env, err := testenv.New(t, testenv.WithEVMSimulatedWithConfigN(t, 1, cfg)) |
130 | 125 | // |
131 | 126 | // # Error Handling |
132 | 127 | // |
|
135 | 130 | // |
136 | 131 | // func TestErrorHandling(t *testing.T) { |
137 | 132 | // // Load test environment |
138 | | -// loader := testenv.NewLoader() |
139 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 1)) |
| 133 | +// env, err := testenv.New(t, testenv.WithEVMSimulatedN(t, 1)) |
140 | 134 | // require.NoError(t, err) |
141 | 135 | // |
142 | 136 | // runtime := NewFromEnvironment(*env) |
|
162 | 156 | // |
163 | 157 | // func TestStateInspection(t *testing.T) { |
164 | 158 | // // Load test environment |
165 | | -// loader := testenv.NewLoader() |
166 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 1)) |
| 159 | +// env, err := testenv.New(t, testenv.WithEVMSimulatedN(t, 1)) |
167 | 160 | // require.NoError(t, err) |
168 | 161 | // |
169 | 162 | // runtime := NewFromEnvironment(*env) |
|
205 | 198 | // |
206 | 199 | // // Subtests can each have their own runtime instance |
207 | 200 | // t.Run("deployment_scenario_1", func(t *testing.T) { |
208 | | -// loader := testenv.NewLoader() |
209 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 1)) |
| 201 | +// env, err := testenv.New(ctx, testenv.WithEVMSimulatedN(t, 1)) |
210 | 202 | // require.NoError(t, err) |
211 | 203 | // |
212 | 204 | // runtime := NewFromEnvironment(*env) |
|
216 | 208 | // }) |
217 | 209 | // |
218 | 210 | // t.Run("deployment_scenario_2", func(t *testing.T) { |
219 | | -// loader := testenv.NewLoader() |
220 | | -// env, err := loader.Load(t, testenv.WithEVMSimulatedN(t, 2)) |
| 211 | +// env, err := testenv.New(t, testenv.WithEVMSimulatedN(t, 2)) |
221 | 212 | // require.NoError(t, err) |
222 | 213 | // |
223 | 214 | // runtime := NewFromEnvironment(*env) |
|
227 | 218 | // }) |
228 | 219 | // } |
229 | 220 | // |
| 221 | +// # MCMS Proposals |
| 222 | +// |
| 223 | +// The runtime provides specialized tasks for handling Multi-Chain Multi-Sig (MCMS) proposals. |
| 224 | +// |
| 225 | +// ## Available MCMS Tasks |
| 226 | +// |
| 227 | +// **SignProposalTask(proposalID, signingKeys...)** - Signs MCMS or Timelock proposals with |
| 228 | +// one or more private keys. The task automatically detects the proposal type and applies |
| 229 | +// the appropriate signing logic. Multiple signatures can be added in a single operation |
| 230 | +// or accumulated across multiple signing tasks. |
| 231 | +// |
| 232 | +// **ExecuteProposalTask(proposalID)** - Executes a signed MCMS or Timelock proposal on |
| 233 | +// the target blockchain networks. The task handles chain-specific configurations, sets |
| 234 | +// merkle roots, executes operations sequentially, and confirms all transactions. For |
| 235 | +// Timelock proposals, it manages scheduling and delay mechanisms. |
| 236 | +// |
| 237 | +// **SignAndExecuteProposalsTask(signingKeys)** - Processes all pending proposals in the |
| 238 | +// runtime state by signing them with the provided keys and executing them in batch. |
| 239 | +// This is useful for scenarios where multiple changesets generate proposals that need |
| 240 | +// to be processed together or you want to just execute all pending proposals. |
| 241 | +// |
| 242 | +// ## Usage Pattern |
| 243 | +// |
| 244 | +// MCMS proposals follow a three-phase workflow: |
| 245 | +// 1. **Generation**: Changesets create proposals and store them in runtime state. This is done by running a ChangesetTask. |
| 246 | +// 2. **Signing**: Use SignProposalTask to add cryptographic signatures |
| 247 | +// 3. **Execution**: Use ExecuteProposalTask to apply changes on target chains |
| 248 | +// |
| 249 | +// The runtime automatically manages proposal state, tracking which proposals are pending, |
| 250 | +// signed, or executed. Both standard MCMS proposals and Timelock proposals are supported |
| 251 | +// through the same task interface. |
| 252 | +// |
230 | 253 | // # Best Practices |
231 | 254 | // |
232 | 255 | // - Create a new runtime instance for each test to ensure isolation. |
233 | 256 | // - Be wary when using containerized chains as they take a long time to start containers. It is better to write a |
234 | 257 | // longer test with a single containerized chain than to write a shorter test with multiple containerized chains. |
235 | 258 | // - Verify both intermediate and final state in multi-step tests |
236 | 259 | // - Leverage the runtime's error handling for negative test cases |
| 260 | +// - Use SignAndExecuteProposalsTask for processing, avoiding the need to fetch the proposal ID from state. |
237 | 261 | // |
238 | 262 | // # Common Patterns |
239 | 263 | // |
|
0 commit comments