core/plan/dockerignore_test.go
core/plan/dockerignore_test.goBrowse 1970 files
2,350 tokens
8,499 bytes
Token encoding: o200k_base
Snapshot 21a254f
← Back to SKILL.md
1package plan2 3import (4 "os"5 "path/filepath"6 "slices"7 "testing"8 9 "github.com/railwayapp/railpack/core/app"10 "github.com/stretchr/testify/require"11)12 13func TestCheckAndParseDockerignore(t *testing.T) {14 t.Run("valid dockerignore file", func(t *testing.T) {15 examplePath := filepath.Join("..", "..", "examples", "dockerignore")16 testApp, err := app.NewApp(examplePath)17 require.NoError(t, err)18 19 patterns, err := checkAndParseDockerignore(testApp)20 21 require.NoError(t, err)22 require.NotNil(t, patterns)23 require.Contains(t, patterns, "!negation_test/should_exist.txt")24 require.Contains(t, patterns, "!negation_test/existing_folder")25 26 // Verify some expected patterns from examples/dockerignore/.dockerignore27 // Note: patterns are parsed by the moby/patternmatcher library28 expectedPatterns := []string{29 ".vscode",30 ".copier", // Leading slash is stripped31 ".env-specific",32 ".env*",33 "__pycache__", // Trailing slash is stripped34 "test", // Leading slash is stripped35 "tmp/*", // Leading slash is stripped36 "*.log",37 "Justfile",38 "TODO*", // Leading slash is stripped39 "README.md", // Leading slash is stripped40 "docker-compose*.yml",41 }42 43 for _, expected := range expectedPatterns {44 require.Contains(t, patterns, expected, "Expected pattern %s not found in patterns", expected)45 }46 })47 48 t.Run("inaccessible dockerignore", func(t *testing.T) {49 // Create a temporary directory and file50 tempDir, err := os.MkdirTemp("", "dockerignore-test")51 require.NoError(t, err)52 defer func() { _ = os.RemoveAll(tempDir) }()53 54 dockerignorePath := filepath.Join(tempDir, ".dockerignore")55 err = os.WriteFile(dockerignorePath, []byte("*.log\nnode_modules\n"), 0644)56 require.NoError(t, err)57 58 // Make the file unreadable (this simulates permission errors)59 err = os.Chmod(dockerignorePath, 0000)60 require.NoError(t, err)61 defer func() { _ = os.Chmod(dockerignorePath, 0644) }() // Restore permissions for cleanup62 63 testApp, err := app.NewApp(tempDir)64 require.NoError(t, err)65 66 // This should fail with a permission error67 patterns, err := checkAndParseDockerignore(testApp)68 require.Error(t, err)69 require.Contains(t, err.Error(), "error reading .dockerignore")70 require.Nil(t, patterns)71 })72}73 74func TestDockerignoreExamples(t *testing.T) {75 wd, err := os.Getwd()76 require.NoError(t, err)77 78 examplesDir := filepath.Join(filepath.Dir(filepath.Dir(wd)), "examples")79 entries, err := os.ReadDir(examplesDir)80 require.NoError(t, err)81 82 expectedAsEmpty := []string{"mise-config"}83 foundAsEmpty := []string{}84 testedExamples := 085 for _, entry := range entries {86 if !entry.IsDir() {87 continue88 }89 90 examplePath := filepath.Join(examplesDir, entry.Name())91 dockerignorePath := filepath.Join(examplePath, ".dockerignore")92 _, err := os.Stat(dockerignorePath)93 if os.IsNotExist(err) {94 continue95 }96 require.NoError(t, err)97 98 testedExamples++99 t.Run(entry.Name(), func(t *testing.T) {100 testApp, err := app.NewApp(examplePath)101 require.NoError(t, err)102 103 ctx, err := NewDockerignoreContext(testApp)104 require.NoError(t, err)105 require.True(t, ctx.HasFile)106 if slices.Contains(expectedAsEmpty, entry.Name()) {107 foundAsEmpty = append(foundAsEmpty, entry.Name())108 require.Empty(t, ctx.Excludes)109 return110 }111 require.NotEmpty(t, ctx.Excludes)112 })113 }114 115 require.Positive(t, testedExamples, "expected at least one example with a .dockerignore")116 require.ElementsMatch(t, expectedAsEmpty, foundAsEmpty)117}118 119func TestDockerignoreContext(t *testing.T) {120 t.Run("new context", func(t *testing.T) {121 tempDir, err := os.MkdirTemp("", "dockerignore-test")122 require.NoError(t, err)123 defer func() { _ = os.RemoveAll(tempDir) }()124 125 testApp, err := app.NewApp(tempDir)126 require.NoError(t, err)127 128 ctx, err := NewDockerignoreContext(testApp)129 require.NoError(t, err)130 require.NotNil(t, ctx)131 require.False(t, ctx.HasFile)132 require.Nil(t, ctx.Excludes)133 })134 135 t.Run("context with dockerignore file", func(t *testing.T) {136 examplePath := filepath.Join("..", "..", "examples", "dockerignore")137 testApp, err := app.NewApp(examplePath)138 require.NoError(t, err)139 140 ctx, err := NewDockerignoreContext(testApp)141 require.NoError(t, err)142 require.True(t, ctx.HasFile)143 require.NotNil(t, ctx.Excludes)144 require.Contains(t, ctx.Excludes, "!negation_test/should_exist.txt")145 require.Contains(t, ctx.Excludes, "!negation_test/existing_folder")146 })147 148 t.Run("parse nonexistent file", func(t *testing.T) {149 tempDir, err := os.MkdirTemp("", "dockerignore-test")150 require.NoError(t, err)151 defer func() { _ = os.RemoveAll(tempDir) }()152 153 testApp, err := app.NewApp(tempDir)154 require.NoError(t, err)155 156 ctx, err := NewDockerignoreContext(testApp)157 require.NoError(t, err)158 require.False(t, ctx.HasFile)159 require.Nil(t, ctx.Excludes)160 })161 162 t.Run("parse error handling", func(t *testing.T) {163 // Create a temporary directory with an inaccessible .dockerignore164 tempDir, err := os.MkdirTemp("", "dockerignore-test")165 require.NoError(t, err)166 defer func() { _ = os.RemoveAll(tempDir) }()167 168 dockerignorePath := filepath.Join(tempDir, ".dockerignore")169 err = os.WriteFile(dockerignorePath, []byte("*.log\n"), 0644)170 require.NoError(t, err)171 172 // Make the file unreadable173 err = os.Chmod(dockerignorePath, 0000)174 require.NoError(t, err)175 defer func() { _ = os.Chmod(dockerignorePath, 0644) }()176 177 testApp, err := app.NewApp(tempDir)178 require.NoError(t, err)179 180 ctx, err := NewDockerignoreContext(testApp)181 require.Error(t, err)182 require.Nil(t, ctx)183 })184}185 186func TestDockerignoreDuplicatePatterns(t *testing.T) {187 t.Run("duplicate patterns not removed from raw output", func(t *testing.T) {188 tempDir, err := os.MkdirTemp("", "dockerignore-test")189 require.NoError(t, err)190 defer func() { _ = os.RemoveAll(tempDir) }()191 192 // Create test files193 err = os.WriteFile(filepath.Join(tempDir, "keep.txt"), []byte("exists"), 0644)194 require.NoError(t, err)195 196 // Create .dockerignore with duplicate patterns197 dockerignoreContent := `*.log198*.log199node_modules200!keep.txt201!keep.txt202`203 err = os.WriteFile(filepath.Join(tempDir, ".dockerignore"), []byte(dockerignoreContent), 0644)204 require.NoError(t, err)205 206 testApp, err := app.NewApp(tempDir)207 require.NoError(t, err)208 209 ctx, err := NewDockerignoreContext(testApp)210 require.NoError(t, err)211 212 // Count occurrences of each pattern213 logCount := 0214 nodeModulesCount := 0215 keepCount := 0216 for _, pattern := range ctx.Excludes {217 if pattern == "*.log" {218 logCount++219 }220 if pattern == "node_modules" {221 nodeModulesCount++222 }223 if pattern == "!keep.txt" {224 keepCount++225 }226 }227 228 // Duplicates are preserved in raw output (will be handled downstream)229 require.Equal(t, 2, logCount, "*.log pattern should appear twice")230 require.Equal(t, 1, nodeModulesCount, "node_modules pattern should appear once")231 require.Equal(t, 2, keepCount, "!keep.txt pattern should appear twice")232 })233}234 235func TestCheckAndParseDockerignoreWithNegation(t *testing.T) {236 t.Run("negated patterns preserved in output", func(t *testing.T) {237 tempDir, err := os.MkdirTemp("", "dockerignore-test")238 require.NoError(t, err)239 defer func() { _ = os.RemoveAll(tempDir) }()240 241 // Create test files242 err = os.MkdirAll(filepath.Join(tempDir, "negation_test", "existing_folder"), 0755)243 require.NoError(t, err)244 err = os.WriteFile(filepath.Join(tempDir, "negation_test", "should_exist.txt"), []byte("exists"), 0644)245 require.NoError(t, err)246 err = os.WriteFile(filepath.Join(tempDir, "negation_test", "existing_folder", "file.txt"), []byte("exists"), 0644)247 require.NoError(t, err)248 249 // Create .dockerignore with mixed negation cases250 dockerignoreContent := `251negation_test/*252!negation_test/should_exist.txt253!negation_test/should_not_exist.txt254!negation_test/folder_does_not_exist/255!negation_test/existing_folder/256`257 err = os.WriteFile(filepath.Join(tempDir, ".dockerignore"), []byte(dockerignoreContent), 0644)258 require.NoError(t, err)259 260 testApp, err := app.NewApp(tempDir)261 require.NoError(t, err)262 263 patterns, err := checkAndParseDockerignore(testApp)264 require.NoError(t, err)265 266 // All patterns (both exclude and negated) should be preserved267 require.Contains(t, patterns, "negation_test/*")268 require.Contains(t, patterns, "!negation_test/should_exist.txt")269 require.Contains(t, patterns, "!negation_test/should_not_exist.txt")270 require.Contains(t, patterns, "!negation_test/folder_does_not_exist")271 require.Contains(t, patterns, "!negation_test/existing_folder")272 })273}274