cache-apt-pkgs-action/internal/cache/key_test.go
2025-10-04 22:17:11 -07:00

324 lines
7.8 KiB
Go

package cache
import (
"bytes"
"fmt"
"os"
"path/filepath"
"testing"
"awalsh128.com/cache-apt-pkgs-action/internal/pkgs"
)
const (
package1 = "xdot=1.3-1"
package2 = "rolldice=1.16-1build3"
version1 = "test1"
version2 = "test2"
globalVersion1 = "v1"
globalVersion2 = "v2"
archAmd64 = "amd64"
archX86 = "x86"
)
//==============================================================================
// Helper Functions
//==============================================================================
func createKey(t *testing.T, packages []string, version, globalVersion, osArch string) Key {
t.Helper()
key, err := NewKey(
pkgs.NewPackagesFromStrings(packages...),
version,
globalVersion,
osArch,
)
if err != nil {
t.Fatalf("Failed to create key: %v", err)
}
return key
}
func assertStringEquals(t *testing.T, key Key, expected string) {
t.Helper()
actual := key.String()
if actual != expected {
t.Errorf("String() = %q, expected %q", actual, expected)
}
}
func assertHashesEqual(t *testing.T, key1, key2 Key) {
t.Helper()
hash1 := key1.Hash()
hash2 := key2.Hash()
if !bytes.Equal(hash1, hash2) {
t.Errorf("Hashes should be equal: key1=%x, key2=%x", hash1, hash2)
}
}
func assertHashesDifferent(t *testing.T, key1, key2 Key) {
t.Helper()
hash1 := key1.Hash()
hash2 := key2.Hash()
if bytes.Equal(hash1, hash2) {
t.Errorf("Hashes should be different but were equal: %x", hash1)
}
}
func assertFileContentEquals(t *testing.T, filePath string, expected []byte) {
t.Helper()
actual, err := os.ReadFile(filePath)
if err != nil {
t.Fatalf("Failed to read file %s: %v", filePath, err)
}
if !bytes.Equal(actual, expected) {
t.Errorf("File content mismatch in %s: actual %q, expected %q", filePath, actual, expected)
}
}
//==============================================================================
// String Tests
//==============================================================================
func TestKeyString_WithEmptyKey_ReturnsError(t *testing.T) {
// Arrange & Act
_, err := NewKey(
pkgs.NewPackagesFromStrings(),
"",
"",
"",
)
// Assert
if err == nil {
t.Error("Expected error but got nil")
}
}
func TestKeyString_WithSinglePackage_ReturnsFormattedString(t *testing.T) {
// Arrange
key := createKey(t, []string{package1}, version1, globalVersion2, archAmd64)
expected := fmt.Sprintf(
"Packages: '%s', Version: '%s', GlobalVersion: '%s', OsArch: '%s'",
package1,
version1,
globalVersion2,
archAmd64,
)
// Act & Assert
assertStringEquals(t, key, expected)
}
func TestKeyString_WithMultiplePackages_ReturnsCommaSeparatedString(t *testing.T) {
// Arrange
key := createKey(
t,
[]string{package1, package2}, // xdot=1.3-1, rolldice=1.16-1build3
version1,
globalVersion2,
archAmd64,
)
// Packages are sorted, so "rolldice" comes before "xdot"
expected := fmt.Sprintf(
"Packages: '%s %s', Version: '%s', GlobalVersion: '%s', OsArch: '%s'",
package2,
package1,
version1,
globalVersion2,
archAmd64,
)
// Act & Assert
assertStringEquals(t, key, expected)
}
//==============================================================================
// Hash Tests
//==============================================================================
func TestKeyHash_WithIdenticalKeys_ReturnsSameHash(t *testing.T) {
// Arrange
key1 := createKey(t, []string{package1}, version1, globalVersion2, archAmd64)
key2 := createKey(t, []string{package1}, version1, globalVersion2, archAmd64)
// Act & Assert
assertHashesEqual(t, key1, key2)
}
func TestKeyHash_WithDifferences_ReturnsDifferentHash(t *testing.T) {
tests := []struct {
name string
key1 Key
key2 Key
}{
{
name: "Different packages",
key1: createKey(t, []string{package1}, version1, globalVersion1, archAmd64),
key2: createKey(t, []string{package2}, version1, globalVersion1, archAmd64),
},
{
name: "Different versions",
key1: createKey(t, []string{package1}, version1, globalVersion1, archAmd64),
key2: createKey(t, []string{package2}, version2, globalVersion1, archAmd64),
},
{
name: "Different global versions",
key1: createKey(t, []string{package1}, version1, globalVersion1, archAmd64),
key2: createKey(t, []string{package2}, version1, globalVersion2, archAmd64),
},
{
name: "Different architectures",
key1: createKey(t, []string{package1}, version1, globalVersion1, archAmd64),
key2: createKey(t, []string{package1}, version1, globalVersion2, archX86),
},
}
for _, tt := range tests {
t.Run(tt.name, func(t *testing.T) {
assertHashesDifferent(t, tt.key1, tt.key2)
})
}
}
//==============================================================================
// Write Tests
//==============================================================================
func TestKeyWrite_WithValidPaths_WritesPlaintextAndHash(t *testing.T) {
// Arrange
key := createKey(
t,
[]string{package1, package2},
version1,
globalVersion2,
archAmd64,
)
plaintextPath := filepath.Join(t.TempDir(), "key.txt")
ciphertextPath := filepath.Join(t.TempDir(), "key.md5")
// Act
err := key.Write(plaintextPath, ciphertextPath)
// Assert
if err != nil {
t.Fatalf("Write() failed: %v", err)
}
// Verify plaintext file
expectedPlaintext := []byte(key.String())
assertFileContentEquals(t, plaintextPath, expectedPlaintext)
// Verify hash file
expectedHash := key.Hash()
assertFileContentEquals(t, ciphertextPath, expectedHash)
}
func TestKeyWrite_WithInvalidPlaintextPath_ReturnsError(t *testing.T) {
// Arrange
key := createKey(t, []string{package1}, version1, globalVersion2, archAmd64)
invalidPath := "/invalid/path/key.txt"
validPath := filepath.Join(t.TempDir(), "key.md5")
// Act
err := key.Write(invalidPath, validPath)
// Assert
if err == nil {
t.Error("Write() should have failed with invalid plaintext path")
}
}
func TestKeyWrite_WithInvalidCiphertextPath_ReturnsError(t *testing.T) {
// Arrange
key := createKey(t, []string{package1}, version1, globalVersion2, archAmd64)
validPath := filepath.Join(t.TempDir(), "key.txt")
invalidPath := "/invalid/path/key.md5"
// Act
err := key.Write(validPath, invalidPath)
// Assert
if err == nil {
t.Error("Write() should have failed with invalid ciphertext path")
}
}
//==============================================================================
// Integration Tests
//==============================================================================
func TestKeyWriteAndRead_PlaintextRoundTrip_PreservesContent(t *testing.T) {
// Arrange
key := createKey(
t,
[]string{package1, package2},
version1,
globalVersion2,
archAmd64,
)
tempDir := t.TempDir()
plaintextPath := filepath.Join(tempDir, "key.txt")
ciphertextPath := filepath.Join(tempDir, "key.md5")
// Act
err := key.Write(plaintextPath, ciphertextPath)
if err != nil {
t.Fatalf("Write() failed: %v", err)
}
plaintextBytes, err := os.ReadFile(plaintextPath)
if err != nil {
t.Fatalf("ReadFile() failed: %v", err)
}
// Assert
actualPlaintext := string(plaintextBytes)
expectedPlaintext := key.String()
if actualPlaintext != expectedPlaintext {
t.Errorf(
"Plaintext round trip failed: actual %q, expected %q",
actualPlaintext,
expectedPlaintext,
)
}
}
func TestKeyWriteAndRead_CiphertextRoundTrip_PreservesHash(t *testing.T) {
// Arrange
key := createKey(
t,
[]string{package1, package2},
version1,
globalVersion2,
archAmd64,
)
tempDir := t.TempDir()
plaintextPath := filepath.Join(tempDir, "key.txt")
ciphertextPath := filepath.Join(tempDir, "key.md5")
// Act
err := key.Write(plaintextPath, ciphertextPath)
if err != nil {
t.Fatalf("Write() failed: %v", err)
}
ciphertextBytes, err := os.ReadFile(ciphertextPath)
if err != nil {
t.Fatalf("ReadFile() failed: %v", err)
}
// Assert
expectedHash := key.Hash()
if !bytes.Equal(ciphertextBytes, expectedHash) {
t.Errorf(
"Ciphertext round trip failed: actual %x, expected %x",
ciphertextBytes,
expectedHash,
)
}
}