blob: e15a81fe9ca4b89d772f555d37d129b4c22cb8e1 [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// TestGetHostGoCacheDirs tests that we can get the host Go cache directories
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000041func TestGetHostGoCacheDirs(t *testing.T) {
Philip Zeyliger983b58a2025-07-02 19:42:08 -070042 if !RaceEnabled() {
43 t.Skip("Race detector not enabled, skipping test")
44 }
45
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000046 ctx := context.Background()
47
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000048 goCacheDir, err := getHostGoCacheDir(ctx)
49 if err != nil {
50 t.Fatalf("getHostGoCacheDir failed: %v", err)
51 }
52 if goCacheDir == "" {
Philip Zeyliger983b58a2025-07-02 19:42:08 -070053 t.Error("GOCACHE is empty")
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000054 }
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000055
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000056 goModCacheDir, err := getHostGoModCacheDir(ctx)
57 if err != nil {
58 t.Fatalf("getHostGoModCacheDir failed: %v", err)
59 }
60 if goModCacheDir == "" {
Philip Zeyliger983b58a2025-07-02 19:42:08 -070061 t.Error("GOMODCACHE is empty")
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000062 }
Philip Zeyliger983b58a2025-07-02 19:42:08 -070063
64 t.Logf("GOCACHE: %s", goCacheDir)
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000065 t.Logf("GOMODCACHE: %s", goModCacheDir)
Philip Zeyliger983b58a2025-07-02 19:42:08 -070066}
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000067
Philip Zeyliger983b58a2025-07-02 19:42:08 -070068// TestCreateCacheKey tests the cache key generation
69func TestCreateCacheKey(t *testing.T) {
70 key1 := createCacheKey("image1", "/path1")
71 key2 := createCacheKey("image2", "/path1")
72 key3 := createCacheKey("image1", "/path2")
73 key4 := createCacheKey("image1", "/path1")
74
75 // Different inputs should produce different keys
76 if key1 == key2 {
77 t.Error("Different base images should produce different cache keys")
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000078 }
Philip Zeyliger983b58a2025-07-02 19:42:08 -070079 if key1 == key3 {
80 t.Error("Different paths should produce different cache keys")
81 }
82
83 // Same inputs should produce same key
84 if key1 != key4 {
85 t.Error("Same inputs should produce same cache key")
86 }
87
88 // Keys should be reasonably short
89 if len(key1) != 12 {
90 t.Errorf("Cache key length should be 12, got %d", len(key1))
Josh Bleecher Snyder3e6a4c42025-05-23 17:29:57 +000091 }
92}
Jon Friesend27921f2025-06-05 13:15:56 +000093
Philip Zeyliger983b58a2025-07-02 19:42:08 -070094// TestEnsureBaseImageExists tests the base image existence check and pull logic
95func TestEnsureBaseImageExists(t *testing.T) {
96 // This test would require Docker to be running and would make network calls
97 // So we'll skip it unless we're in an integration test environment
98 if testing.Short() {
99 t.Skip("Skipping integration test that requires Docker")
Jon Friesend27921f2025-06-05 13:15:56 +0000100 }
101
Philip Zeyliger983b58a2025-07-02 19:42:08 -0700102 ctx := context.Background()
Jon Friesend27921f2025-06-05 13:15:56 +0000103
Philip Zeyliger983b58a2025-07-02 19:42:08 -0700104 // Test with a non-existent image (should fail gracefully)
105 err := ensureBaseImageExists(ctx, "nonexistent/image:tag")
106 if err == nil {
107 t.Error("Expected error for nonexistent image, got nil")
Philip Zeyliger2343f8a2025-06-17 06:16:19 -0700108 }
109}
Josh Bleecher Snyder1c18ec92025-07-08 10:55:54 -0700110
111// TestBinaryCaching tests the content-addressable binary caching functionality
112func TestBinaryCaching(t *testing.T) {
113 // Mock the embedded binary
114 testBinary := []byte("fake binary content for testing")
115
116 // Calculate expected hash
117 hash := sha256.Sum256(testBinary)
118 hashHex := hex.EncodeToString(hash[:])
119
120 // Create a temporary directory for this test
121 tempDir := t.TempDir()
122 cacheDir := filepath.Join(tempDir, "sketch-binary-cache")
123 binaryPath := filepath.Join(cacheDir, hashHex)
124
125 // First, create the cache directory
126 err := os.MkdirAll(cacheDir, 0o755)
127 if err != nil {
128 t.Fatalf("Failed to create cache directory: %v", err)
129 }
130
131 // Verify the binary doesn't exist initially
132 if _, err := os.Stat(binaryPath); !os.IsNotExist(err) {
133 t.Fatalf("Binary should not exist initially, but stat returned: %v", err)
134 }
135
136 // Write the binary (simulating first time)
137 err = os.WriteFile(binaryPath, testBinary, 0o700)
138 if err != nil {
139 t.Fatalf("Failed to write binary: %v", err)
140 }
141
142 // Verify the binary now exists and has correct permissions
143 info, err := os.Stat(binaryPath)
144 if err != nil {
145 t.Fatalf("Failed to stat cached binary: %v", err)
146 }
147
148 if info.Mode().Perm() != 0o700 {
149 t.Errorf("Expected permissions 0700, got %o", info.Mode().Perm())
150 }
151
152 // Verify content matches
153 cachedContent, err := os.ReadFile(binaryPath)
154 if err != nil {
155 t.Fatalf("Failed to read cached binary: %v", err)
156 }
157
158 if !bytes.Equal(testBinary, cachedContent) {
159 t.Error("Cached binary content doesn't match original")
160 }
161
162 // Test that the same hash produces the same path
163 hash2 := sha256.Sum256(testBinary)
164 hashHex2 := hex.EncodeToString(hash2[:])
165
166 if hashHex != hashHex2 {
167 t.Error("Same content should produce same hash")
168 }
169
170 // Test that different content produces different hash
171 differentBinary := []byte("different fake binary content")
172 differentHash := sha256.Sum256(differentBinary)
173 differentHashHex := hex.EncodeToString(differentHash[:])
174
175 if hashHex == differentHashHex {
176 t.Error("Different content should produce different hash")
177 }
178}