diff --git a/cmd/firmware-action/recipes/coreboot_test.go b/cmd/firmware-action/recipes/coreboot_test.go index d028c249..238e501e 100644 --- a/cmd/firmware-action/recipes/coreboot_test.go +++ b/cmd/firmware-action/recipes/coreboot_test.go @@ -9,6 +9,7 @@ import ( "os" "os/exec" "path/filepath" + "regexp" "testing" "dagger.io/dagger" @@ -70,13 +71,32 @@ func TestCoreboot(t *testing.T) { "defconfig", }, } + // The universal module is used in this test to check version of compiled coreboot binary + optionsUniversal := UniversalOpts{ + CommonOpts: CommonOpts{ + OutputDir: "output-universal", + ContainerOutputFiles: []string{ + "build_info.txt", + }, + ContainerInputDir: "input", + }, + UniversalSpecific: UniversalSpecific{ + BuildCommands: []string{ + "cbfstool coreboot.rom extract -n build_info -f build_info.txt", + }, + }, + } testCases := []struct { - name string - corebootVersion string - corebootOptions CorebootOpts - cmds [][]string - wantErr error + name string + corebootVersion string + corebootOptions CorebootOpts + universalOptions UniversalOpts + cmds [][]string + envVars map[string]string + versionRegex string + wantErr error + skip bool }{ { name: "normal build for QEMU", @@ -86,6 +106,8 @@ func TestCoreboot(t *testing.T) { DefconfigPath: "seabios_defconfig", }, wantErr: nil, + // skip: false, + skip: true, }, { name: "binary payload - file does not exists", @@ -98,6 +120,7 @@ func TestCoreboot(t *testing.T) { }, }, wantErr: os.ErrNotExist, + skip: true, }, { name: "binary payload - file exists but empty", @@ -113,19 +136,96 @@ func TestCoreboot(t *testing.T) { {"touch", "intel_me.bin"}, }, wantErr: nil, + skip: true, + }, + // Test COREBOOT_VERSION: user-defined KERNELVERSION + { + name: "normal build for QEMU with user-defined KERNELVERSION", + corebootVersion: "4.19", + corebootOptions: CorebootOpts{ + CommonOpts: common, + DefconfigPath: "seabios_defconfig", + }, + universalOptions: optionsUniversal, + envVars: map[string]string{ + "KERNELVERSION": "v0.1.2", + }, + versionRegex: `v0\.1\.2`, + wantErr: nil, + // skip: false, + skip: true, + }, + // Test COREBOOT_VERSION: user-created .coreboot-version + { + name: "normal build for QEMU with user-created .coreboot-version", + corebootVersion: "4.19", + corebootOptions: CorebootOpts{ + CommonOpts: common, + DefconfigPath: "seabios_defconfig", + }, + cmds: [][]string{ + {"echo", "v0.1.2-file", ">>", "./coreboot/.coreboot-version"}, + {"ls", "-a1lh", "./"}, + {"ls", "-a1lh", "./coreboot"}, + {"cat", "./coreboot/.coreboot-version"}, + }, + universalOptions: optionsUniversal, + versionRegex: `v0\.1\.2\-file`, + wantErr: nil, + skip: false, + // skip: true, + }, + // Test COREBOOT_VERSION: auto-generated KERNELVERSION + { + name: "normal build for QEMU with auto-generated KERNELVERSION", + corebootVersion: "4.19", + corebootOptions: CorebootOpts{ + CommonOpts: common, + DefconfigPath: "seabios_defconfig", + }, + universalOptions: optionsUniversal, + versionRegex: `4\.19`, + wantErr: nil, + // skip: false, + skip: true, + }, + // Test COREBOOT_VERSION: auto-generated KERNELVERSION (dirty) + { + name: "normal build for QEMU with auto-generated dirty KERNELVERSION", + corebootVersion: "4.19", + corebootOptions: CorebootOpts{ + CommonOpts: common, + DefconfigPath: "seabios_defconfig", + }, + cmds: [][]string{ + {"echo", "hello world!", ">>", "./coreboot/README.md"}, + }, + universalOptions: optionsUniversal, + versionRegex: `4\.19\-dirty`, + wantErr: nil, + // skip: false, + skip: true, }, } for _, tc := range testCases { t.Run(tc.name, func(t *testing.T) { + if tc.skip { + // TODO: remove this + return + } ctx := context.Background() client, err := dagger.Connect(ctx, dagger.WithLogOutput(os.Stdout)) assert.NoError(t, err) defer client.Close() - // Prepare options + // Prepare options - coreboot tmpDir := t.TempDir() tc.corebootOptions.SdkURL = fmt.Sprintf("ghcr.io/9elements/firmware-action/coreboot_%s:main", tc.corebootVersion) tc.corebootOptions.RepoPath = filepath.Join(tmpDir, "coreboot") + // Prepare options - universal module + outputPath := filepath.Join(tmpDir, tc.corebootOptions.OutputDir) + tc.universalOptions.SdkURL = fmt.Sprintf("ghcr.io/9elements/firmware-action/coreboot_%s:main", tc.corebootVersion) + tc.universalOptions.RepoPath = outputPath // Change current working directory pwd, err := os.Getwd() @@ -151,16 +251,29 @@ func TestCoreboot(t *testing.T) { assert.NoError(t, err) // Artifacts - outputPath := filepath.Join(tmpDir, tc.corebootOptions.OutputDir) err = os.MkdirAll(outputPath, os.ModePerm) assert.NoError(t, err) tc.corebootOptions.OutputDir = outputPath + outputPathUniversal := filepath.Join(tmpDir, tc.universalOptions.OutputDir) + tc.universalOptions.OutputDir = outputPathUniversal - // Prep + // Prep - environment variables + for key, value := range tc.envVars { + os.Setenv(key, value) + defer os.Unsetenv(key) + fmt.Printf("Setting %s = %s\n", key, value) + } + + // Prep - commands for cmd := range tc.cmds { - err = exec.Command(tc.cmds[cmd][0], tc.cmds[cmd][1:]...).Run() - assert.NoError(t, err) + // err = exec.Command(tc.cmds[cmd][0], tc.cmds[cmd][1:]...).Run() + // assert.NoError(t, err) + cmd := exec.Command(tc.cmds[cmd][0], tc.cmds[cmd][1:]...) + stdout, err := cmd.CombinedOutput() + assert.Equal(t, string(stdout), "") + assert.NoError(t, err, string(stdout)) } + // Try to build coreboot _, err = tc.corebootOptions.buildFirmware(ctx, client, "") assert.ErrorIs(t, err, tc.wantErr) @@ -170,6 +283,25 @@ func TestCoreboot(t *testing.T) { assert.ErrorIs(t, filesystem.CheckFileExists(filepath.Join(outputPath, "coreboot.rom")), os.ErrExist) assert.ErrorIs(t, filesystem.CheckFileExists(filepath.Join(outputPath, "defconfig")), os.ErrExist) } + + // Check corebot version + if tc.wantErr == nil && len(tc.universalOptions.UniversalSpecific.BuildCommands) > 0 { + _, err = tc.universalOptions.buildFirmware(ctx, client, "") + assert.ErrorIs(t, err, tc.wantErr) + + // Check file with coreboot version exists + corebootVersionFile := filepath.Join(outputPathUniversal, "build_info.txt") + assert.ErrorIs(t, filesystem.CheckFileExists(corebootVersionFile), os.ErrExist) + + // Find the coreboot version + corebootVersionFileContent, err := os.ReadFile(corebootVersionFile) + assert.NoError(t, err) + versionEntryPatter := regexp.MustCompile(`COREBOOT_VERSION: (.*)`) + version := string(versionEntryPatter.FindSubmatch(corebootVersionFileContent)[1]) + + versionPattern := regexp.MustCompile(tc.versionRegex) + assert.True(t, versionPattern.MatchString(version), fmt.Sprintf("found version '%s' does not match expected regex '%s'", version, tc.versionRegex)) + } }) } } diff --git a/cmd/firmware-action/recipes/output-universal b/cmd/firmware-action/recipes/output-universal new file mode 100644 index 00000000..e91c9fd5 Binary files /dev/null and b/cmd/firmware-action/recipes/output-universal differ