|
1 | 1 | package cosmwasm
|
2 | 2 |
|
3 | 3 | import (
|
| 4 | + "bytes" |
| 5 | + "crypto/sha256" |
| 6 | + "encoding/hex" |
| 7 | + "sync" |
4 | 8 | "testing"
|
5 | 9 |
|
| 10 | + "github.com/stretchr/testify/assert" |
6 | 11 | "github.com/stretchr/testify/require"
|
7 | 12 |
|
8 | 13 | "github.com/CosmWasm/wasmvm/v2/types"
|
9 | 14 | )
|
10 | 15 |
|
11 | 16 | func TestCreateChecksum(t *testing.T) {
|
12 |
| - // nil |
13 |
| - _, err := CreateChecksum(nil) |
14 |
| - require.ErrorContains(t, err, "nil or empty") |
| 17 | + tests := []struct { |
| 18 | + name string |
| 19 | + input []byte |
| 20 | + want types.Checksum |
| 21 | + wantErr bool |
| 22 | + errMsg string |
| 23 | + }{ |
| 24 | + { |
| 25 | + name: "Nil input", |
| 26 | + input: nil, |
| 27 | + wantErr: true, |
| 28 | + errMsg: "Wasm bytes nil or empty", |
| 29 | + }, |
| 30 | + { |
| 31 | + name: "Empty input", |
| 32 | + input: []byte{}, |
| 33 | + wantErr: true, |
| 34 | + errMsg: "Wasm bytes nil or empty", |
| 35 | + }, |
| 36 | + { |
| 37 | + name: "Too short (1 byte)", |
| 38 | + input: []byte{0x00}, |
| 39 | + wantErr: true, |
| 40 | + errMsg: "Wasm bytes shorter than 4 bytes", |
| 41 | + }, |
| 42 | + { |
| 43 | + name: "Too short (3 bytes)", |
| 44 | + input: []byte{0x00, 0x61, 0x73}, |
| 45 | + wantErr: true, |
| 46 | + errMsg: "Wasm bytes shorter than 4 bytes", |
| 47 | + }, |
| 48 | + { |
| 49 | + name: "Valid minimal Wasm", |
| 50 | + input: []byte{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00}, // "(module)" |
| 51 | + want: types.ForceNewChecksum("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"), |
| 52 | + wantErr: false, |
| 53 | + }, |
| 54 | + { |
| 55 | + name: "Invalid Wasm magic number", |
| 56 | + input: []byte{0x01, 0x02, 0x03, 0x04}, |
| 57 | + wantErr: true, |
| 58 | + errMsg: "Wasm bytes do not start with Wasm magic number", |
| 59 | + }, |
| 60 | + { |
| 61 | + name: "Text file", |
| 62 | + input: []byte("Hello world"), |
| 63 | + wantErr: true, |
| 64 | + errMsg: "Wasm bytes do not start with Wasm magic number", |
| 65 | + }, |
| 66 | + { |
| 67 | + name: "Large valid Wasm prefix", |
| 68 | + input: append([]byte{0x00, 0x61, 0x73, 0x6d}, bytes.Repeat([]byte{0x01}, 1024)...), |
| 69 | + want: types.ForceNewChecksum("38c467d192bb1bb8045a0dc45623305d63225c8361364281c112aef713c11b14"), // Precomputed SHA-256 |
| 70 | + wantErr: false, |
| 71 | + }, |
| 72 | + { |
| 73 | + name: "Exact 4 bytes with wrong magic", |
| 74 | + input: []byte{0xFF, 0xFF, 0xFF, 0xFF}, |
| 75 | + wantErr: true, |
| 76 | + errMsg: "Wasm bytes do not start with Wasm magic number", |
| 77 | + }, |
| 78 | + } |
15 | 79 |
|
16 |
| - // empty |
17 |
| - _, err = CreateChecksum([]byte{}) |
18 |
| - require.ErrorContains(t, err, "nil or empty") |
| 80 | + for _, tt := range tests { |
| 81 | + t.Run(tt.name, func(t *testing.T) { |
| 82 | + got, err := CreateChecksum(tt.input) |
| 83 | + if tt.wantErr { |
| 84 | + require.Error(t, err) |
| 85 | + require.Contains(t, err.Error(), tt.errMsg) |
| 86 | + assert.Equal(t, types.Checksum{}, got) |
| 87 | + } else { |
| 88 | + require.NoError(t, err) |
| 89 | + require.Equal(t, tt.want, got) |
| 90 | + // Verify the checksum is a valid SHA-256 hash |
| 91 | + hashBytes, err := hex.DecodeString(tt.want.String()) |
| 92 | + require.NoError(t, err) |
| 93 | + require.Len(t, hashBytes, 32) |
| 94 | + } |
| 95 | + }) |
| 96 | + } |
| 97 | +} |
| 98 | + |
| 99 | +// TestCreateChecksumConsistency ensures consistent output for the same input |
| 100 | +func TestCreateChecksumConsistency(t *testing.T) { |
| 101 | + input := []byte{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00} // Minimal valid Wasm |
| 102 | + expected := types.ForceNewChecksum("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476") |
19 | 103 |
|
20 |
| - // short |
21 |
| - _, err = CreateChecksum([]byte("\x00\x61\x73")) |
22 |
| - require.ErrorContains(t, err, " shorter than 4 bytes") |
| 104 | + for i := 0; i < 100; i++ { |
| 105 | + checksum, err := CreateChecksum(input) |
| 106 | + require.NoError(t, err) |
| 107 | + assert.Equal(t, expected, checksum, "Checksum should be consistent across runs") |
| 108 | + } |
| 109 | +} |
23 | 110 |
|
24 |
| - // Wasm blob returns correct hash |
25 |
| - // echo "(module)" > my.wat && wat2wasm my.wat && hexdump -C my.wasm && sha256sum my.wasm |
26 |
| - checksum, err := CreateChecksum([]byte("\x00\x61\x73\x6d\x01\x00\x00\x00")) |
| 111 | +// TestCreateChecksumLargeInput tests behavior with a large valid Wasm input |
| 112 | +func TestCreateChecksumLargeInput(t *testing.T) { |
| 113 | + // Create a large valid Wasm-like input (starts with magic number) |
| 114 | + largeInput := append([]byte{0x00, 0x61, 0x73, 0x6d}, bytes.Repeat([]byte{0xFF}, 1<<20)...) // 1MB |
| 115 | + checksum, err := CreateChecksum(largeInput) |
27 | 116 | require.NoError(t, err)
|
28 |
| - require.Equal(t, types.ForceNewChecksum("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"), checksum) |
29 | 117 |
|
30 |
| - // Text file fails |
31 |
| - _, err = CreateChecksum([]byte("Hello world")) |
32 |
| - require.ErrorContains(t, err, "do not start with Wasm magic number") |
| 118 | + // Compute expected SHA-256 manually to verify |
| 119 | + h := sha256.New() |
| 120 | + h.Write(largeInput) |
| 121 | + expected := types.ForceNewChecksum(hex.EncodeToString(h.Sum(nil))) |
| 122 | + |
| 123 | + assert.Equal(t, expected, checksum, "Checksum should match SHA-256 of large input") |
| 124 | +} |
| 125 | + |
| 126 | +// TestCreateChecksumInvalidMagicVariations tests variations of invalid Wasm magic numbers |
| 127 | +func TestCreateChecksumInvalidMagicVariations(t *testing.T) { |
| 128 | + invalidMagics := [][]byte{ |
| 129 | + {0x01, 0x61, 0x73, 0x6d}, // Wrong first byte |
| 130 | + {0x00, 0x62, 0x73, 0x6d}, // Wrong second byte |
| 131 | + {0x00, 0x61, 0x74, 0x6d}, // Wrong third byte |
| 132 | + {0x00, 0x61, 0x73, 0x6e}, // Wrong fourth byte |
| 133 | + } |
| 134 | + |
| 135 | + for _, input := range invalidMagics { |
| 136 | + _, err := CreateChecksum(input) |
| 137 | + require.Error(t, err) |
| 138 | + require.Contains(t, err.Error(), "Wasm bytes do not start with Wasm magic number") |
| 139 | + } |
| 140 | +} |
| 141 | + |
| 142 | +// TestCreateChecksumStress tests the function under high load with valid inputs |
| 143 | +func TestCreateChecksumStress(t *testing.T) { |
| 144 | + if testing.Short() { |
| 145 | + t.Skip("Skipping stress test in short mode") |
| 146 | + } |
| 147 | + |
| 148 | + validInput := []byte{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00} |
| 149 | + const iterations = 10000 |
| 150 | + |
| 151 | + for i := 0; i < iterations; i++ { |
| 152 | + checksum, err := CreateChecksum(validInput) |
| 153 | + require.NoError(t, err) |
| 154 | + require.Equal(t, types.ForceNewChecksum("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476"), checksum) |
| 155 | + } |
| 156 | +} |
| 157 | + |
| 158 | +// TestCreateChecksumConcurrent tests concurrent execution safety |
| 159 | +func TestCreateChecksumConcurrent(t *testing.T) { |
| 160 | + if testing.Short() { |
| 161 | + t.Skip("Skipping concurrent test in short mode") |
| 162 | + } |
| 163 | + |
| 164 | + validInput := []byte{0x00, 0x61, 0x73, 0x6d, 0x01, 0x00, 0x00, 0x00} |
| 165 | + expected := types.ForceNewChecksum("93a44bbb96c751218e4c00d479e4c14358122a389acca16205b1e4d0dc5f9476") |
| 166 | + const goroutines = 50 |
| 167 | + const iterations = 200 |
| 168 | + |
| 169 | + var wg sync.WaitGroup |
| 170 | + for i := 0; i < goroutines; i++ { |
| 171 | + wg.Add(1) |
| 172 | + go func() { |
| 173 | + defer wg.Done() |
| 174 | + for j := 0; j < iterations; j++ { |
| 175 | + checksum, err := CreateChecksum(validInput) |
| 176 | + assert.NoError(t, err) |
| 177 | + assert.Equal(t, expected, checksum) |
| 178 | + } |
| 179 | + }() |
| 180 | + } |
| 181 | + wg.Wait() |
33 | 182 | }
|
0 commit comments