blob: 2b98c255fce467b2746b554bbb07adbb9749a41c [file] [log] [blame]
Earl Lee2e463fb2025-04-17 11:22:22 -07001package dockerimg
2
3import (
Josh Bleecher Snyder1c18ec92025-07-08 10:55:54 -07004 "bytes"
Earl Lee2e463fb2025-04-17 11:22:22 -07005 "context"
Josh Bleecher Snyder1c18ec92025-07-08 10:55:54 -07006 "crypto/sha256"
7 "encoding/hex"
Earl Lee2e463fb2025-04-17 11:22:22 -07008 "os"
Josh Bleecher Snyder1c18ec92025-07-08 10:55:54 -07009 "path/filepath"
Earl Lee2e463fb2025-04-17 11:22:22 -070010 "testing"
Earl Lee2e463fb2025-04-17 11:22:22 -070011)
12
Philip Zeyliger983b58a2025-07-02 19:42:08 -070013// TestDockerHashIsPushed tests that the published image hash is available
David Crawshaw11129492025-04-25 20:41:53 -070014func TestDockerHashIsPushed(t *testing.T) {
Philip Zeyliger983b58a2025-07-02 19:42:08 -070015 // Skip this test if we can't reach the internet
16 if os.Getenv("CI") == "" {
17 t.Skip("Skipping test that requires internet access")
18 }
David Crawshaw11129492025-04-25 20:41:53 -070019
Philip Zeyliger983b58a2025-07-02 19:42:08 -070020 if err := checkTagExists(dockerfileBaseHash()); err != nil {
21 t.Errorf("Docker image tag %s not found: %v", dockerfileBaseHash(), err)
22 }
David Crawshaw11129492025-04-25 20:41:53 -070023
Philip Zeyliger983b58a2025-07-02 19:42:08 -070024 // Test that the default image components are reasonable
25 name, dockerfile, tag := DefaultImage()
26 if name == "" {
27 t.Error("DefaultImage name is empty")
28 }
29 if dockerfile == "" {
30 t.Error("DefaultImage dockerfile is empty")
31 }
32 if tag == "" {
33 t.Error("DefaultImage tag is empty")
34 }
35 if len(tag) < 10 {
36 t.Errorf("DefaultImage tag suspiciously short: %s", tag)
David Crawshaw11129492025-04-25 20:41:53 -070037 }
38}
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000039
Philip Zeyliger983b58a2025-07-02 19:42:08 -070040// TestCreateCacheKey tests the cache key generation
41func TestCreateCacheKey(t *testing.T) {
42 key1 := createCacheKey("image1", "/path1")
43 key2 := createCacheKey("image2", "/path1")
44 key3 := createCacheKey("image1", "/path2")
45 key4 := createCacheKey("image1", "/path1")
46
47 // Different inputs should produce different keys
48 if key1 == key2 {
49 t.Error("Different base images should produce different cache keys")
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000050 }
Philip Zeyliger983b58a2025-07-02 19:42:08 -070051 if key1 == key3 {
52 t.Error("Different paths should produce different cache keys")
53 }
54
55 // Same inputs should produce same key
56 if key1 != key4 {
57 t.Error("Same inputs should produce same cache key")
58 }
59
60 // Keys should be reasonably short
61 if len(key1) != 12 {
62 t.Errorf("Cache key length should be 12, got %d", len(key1))
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000063 }
64}
Jon Friesend27921f2025-06-05 13:15:56 +000065
Philip Zeyliger983b58a2025-07-02 19:42:08 -070066// TestEnsureBaseImageExists tests the base image existence check and pull logic
67func TestEnsureBaseImageExists(t *testing.T) {
68 // This test would require Docker to be running and would make network calls
69 // So we'll skip it unless we're in an integration test environment
70 if testing.Short() {
71 t.Skip("Skipping integration test that requires Docker")
Jon Friesend27921f2025-06-05 13:15:56 +000072 }
73
Philip Zeyliger983b58a2025-07-02 19:42:08 -070074 ctx := context.Background()
Jon Friesend27921f2025-06-05 13:15:56 +000075
Philip Zeyliger983b58a2025-07-02 19:42:08 -070076 // Test with a non-existent image (should fail gracefully)
77 err := ensureBaseImageExists(ctx, "nonexistent/image:tag")
78 if err == nil {
79 t.Error("Expected error for nonexistent image, got nil")
Philip Zeyliger2343f8a2025-06-17 06:16:19 -070080 }
81}
Josh Bleecher Snyder1c18ec92025-07-08 10:55:54 -070082
83// TestBinaryCaching tests the content-addressable binary caching functionality
84func TestBinaryCaching(t *testing.T) {
85 // Mock the embedded binary
86 testBinary := []byte("fake binary content for testing")
87
88 // Calculate expected hash
89 hash := sha256.Sum256(testBinary)
90 hashHex := hex.EncodeToString(hash[:])
91
92 // Create a temporary directory for this test
93 tempDir := t.TempDir()
94 cacheDir := filepath.Join(tempDir, "sketch-binary-cache")
95 binaryPath := filepath.Join(cacheDir, hashHex)
96
97 // First, create the cache directory
98 err := os.MkdirAll(cacheDir, 0o755)
99 if err != nil {
100 t.Fatalf("Failed to create cache directory: %v", err)
101 }
102
103 // Verify the binary doesn't exist initially
104 if _, err := os.Stat(binaryPath); !os.IsNotExist(err) {
105 t.Fatalf("Binary should not exist initially, but stat returned: %v", err)
106 }
107
108 // Write the binary (simulating first time)
109 err = os.WriteFile(binaryPath, testBinary, 0o700)
110 if err != nil {
111 t.Fatalf("Failed to write binary: %v", err)
112 }
113
114 // Verify the binary now exists and has correct permissions
115 info, err := os.Stat(binaryPath)
116 if err != nil {
117 t.Fatalf("Failed to stat cached binary: %v", err)
118 }
119
120 if info.Mode().Perm() != 0o700 {
121 t.Errorf("Expected permissions 0700, got %o", info.Mode().Perm())
122 }
123
124 // Verify content matches
125 cachedContent, err := os.ReadFile(binaryPath)
126 if err != nil {
127 t.Fatalf("Failed to read cached binary: %v", err)
128 }
129
130 if !bytes.Equal(testBinary, cachedContent) {
131 t.Error("Cached binary content doesn't match original")
132 }
133
134 // Test that the same hash produces the same path
135 hash2 := sha256.Sum256(testBinary)
136 hashHex2 := hex.EncodeToString(hash2[:])
137
138 if hashHex != hashHex2 {
139 t.Error("Same content should produce same hash")
140 }
141
142 // Test that different content produces different hash
143 differentBinary := []byte("different fake binary content")
144 differentHash := sha256.Sum256(differentBinary)
145 differentHashHex := hex.EncodeToString(differentHash[:])
146
147 if hashHex == differentHashHex {
148 t.Error("Different content should produce different hash")
149 }
150}