blob: e8a5d5af67ed9926c51e77fed74c34ba6e370a17 [file] [log] [blame]
package dockerimg
import (
"bytes"
"context"
"crypto/sha256"
"encoding/hex"
"os"
"os/exec"
"path/filepath"
"testing"
)
// TestDockerHashIsPushed tests that the published image hash is available
func TestDockerHashIsPushed(t *testing.T) {
// Skip this test if we can't reach the internet
if os.Getenv("CI") == "" {
t.Skip("Skipping test that requires internet access")
}
if err := checkTagExists(dockerfileBaseHash()); err != nil {
t.Errorf("Docker image tag %s not found: %v", dockerfileBaseHash(), err)
}
// Test that the default image components are reasonable
name, dockerfile, tag := DefaultImage()
if name == "" {
t.Error("DefaultImage name is empty")
}
if dockerfile == "" {
t.Error("DefaultImage dockerfile is empty")
}
if tag == "" {
t.Error("DefaultImage tag is empty")
}
if len(tag) < 10 {
t.Errorf("DefaultImage tag suspiciously short: %s", tag)
}
}
// TestCreateCacheKey tests the cache key generation
func TestCreateCacheKey(t *testing.T) {
key1 := createCacheKey("image1", "/path1")
key2 := createCacheKey("image2", "/path1")
key3 := createCacheKey("image1", "/path2")
key4 := createCacheKey("image1", "/path1")
// Different inputs should produce different keys
if key1 == key2 {
t.Error("Different base images should produce different cache keys")
}
if key1 == key3 {
t.Error("Different paths should produce different cache keys")
}
// Same inputs should produce same key
if key1 != key4 {
t.Error("Same inputs should produce same cache key")
}
// Keys should be reasonably short
if len(key1) != 12 {
t.Errorf("Cache key length should be 12, got %d", len(key1))
}
}
// TestEnsureBaseImageExists tests the base image existence check and pull logic
func TestEnsureBaseImageExists(t *testing.T) {
// This test would require Docker to be running and would make network calls
// So we'll skip it unless we're in an integration test environment
if testing.Short() {
t.Skip("Skipping integration test that requires Docker")
}
ctx := context.Background()
// Test with a non-existent image (should fail gracefully)
err := ensureBaseImageExists(ctx, "nonexistent/image:tag")
if err == nil {
t.Error("Expected error for nonexistent image, got nil")
}
}
// TestBinaryCaching tests the content-addressable binary caching functionality
func TestBinaryCaching(t *testing.T) {
// Mock the embedded binary
testBinary := []byte("fake binary content for testing")
// Calculate expected hash
hash := sha256.Sum256(testBinary)
hashHex := hex.EncodeToString(hash[:])
// Create a temporary directory for this test
tempDir := t.TempDir()
cacheDir := filepath.Join(tempDir, "sketch-binary-cache")
binaryPath := filepath.Join(cacheDir, hashHex)
// First, create the cache directory
err := os.MkdirAll(cacheDir, 0o755)
if err != nil {
t.Fatalf("Failed to create cache directory: %v", err)
}
// Verify the binary doesn't exist initially
if _, err := os.Stat(binaryPath); !os.IsNotExist(err) {
t.Fatalf("Binary should not exist initially, but stat returned: %v", err)
}
// Write the binary (simulating first time)
err = os.WriteFile(binaryPath, testBinary, 0o700)
if err != nil {
t.Fatalf("Failed to write binary: %v", err)
}
// Verify the binary now exists and has correct permissions
info, err := os.Stat(binaryPath)
if err != nil {
t.Fatalf("Failed to stat cached binary: %v", err)
}
if info.Mode().Perm() != 0o700 {
t.Errorf("Expected permissions 0700, got %o", info.Mode().Perm())
}
// Verify content matches
cachedContent, err := os.ReadFile(binaryPath)
if err != nil {
t.Fatalf("Failed to read cached binary: %v", err)
}
if !bytes.Equal(testBinary, cachedContent) {
t.Error("Cached binary content doesn't match original")
}
// Test that the same hash produces the same path
hash2 := sha256.Sum256(testBinary)
hashHex2 := hex.EncodeToString(hash2[:])
if hashHex != hashHex2 {
t.Error("Same content should produce same hash")
}
// Test that different content produces different hash
differentBinary := []byte("different fake binary content")
differentHash := sha256.Sum256(differentBinary)
differentHashHex := hex.EncodeToString(differentHash[:])
if hashHex == differentHashHex {
t.Error("Different content should produce different hash")
}
}
func TestCollectGoModules(t *testing.T) {
// Create a temporary directory with test files
tempDir := t.TempDir()
// Initialize a git repository
cmd := exec.Command("git", "init", ".")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to init git repo: %v", err)
}
// Create test go.mod files
modContent := "module test\n\ngo 1.19\n"
sumContent := "example.com/test v1.0.0 h1:abc\n"
// Root go.mod
if err := os.WriteFile(filepath.Join(tempDir, "go.mod"), []byte(modContent), 0o644); err != nil {
t.Fatalf("Failed to create go.mod: %v", err)
}
if err := os.WriteFile(filepath.Join(tempDir, "go.sum"), []byte(sumContent), 0o644); err != nil {
t.Fatalf("Failed to create go.sum: %v", err)
}
// Subdirectory go.mod
subDir := filepath.Join(tempDir, "subdir")
if err := os.MkdirAll(subDir, 0o755); err != nil {
t.Fatalf("Failed to create subdir: %v", err)
}
if err := os.WriteFile(filepath.Join(subDir, "go.mod"), []byte(modContent), 0o644); err != nil {
t.Fatalf("Failed to create subdir/go.mod: %v", err)
}
// No go.sum for subdir to test the case where go.sum is missing
// Add files to git
cmd = exec.Command("git", "add", ".")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to add files to git: %v", err)
}
// Configure git user for the test repo
cmd = exec.Command("git", "config", "user.email", "test@example.com")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to set git user email: %v", err)
}
cmd = exec.Command("git", "config", "user.name", "Test User")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to set git user name: %v", err)
}
// Commit the files
cmd = exec.Command("git", "commit", "-m", "test commit")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to commit files: %v", err)
}
// Collect go modules
ctx := context.Background()
modules, err := collectGoModules(ctx, tempDir)
if err != nil {
t.Fatalf("collectGoModules failed: %v", err)
}
// Verify results
if len(modules) != 2 {
t.Fatalf("Expected 2 modules, got %d", len(modules))
}
// Check root module
root := modules[0]
if root.modPath != "go.mod" {
t.Errorf("Expected root modPath to be 'go.mod', got %s", root.modPath)
}
if root.modSHA == "" {
t.Errorf("Expected root modSHA to be non-empty")
}
if root.sumSHA == "" {
t.Errorf("Expected root sumSHA to be non-empty")
}
// Check subdir module
sub := modules[1]
if sub.modPath != "subdir/go.mod" {
t.Errorf("Expected subdir modPath to be 'subdir/go.mod', got %s", sub.modPath)
}
if sub.modSHA == "" {
t.Errorf("Expected subdir modSHA to be non-empty")
}
if sub.sumSHA != "" {
t.Errorf("Expected subdir sumSHA to be empty, got %s", sub.sumSHA)
}
}
func TestCollectGoModulesNoModFiles(t *testing.T) {
// Create a temporary directory with no go.mod files
tempDir := t.TempDir()
// Initialize a git repository
cmd := exec.Command("git", "init", ".")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to init git repo: %v", err)
}
// Create a non-go.mod file
if err := os.WriteFile(filepath.Join(tempDir, "README.md"), []byte("# Test"), 0o644); err != nil {
t.Fatalf("Failed to create README.md: %v", err)
}
// Add files to git
cmd = exec.Command("git", "add", ".")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to add files to git: %v", err)
}
// Configure git user for the test repo
cmd = exec.Command("git", "config", "user.email", "test@example.com")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to set git user email: %v", err)
}
cmd = exec.Command("git", "config", "user.name", "Test User")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to set git user name: %v", err)
}
// Commit the files
cmd = exec.Command("git", "commit", "-m", "test commit")
cmd.Dir = tempDir
if err := cmd.Run(); err != nil {
t.Fatalf("Failed to commit files: %v", err)
}
// Collect go modules
ctx := context.Background()
modules, err := collectGoModules(ctx, tempDir)
if err != nil {
t.Fatalf("collectGoModules failed: %v", err)
}
// Verify no modules found
if len(modules) != 0 {
t.Fatalf("Expected 0 modules, got %d", len(modules))
}
}