github.com/9elements/firmware-action/action@v0.0.0-20240514065043-044ed91c9ed8/recipes/config_test.go (about) 1 // SPDX-License-Identifier: MIT 2 3 // Package recipes / coreboot 4 package recipes 5 6 import ( 7 "fmt" 8 "os" 9 "path/filepath" 10 "testing" 11 12 "github.com/google/go-cmp/cmp" 13 "github.com/stretchr/testify/assert" 14 ) 15 16 func TestValidateConfig(t *testing.T) { 17 commonDummy := CommonOpts{ 18 SdkURL: "ghcr.io/9elements/firmware-action/coreboot_4.19:main", 19 RepoPath: "dummy/dir/", 20 OutputDir: "dummy/dir/", 21 } 22 23 testCases := []struct { 24 name string 25 wantErr error 26 opts Config 27 }{ 28 { 29 name: "completely empty", 30 wantErr: nil, 31 opts: Config{}, 32 }, 33 { 34 name: "empty coreboot opts", 35 wantErr: nil, 36 opts: Config{ 37 Coreboot: map[string]CorebootOpts{}, 38 }, 39 }, 40 { 41 name: "missing required coreboot opts", 42 wantErr: ErrFailedValidation, 43 opts: Config{ 44 Coreboot: map[string]CorebootOpts{ 45 "coreboot-A": {}, 46 }, 47 }, 48 }, 49 { 50 name: "required coreboot opts present", 51 wantErr: nil, 52 opts: Config{ 53 Coreboot: map[string]CorebootOpts{ 54 "coreboot-A": { 55 CommonOpts: commonDummy, 56 DefconfigPath: "dummy", 57 }, 58 }, 59 }, 60 }, 61 { 62 name: "required coreboot opts present 2", 63 wantErr: nil, 64 opts: Config{ 65 Coreboot: map[string]CorebootOpts{ 66 "coreboot-A": { 67 CommonOpts: commonDummy, 68 DefconfigPath: "dummy", 69 Blobs: CorebootBlobs{}, 70 }, 71 }, 72 }, 73 }, 74 { 75 name: "missing common opts", 76 wantErr: ErrFailedValidation, 77 opts: Config{ 78 Coreboot: map[string]CorebootOpts{ 79 "coreboot-A": { 80 CommonOpts: CommonOpts{}, 81 DefconfigPath: "dummy", 82 Blobs: CorebootBlobs{}, 83 }, 84 }, 85 }, 86 }, 87 } 88 for _, tc := range testCases { 89 t.Run(tc.name, func(t *testing.T) { 90 err := ValidateConfig(tc.opts) 91 assert.ErrorIs(t, err, tc.wantErr) 92 }) 93 } 94 } 95 96 func TestConfigReadAndWrite(t *testing.T) { 97 configOriginal := Config{ 98 Coreboot: map[string]CorebootOpts{}, 99 Linux: map[string]LinuxOpts{}, 100 Edk2: map[string]Edk2Opts{}, 101 } 102 103 tmpDir := t.TempDir() 104 configFilepath := filepath.Join(tmpDir, "test.json") 105 106 // Write 107 err := WriteConfig(configFilepath, &configOriginal) 108 assert.NoError(t, err) 109 110 // Read 111 configNew, err := ReadConfig(configFilepath) 112 assert.NoError(t, err) 113 114 // Compare 115 equal := cmp.Equal(&configOriginal, configNew) 116 if !equal { 117 fmt.Println(cmp.Diff(configOriginal, configNew)) 118 assert.True(t, equal, "written and read configuration are not equal") 119 } 120 } 121 122 func TestConfigEnvVars(t *testing.T) { 123 commonDummy := CommonOpts{ 124 SdkURL: "ghcr.io/9elements/firmware-action/coreboot_4.19:main", 125 RepoPath: "dummy/dir/", 126 OutputDir: "dummy/dir/", 127 } 128 129 testCases := []struct { 130 name string 131 wantErr error 132 url string 133 urlExpected string 134 repoPath string 135 repoPathExpected string 136 envVars map[string]string 137 }{ 138 { 139 name: "no env vars", 140 wantErr: nil, 141 url: commonDummy.SdkURL, 142 urlExpected: commonDummy.SdkURL, 143 repoPath: commonDummy.RepoPath, 144 repoPathExpected: commonDummy.RepoPath, 145 envVars: map[string]string{}, 146 }, 147 { 148 name: "env vars", 149 wantErr: nil, 150 url: "ghcr.io/$TEST_ENV_VAR/coreboot_4.19:main", 151 urlExpected: commonDummy.SdkURL, 152 repoPath: commonDummy.RepoPath, 153 repoPathExpected: commonDummy.RepoPath, 154 envVars: map[string]string{ 155 "TEST_ENV_VAR": "9elements/firmware-action", 156 }, 157 }, 158 { 159 name: "env vars with brackets", 160 wantErr: nil, 161 url: "ghcr.io/${TEST_ENV_VAR}/coreboot_4.19:main", 162 urlExpected: commonDummy.SdkURL, 163 repoPath: commonDummy.RepoPath, 164 repoPathExpected: commonDummy.RepoPath, 165 envVars: map[string]string{ 166 "TEST_ENV_VAR": "9elements/firmware-action", 167 }, 168 }, 169 { 170 name: "multiple env vars in multiple entries", 171 wantErr: nil, 172 url: "ghcr.io/${TEST_ENV_VAR_PROJECT}/${TEST_ENV_VAR_SDK}:${TEST_ENV_VAR_VERSION}", 173 urlExpected: commonDummy.SdkURL, 174 repoPath: "${TEST_ENV_VAR_REPOPATH}", 175 repoPathExpected: commonDummy.RepoPath, 176 envVars: map[string]string{ 177 "TEST_ENV_VAR_PROJECT": "9elements/firmware-action", 178 "TEST_ENV_VAR_VERSION": "main", 179 "TEST_ENV_VAR_SDK": "coreboot_4.19", 180 "TEST_ENV_VAR_REPOPATH": "dummy/dir/", 181 }, 182 }, 183 } 184 for _, tc := range testCases { 185 t.Run(tc.name, func(t *testing.T) { 186 opts := Config{ 187 Coreboot: map[string]CorebootOpts{ 188 "coreboot-A": { 189 CommonOpts: CommonOpts{ 190 SdkURL: tc.url, 191 RepoPath: "dummy/dir/", 192 OutputDir: "dummy/dir/", 193 }, 194 DefconfigPath: "dummy", 195 }, 196 }, 197 } 198 for key, value := range tc.envVars { 199 os.Setenv(key, value) 200 defer os.Unsetenv(key) 201 fmt.Printf("Setting %s = %s\n", key, value) 202 } 203 204 // Write and read config 205 // The read function handles the expansion of environment variables 206 tmpDir := t.TempDir() 207 configFilepath := filepath.Join(tmpDir, "test.json") 208 // Write 209 err := WriteConfig(configFilepath, &opts) 210 assert.NoError(t, err) 211 // Read 212 optsConverted, err := ReadConfig(configFilepath) 213 assert.NoError(t, err) 214 215 // err = ValidateConfig(optsConverted) 216 assert.ErrorIs(t, err, tc.wantErr) 217 assert.Equal(t, tc.urlExpected, optsConverted.Coreboot["coreboot-A"].SdkURL) 218 assert.Equal(t, tc.repoPathExpected, optsConverted.Coreboot["coreboot-A"].RepoPath) 219 }) 220 } 221 } 222 223 func TestOffsetToLineNumber(t *testing.T) { 224 testCases := []struct { 225 name string 226 input string 227 offset int 228 line int 229 character int 230 wantErr error 231 }{ 232 { 233 name: "empty string", 234 input: "", 235 offset: 1, 236 wantErr: ErrVerboseJSON, 237 }, 238 { 239 name: "1 line, offset 0", 240 input: "dummy line", 241 offset: 0, 242 line: 1, 243 character: 1, 244 wantErr: nil, 245 }, 246 { 247 name: "1 line, offset 1", 248 input: "dummy line", 249 offset: 1, 250 line: 1, 251 character: 2, 252 wantErr: nil, 253 }, 254 { 255 name: "2 lines, offset in 1st line", 256 // offset: 012345 6789 257 input: "dummy\nline", 258 offset: 1, 259 line: 1, 260 character: 2, 261 wantErr: nil, 262 }, 263 { 264 name: "2 lines, offset end of 1st line", 265 // offset: 012345 6789 266 input: "dummy\nline", 267 offset: 4, 268 line: 1, 269 character: 5, 270 wantErr: nil, 271 }, 272 { 273 name: "2 lines, offset in 2nd line", 274 input: "dummy\nline", 275 offset: 7, 276 line: 2, 277 character: 2, 278 wantErr: nil, 279 }, 280 { 281 name: "2 lines, offset in 2nd line", 282 // offset: 0 1 2 3 4567 283 input: "\n\n\n\nline", 284 offset: 7, 285 line: 5, 286 character: 4, 287 wantErr: nil, 288 }, 289 } 290 for _, tc := range testCases { 291 t.Run(tc.name, func(t *testing.T) { 292 line, character, err := offsetToLineNumber(tc.input, tc.offset) 293 assert.ErrorIs(t, err, tc.wantErr) 294 if err != nil { 295 // no need to continue on error 296 return 297 } 298 assert.Equal(t, tc.line, line, "line is wrong") 299 assert.Equal(t, tc.character, character, "character is wrong") 300 }) 301 } 302 }