-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Added tests for image history. Test cases: - Adding an entry to image history - Adding another entry to image history with a different uuid - Deep copying config - Modifying config - Populate / redact functions Moved redactedString to a constant so it can be reused in the tests. Added another file in additional dirs for good measure (I found that it helped while locally testing image history). Added a config for image history that contains several different fields. Possible future tests: Test custom MarshalJSON functions that were added for image history Test omitting JSON fields as selected --- ### **Checklist** - [x] Tests added/updated - [x] Documentation updated (if needed) - [x] Code conforms to style guidelines
- Loading branch information
1 parent
72b6656
commit 7d539f4
Showing
5 changed files
with
267 additions
and
7 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
134 changes: 134 additions & 0 deletions
134
toolkit/tools/pkg/imagecustomizerlib/imagehistory_test.go
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,134 @@ | ||
package imagecustomizerlib | ||
|
||
import ( | ||
"encoding/json" | ||
"os" | ||
"path/filepath" | ||
"testing" | ||
"time" | ||
|
||
"github.com/microsoft/azurelinux/toolkit/tools/imagecustomizerapi" | ||
"github.com/microsoft/azurelinux/toolkit/tools/internal/file" | ||
"github.com/stretchr/testify/assert" | ||
"gopkg.in/yaml.v3" | ||
) | ||
|
||
func createTestConfig(configFilePath string, t *testing.T) imagecustomizerapi.Config { | ||
configFile := filepath.Join(testDir, configFilePath) | ||
|
||
var config imagecustomizerapi.Config | ||
err := imagecustomizerapi.UnmarshalYamlFile(configFile, &config) | ||
assert.NoError(t, err) | ||
return config | ||
} | ||
|
||
func TestAddImageHistory(t *testing.T) { | ||
tempDir := filepath.Join(tmpDir, "TestAddImageHistory") | ||
|
||
historyDir := filepath.Join(tempDir, customizerLoggingDir) | ||
historyFilePath := filepath.Join(historyDir, historyFileName) | ||
config := createTestConfig("imagehistory-config.yaml", t) | ||
// Serialize the config before calling addImageHistory | ||
originalConfigBytes, err := yaml.Marshal(config) | ||
assert.NoError(t, err, "failed to serialize original config") | ||
|
||
expectedVersion := "0.1.0" | ||
expectedDate := time.Now().Format("2006-01-02T15:04:05Z") | ||
_, expectedUuid, err := createUuid() | ||
assert.NoError(t, err) | ||
|
||
// Test adding the first entry | ||
err = addImageHistory(tempDir, expectedUuid, testDir, expectedVersion, expectedDate, &config) | ||
assert.NoError(t, err, "addImageHistory should not return an error") | ||
|
||
verifyHistoryFile(t, 1, expectedUuid, expectedVersion, expectedDate, config, historyFilePath) | ||
|
||
// Verify the config is unchanged | ||
currentConfigBytes, err := yaml.Marshal(config) | ||
assert.NoError(t, err, "failed to serialize current config") | ||
assert.Equal(t, originalConfigBytes, currentConfigBytes, "config should remain unchanged after adding image history") | ||
|
||
// Test adding another entry with a different uuid | ||
_, expectedUuid, err = createUuid() | ||
assert.NoError(t, err) | ||
err = addImageHistory(tempDir, expectedUuid, testDir, expectedVersion, expectedDate, &config) | ||
assert.NoError(t, err, "addImageHistory should not return an error") | ||
|
||
allHistory := verifyHistoryFile(t, 2, expectedUuid, expectedVersion, expectedDate, config, historyFilePath) | ||
|
||
// Verify the imageUuid is unique for each entry | ||
assert.NotEqual(t, allHistory[0].ImageUuid, allHistory[1].ImageUuid, "imageUuid should be different for each entry") | ||
} | ||
|
||
func verifyHistoryFile(t *testing.T, expectedEntries int, expectedUuid string, expectedVersion string, expectedDate string, config imagecustomizerapi.Config, historyFilePath string) (allHistory []ImageHistory) { | ||
exists, err := file.PathExists(historyFilePath) | ||
assert.NoError(t, err, "error checking history file existence") | ||
assert.True(t, exists, "history file should exist") | ||
|
||
historyContent, err := os.ReadFile(historyFilePath) | ||
assert.NoError(t, err, "error reading history file") | ||
|
||
err = json.Unmarshal(historyContent, &allHistory) | ||
assert.NoError(t, err, "error unmarshalling history content") | ||
assert.Len(t, allHistory, expectedEntries, "history file should contain the expected number of entries") | ||
|
||
// Verify the last entry content | ||
entry := allHistory[expectedEntries-1] | ||
assert.Equal(t, expectedUuid, entry.ImageUuid, "imageUuid should match") | ||
assert.Equal(t, expectedVersion, entry.ToolVersion, "toolVersion should match") | ||
assert.Equal(t, expectedDate, entry.BuildTime, "buildTime should match") | ||
// Since the config is modified its entirety won't be an exact match; picking one consistent field to verify | ||
assert.Equal(t, config.OS.BootLoader.ResetType, entry.Config.OS.BootLoader.ResetType, "config bootloader reset type should match") | ||
|
||
verifyAdditionalFilesHashes(t, entry.Config.OS.AdditionalFiles) | ||
verifyAdditionalDirsHashes(t, entry.Config.OS.AdditionalDirs) | ||
verifyScriptsHashes(t, entry.Config.Scripts.PostCustomization) | ||
verifyScriptsHashes(t, entry.Config.Scripts.FinalizeCustomization) | ||
verifySshPublicKeysRedacted(t, entry.Config.OS.Users) | ||
|
||
return | ||
} | ||
|
||
func verifySshPublicKeysRedacted(t *testing.T, users []imagecustomizerapi.User) { | ||
for _, user := range users { | ||
for _, key := range user.SSHPublicKeys { | ||
assert.Equal(t, redactedString, key, "SSH public keys should be redacted") | ||
} | ||
} | ||
} | ||
|
||
func verifyScriptsHashes(t *testing.T, scripts []imagecustomizerapi.Script) { | ||
for _, script := range scripts { | ||
if script.Path != "" { | ||
verifyFileHash(t, script.Path, script.SHA256Hash) | ||
} else { | ||
assert.Empty(t, script.SHA256Hash, "script hash should be empty") | ||
} | ||
} | ||
} | ||
func verifyAdditionalFilesHashes(t *testing.T, files imagecustomizerapi.AdditionalFileList) { | ||
for _, f := range files { | ||
if f.Source != "" { | ||
verifyFileHash(t, f.Source, f.SHA256Hash) | ||
} else { | ||
assert.Empty(t, f.SHA256Hash, "SHA256Hash for additional files should be empty") | ||
} | ||
} | ||
} | ||
|
||
func verifyAdditionalDirsHashes(t *testing.T, dirs imagecustomizerapi.DirConfigList) { | ||
for _, dir := range dirs { | ||
assert.NotEmpty(t, dir.SHA256HashMap, "SHA256HashMap for additional directories should not be empty") | ||
for relPath, hash := range dir.SHA256HashMap { | ||
verifyFileHash(t, filepath.Join(dir.Source, relPath), hash) | ||
} | ||
} | ||
} | ||
|
||
func verifyFileHash(t *testing.T, path string, foundHash string) { | ||
assert.NotEmpty(t, foundHash, "SHA256Hash for file %s should not be empty", path) | ||
fullPath := filepath.Join(testDir, path) | ||
expectedHash, err := file.GenerateSHA256(fullPath) | ||
assert.NoError(t, err, "error generating SHA256 hash for file %s", path) | ||
assert.Equal(t, foundHash, expectedHash, "SHA256 hash for file %s should match", path) | ||
} |
3 changes: 3 additions & 0 deletions
3
toolkit/tools/pkg/imagecustomizerlib/testdata/dirs/a/usr/local/bin/plants.sh
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
#!/usr/bin/env bash | ||
|
||
echo "aloe vera and cactus" |
124 changes: 124 additions & 0 deletions
124
toolkit/tools/pkg/imagecustomizerlib/testdata/imagehistory-config.yaml
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,124 @@ | ||
storage: | ||
disks: | ||
- partitionTableType: gpt | ||
maxSize: 4G | ||
partitions: | ||
- id: esp | ||
type: esp | ||
start: 1M | ||
end: 9M | ||
|
||
- id: boot | ||
start: 9M | ||
end: 108M | ||
|
||
- id: rootfs | ||
label: rootfs | ||
size: 1G | ||
|
||
- id: var | ||
start: 2G | ||
size: grow | ||
|
||
bootType: efi | ||
|
||
filesystems: | ||
- deviceId: esp | ||
type: fat32 | ||
mountPoint: | ||
path: /boot/efi | ||
options: umask=0077 | ||
|
||
- deviceId: boot | ||
type: ext4 | ||
mountPoint: | ||
path: /boot | ||
|
||
- deviceId: rootfs | ||
type: xfs | ||
mountPoint: | ||
path: / | ||
|
||
- deviceId: var | ||
type: xfs | ||
mountPoint: | ||
path: /var | ||
|
||
os: | ||
packages: | ||
remove: | ||
- which | ||
|
||
install: | ||
- jq | ||
|
||
installLists: | ||
- lists/golang.yaml | ||
|
||
update: | ||
- jq | ||
users: | ||
- name: mariner_user | ||
sshPublicKeys: | ||
- ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABgQDQ | ||
- /home/test/.ssh/authorized_keys | ||
- "test" | ||
- ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAnotvalidAAIFyWtgGE06d/uBFQm70fRDoh06bWQQwC6Qkm test@test-machine | ||
secondaryGroups: | ||
- sudo | ||
|
||
- name: test | ||
secondaryGroups: | ||
- sudo | ||
|
||
bootloader: | ||
resetType: hard-reset | ||
|
||
kernelCommandLine: | ||
extraCommandLine: ["console=tty0", "console=ttyS0"] | ||
|
||
additionalDirs: | ||
- source: dirs/a | ||
destination: / | ||
- source: dirs/b | ||
destination: / | ||
|
||
|
||
additionalFiles: | ||
- source: files/a.txt | ||
destination: /a.txt | ||
|
||
- source: files/helloworld.sh | ||
destination: /usr/local/bin/helloworld.sh | ||
permissions: 755 | ||
|
||
- content: | | ||
cat | ||
dog | ||
destination: /animals.txt | ||
- content: |- | ||
abcdefghijklmnopqrstuvwxyz | ||
destination: /alphabet.txt | ||
permissions: 644 | ||
- content: "" | ||
destination: /empty.txt | ||
|
||
scripts: | ||
postCustomization: | ||
- path: scripts/postcustomizationscript.sh | ||
- content: | | ||
echo "This is an postCustomization inline script" | ||
echo "$1 $2" | ||
echo "$fruit and $vegetable" | ||
echo "Working dir: $(pwd)" | ||
arguments: | ||
- hello | ||
- world | ||
environmentVariables: | ||
fruit: bananas | ||
vegetable: carrots | ||
finalizeCustomization: | ||
- path: scripts/finalizecustomizationscript.sh |