Skip to content

Commit 94ab60a

Browse files
authored
Improve validation testing (#152)
1 parent 683b0b4 commit 94ab60a

10 files changed

+419
-456
lines changed

builder_test.go

+36-80
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,9 @@
11
package mcms_test
22

33
import (
4+
"encoding/json"
45
"errors"
5-
"fmt"
66
"testing"
7-
"time"
87

98
"github.com/ethereum/go-ethereum/common"
109
"github.com/go-playground/validator/v10"
@@ -13,19 +12,27 @@ import (
1312

1413
"github.com/smartcontractkit/mcms"
1514
"github.com/smartcontractkit/mcms/internal/testutils/chaintest"
16-
"github.com/smartcontractkit/mcms/internal/utils/safecast"
1715
"github.com/smartcontractkit/mcms/types"
1816
)
1917

2018
func TestProposalBuilder(t *testing.T) {
2119
t.Parallel()
2220

2321
// Define a fixed validUntil timestamp for consistency
24-
fixedValidUntil := int64(1893456000) // January 1, 2030
25-
fixedValidUntilCasted, err := safecast.Int64ToUint32(fixedValidUntil)
26-
require.NoError(t, err)
27-
pastValidUntilCast, err := safecast.Int64ToUint32(time.Now().Add(-24 * time.Hour).Unix())
28-
require.NoError(t, err)
22+
validUntil := uint32(1893456000) // January 1, 2030
23+
24+
tx1 := types.Transaction{
25+
To: "0x123",
26+
Data: []byte{0x01},
27+
AdditionalFields: json.RawMessage(`{"value": 0}`),
28+
}
29+
30+
tx2 := types.Transaction{
31+
To: "0x456",
32+
Data: []byte{0x02},
33+
AdditionalFields: json.RawMessage(`{"value": 0}`),
34+
}
35+
2936
tests := []struct {
3037
name string
3138
setup func(*mcms.ProposalBuilder)
@@ -36,20 +43,20 @@ func TestProposalBuilder(t *testing.T) {
3643
name: "valid Proposal",
3744
setup: func(b *mcms.ProposalBuilder) {
3845
b.SetVersion("v1").
39-
SetValidUntil(fixedValidUntilCasted).
46+
SetValidUntil(validUntil).
4047
SetDescription("Valid Proposal").
4148
SetOverridePreviousRoot(false).
4249
AddChainMetadata(chaintest.Chain2Selector, types.ChainMetadata{StartingOpCount: 0}).
4350
AddOperation(types.Operation{
4451
ChainSelector: chaintest.Chain2Selector,
45-
Transaction: types.Transaction{Data: []byte{0x01}},
52+
Transaction: tx1,
4653
})
4754
},
4855
want: &mcms.Proposal{
4956
BaseProposal: mcms.BaseProposal{
5057
Version: "v1",
5158
Kind: types.KindProposal,
52-
ValidUntil: fixedValidUntilCasted,
59+
ValidUntil: validUntil,
5360
Description: "Valid Proposal",
5461
OverridePreviousRoot: false,
5562
ChainMetadata: map[types.ChainSelector]types.ChainMetadata{
@@ -59,36 +66,36 @@ func TestProposalBuilder(t *testing.T) {
5966
Operations: []types.Operation{
6067
{
6168
ChainSelector: chaintest.Chain2Selector,
62-
Transaction: types.Transaction{Data: []byte{0x01}},
69+
Transaction: tx1,
6370
},
6471
},
6572
},
6673
wantErrs: nil,
6774
},
6875
{
69-
name: "valid Proposal using SetTransactions",
76+
name: "valid Proposal using SetOperations",
7077
setup: func(b *mcms.ProposalBuilder) {
7178
b.SetVersion("v1").
72-
SetValidUntil(fixedValidUntilCasted).
79+
SetValidUntil(validUntil).
7380
SetDescription("Valid Proposal").
7481
SetOverridePreviousRoot(false).
7582
AddChainMetadata(chaintest.Chain2Selector, types.ChainMetadata{StartingOpCount: 0}).
7683
SetOperations([]types.Operation{
7784
{
7885
ChainSelector: chaintest.Chain2Selector,
79-
Transaction: types.Transaction{Data: []byte{0x01}},
86+
Transaction: tx1,
8087
},
8188
{
8289
ChainSelector: chaintest.Chain2Selector,
83-
Transaction: types.Transaction{Data: []byte{0x02}},
90+
Transaction: tx2,
8491
},
8592
})
8693
},
8794
want: &mcms.Proposal{
8895
BaseProposal: mcms.BaseProposal{
8996
Version: "v1",
9097
Kind: types.KindProposal,
91-
ValidUntil: fixedValidUntilCasted,
98+
ValidUntil: validUntil,
9299
Description: "Valid Proposal",
93100
OverridePreviousRoot: false,
94101
ChainMetadata: map[types.ChainSelector]types.ChainMetadata{
@@ -98,11 +105,11 @@ func TestProposalBuilder(t *testing.T) {
98105
Operations: []types.Operation{
99106
{
100107
ChainSelector: chaintest.Chain2Selector,
101-
Transaction: types.Transaction{Data: []byte{0x01}},
108+
Transaction: tx1,
102109
},
103110
{
104111
ChainSelector: chaintest.Chain2Selector,
105-
Transaction: types.Transaction{Data: []byte{0x02}},
112+
Transaction: tx2,
106113
},
107114
},
108115
},
@@ -112,7 +119,7 @@ func TestProposalBuilder(t *testing.T) {
112119
name: "valid Proposal with signature and set chain metadata",
113120
setup: func(b *mcms.ProposalBuilder) {
114121
b.SetVersion("v1").
115-
SetValidUntil(fixedValidUntilCasted).
122+
SetValidUntil(validUntil).
116123
SetDescription("Valid Proposal").
117124
SetOverridePreviousRoot(false).
118125
SetChainMetadata(map[types.ChainSelector]types.ChainMetadata{
@@ -121,11 +128,11 @@ func TestProposalBuilder(t *testing.T) {
121128
SetOperations([]types.Operation{
122129
{
123130
ChainSelector: chaintest.Chain2Selector,
124-
Transaction: types.Transaction{Data: []byte{0x01}},
131+
Transaction: tx1,
125132
},
126133
{
127134
ChainSelector: chaintest.Chain2Selector,
128-
Transaction: types.Transaction{Data: []byte{0x02}},
135+
Transaction: tx2,
129136
},
130137
}).
131138
AddSignature(types.Signature{
@@ -138,7 +145,7 @@ func TestProposalBuilder(t *testing.T) {
138145
BaseProposal: mcms.BaseProposal{
139146
Version: "v1",
140147
Kind: types.KindProposal,
141-
ValidUntil: fixedValidUntilCasted,
148+
ValidUntil: validUntil,
142149
Description: "Valid Proposal",
143150
OverridePreviousRoot: false,
144151
Signatures: []types.Signature{{
@@ -153,84 +160,33 @@ func TestProposalBuilder(t *testing.T) {
153160
Operations: []types.Operation{
154161
{
155162
ChainSelector: chaintest.Chain2Selector,
156-
Transaction: types.Transaction{Data: []byte{0x01}},
163+
Transaction: tx1,
157164
},
158165
{
159166
ChainSelector: chaintest.Chain2Selector,
160-
Transaction: types.Transaction{Data: []byte{0x02}},
167+
Transaction: tx2,
161168
},
162169
},
163170
},
164171
wantErrs: nil,
165172
},
166173
{
167-
name: "Missing Version",
174+
name: "validation error",
168175
setup: func(b *mcms.ProposalBuilder) {
169-
b.SetValidUntil(fixedValidUntilCasted).
170-
SetDescription("Missing Version").
176+
b.SetValidUntil(validUntil).
177+
SetDescription("Valid Proposal").
171178
SetOverridePreviousRoot(false).
172179
AddChainMetadata(chaintest.Chain2Selector, types.ChainMetadata{StartingOpCount: 0}).
173180
AddOperation(types.Operation{
174181
ChainSelector: chaintest.Chain2Selector,
175-
Transaction: types.Transaction{Data: []byte{0x01}},
182+
Transaction: tx1,
176183
})
177184
},
178185
want: nil,
179186
wantErrs: []string{
180187
"Key: 'Proposal.BaseProposal.Version' Error:Field validation for 'Version' failed on the 'required' tag",
181188
},
182189
},
183-
{
184-
name: "ValidUntil in Past",
185-
setup: func(b *mcms.ProposalBuilder) {
186-
b.SetVersion("v1").
187-
SetValidUntil(pastValidUntilCast).
188-
SetDescription("ValidUntil in Past").
189-
SetOverridePreviousRoot(false).
190-
AddChainMetadata(chaintest.Chain2Selector, types.ChainMetadata{StartingOpCount: 0}).
191-
AddOperation(types.Operation{
192-
ChainSelector: chaintest.Chain2Selector,
193-
Transaction: types.Transaction{Data: []byte{0x01}},
194-
})
195-
},
196-
want: nil,
197-
wantErrs: []string{
198-
fmt.Sprintf("invalid valid until: %d", pastValidUntilCast),
199-
},
200-
},
201-
{
202-
name: "No Transactions",
203-
setup: func(b *mcms.ProposalBuilder) {
204-
b.SetVersion("v1").
205-
SetValidUntil(fixedValidUntilCasted).
206-
SetDescription("No Transactions").
207-
SetOverridePreviousRoot(false).
208-
AddChainMetadata(chaintest.Chain2Selector, types.ChainMetadata{StartingOpCount: 0})
209-
// No transactions added
210-
},
211-
want: nil,
212-
wantErrs: []string{
213-
"Key: 'Proposal.Operations' Error:Field validation for 'Operations' failed on the 'min' tag",
214-
},
215-
},
216-
{
217-
name: "Missing ChainMetadata",
218-
setup: func(b *mcms.ProposalBuilder) {
219-
b.SetVersion("v1").
220-
SetValidUntil(fixedValidUntilCasted).
221-
SetDescription("Missing ChainMetadata").
222-
SetOverridePreviousRoot(false).
223-
// ChainMetadata is not added
224-
AddOperation(types.Operation{
225-
ChainSelector: chaintest.Chain2Selector,
226-
Transaction: types.Transaction{Data: []byte{0x01}},
227-
})
228-
},
229-
want: nil,
230-
wantErrs: []string{
231-
"Key: 'Proposal.BaseProposal.ChainMetadata' Error:Field validation for 'ChainMetadata' failed on the 'min' tag",
232-
},
233-
},
234190
}
235191

236192
for _, tt := range tests {

builder_timelock_test.go

+15-34
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,13 @@ func TestTimelockProposalBuilder(t *testing.T) {
1616
t.Parallel()
1717

1818
// Define a fixed validUntil timestamp for consistency
19-
fixedValidUntil := uint32(1893456000) // January 1, 2030
19+
validUntil := uint32(1893456000) // January 1, 2030
20+
21+
tx1 := types.Transaction{
22+
Data: []byte{0x01},
23+
To: "0xContractAddress",
24+
AdditionalFields: json.RawMessage([]byte(`{"value": 0}`)),
25+
}
2026

2127
tests := []struct {
2228
name string
@@ -28,7 +34,7 @@ func TestTimelockProposalBuilder(t *testing.T) {
2834
name: "valid timelock proposal with setters",
2935
setup: func(b *mcms.TimelockProposalBuilder) {
3036
b.SetVersion("v1").
31-
SetValidUntil(fixedValidUntil).
37+
SetValidUntil(validUntil).
3238
SetDescription("Valid Timelock Proposal").
3339
SetOverridePreviousRoot(false).
3440
SetAction(types.TimelockActionSchedule).
@@ -41,21 +47,15 @@ func TestTimelockProposalBuilder(t *testing.T) {
4147
}).
4248
SetOperations([]types.BatchOperation{{
4349
ChainSelector: chaintest.Chain2Selector,
44-
Transactions: []types.Transaction{
45-
{
46-
Data: []byte{0x01},
47-
To: "0xContractAddress",
48-
AdditionalFields: json.RawMessage([]byte(`{"value": 0}`)),
49-
},
50-
},
50+
Transactions: []types.Transaction{tx1},
5151
},
5252
})
5353
},
5454
want: &mcms.TimelockProposal{
5555
BaseProposal: mcms.BaseProposal{
5656
Version: "v1",
5757
Kind: types.KindTimelockProposal,
58-
ValidUntil: fixedValidUntil,
58+
ValidUntil: validUntil,
5959
Description: "Valid Timelock Proposal",
6060
OverridePreviousRoot: false,
6161
ChainMetadata: map[types.ChainSelector]types.ChainMetadata{
@@ -70,13 +70,7 @@ func TestTimelockProposalBuilder(t *testing.T) {
7070
Operations: []types.BatchOperation{
7171
{
7272
ChainSelector: chaintest.Chain2Selector,
73-
Transactions: []types.Transaction{
74-
{
75-
Data: []byte{0x01},
76-
To: "0xContractAddress",
77-
AdditionalFields: json.RawMessage([]byte(`{"value": 0}`)),
78-
},
79-
},
73+
Transactions: []types.Transaction{tx1},
8074
},
8175
},
8276
},
@@ -85,7 +79,7 @@ func TestTimelockProposalBuilder(t *testing.T) {
8579
name: "valid timelock proposal with adders",
8680
setup: func(b *mcms.TimelockProposalBuilder) {
8781
b.SetVersion("v1").
88-
SetValidUntil(fixedValidUntil).
82+
SetValidUntil(validUntil).
8983
SetDescription("Valid Timelock Proposal").
9084
SetOverridePreviousRoot(false).
9185
SetAction(types.TimelockActionSchedule).
@@ -94,20 +88,14 @@ func TestTimelockProposalBuilder(t *testing.T) {
9488
AddTimelockAddress(chaintest.Chain2Selector, "0xTimelockAddress").
9589
AddOperation(types.BatchOperation{
9690
ChainSelector: chaintest.Chain2Selector,
97-
Transactions: []types.Transaction{
98-
{
99-
Data: []byte{0x01},
100-
To: "0xContractAddress",
101-
AdditionalFields: json.RawMessage([]byte(`{"value": 0}`)),
102-
},
103-
},
91+
Transactions: []types.Transaction{tx1},
10492
})
10593
},
10694
want: &mcms.TimelockProposal{
10795
BaseProposal: mcms.BaseProposal{
10896
Version: "v1",
10997
Kind: types.KindTimelockProposal,
110-
ValidUntil: fixedValidUntil,
98+
ValidUntil: validUntil,
11199
Description: "Valid Timelock Proposal",
112100
OverridePreviousRoot: false,
113101
ChainMetadata: map[types.ChainSelector]types.ChainMetadata{
@@ -122,20 +110,13 @@ func TestTimelockProposalBuilder(t *testing.T) {
122110
Operations: []types.BatchOperation{
123111
{
124112
ChainSelector: chaintest.Chain2Selector,
125-
Transactions: []types.Transaction{
126-
{
127-
Data: []byte{0x01},
128-
To: "0xContractAddress",
129-
AdditionalFields: json.RawMessage([]byte(`{"value": 0}`)),
130-
},
131-
},
113+
Transactions: []types.Transaction{tx1},
132114
},
133115
},
134116
},
135117
},
136118
{
137119
name: "validation fails: missing delay",
138-
want: nil,
139120
wantErr: true,
140121
},
141122
}

errors.go

+1-14
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ type InvalidProposalKindError struct {
1818
func (e *InvalidProposalKindError) Error() string {
1919
return fmt.Sprintf("invalid proposal kind: %s, value accepted is %s", e.ProvidedKind, e.AcceptedKind)
2020
}
21+
2122
func NewInvalidProposalKindError(provided, accepted types.ProposalKind) *InvalidProposalKindError {
2223
return &InvalidProposalKindError{ProvidedKind: provided, AcceptedKind: accepted}
2324
}
@@ -82,20 +83,6 @@ func (e *QuorumNotReachedError) Error() string {
8283
return fmt.Sprintf("quorum not reached for chain %d", e.ChainSelector)
8384
}
8485

85-
// InvalidDelayError is the error for when the received delay for Timelock is invalid.
86-
type InvalidDelayError struct {
87-
ReceivedDelay string
88-
}
89-
90-
// Error returns the error message.
91-
func (e *InvalidDelayError) Error() string {
92-
return fmt.Sprintf("invalid delay: %s", e.ReceivedDelay)
93-
}
94-
95-
func NewInvalidDelayError(receivedDelay string) *InvalidDelayError {
96-
return &InvalidDelayError{ReceivedDelay: receivedDelay}
97-
}
98-
9986
type InvalidValidUntilError struct {
10087
ReceivedValidUntil uint32
10188
}

0 commit comments

Comments
 (0)