buildkit/build_llb/layers_test.go
buildkit/build_llb/layers_test.goBrowse 1970 files
1,861 tokens
6,209 bytes
Token encoding: o200k_base
Snapshot 21a254f
← Back to SKILL.md
1package build_llb2 3import (4 "testing"5 6 "github.com/google/go-cmp/cmp"7 "github.com/railwayapp/railpack/core/plan"8 "github.com/stretchr/testify/require"9)10 11func TestShouldLLBMerge(t *testing.T) {12 tests := []struct {13 name string14 input []plan.Layer15 expected bool16 }{17 {18 name: "no layers",19 input: []plan.Layer{},20 expected: true,21 },22 23 {24 name: "no overlap with excludes",25 input: []plan.Layer{26 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules"})),27 plan.NewStepLayer("build", plan.NewFilter([]string{"."}, []string{"node_modules"})),28 plan.NewStepLayer("build", plan.NewIncludeFilter([]string{"/root/.cache"})),29 },30 expected: true,31 },32 33 {34 name: "no overlap different roots",35 input: []plan.Layer{36 plan.NewStepLayer("mise", plan.NewIncludeFilter([]string{"/mise/shims", "/mise/installs"})),37 plan.NewStepLayer("build", plan.NewIncludeFilter([]string{"/root/.cache"})),38 },39 expected: true,40 },41 42 {43 name: "overlapping include",44 input: []plan.Layer{45 plan.NewStepLayer("build", plan.NewIncludeFilter([]string{"."})),46 plan.NewStepLayer("build", plan.NewIncludeFilter([]string{".", "/root/.cache"})),47 },48 expected: false,49 },50 51 {52 name: "overlapping with exclude",53 input: []plan.Layer{54 plan.NewStepLayer("build", plan.NewFilter([]string{"/root/.cache", "."}, []string{"node_modules", ".yarn"})),55 plan.NewStepLayer("build", plan.NewFilter([]string{"/something/else", "."}, []string{})),56 },57 expected: false,58 },59 60 {61 name: "path contains no exclude",62 input: []plan.Layer{63 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules"})),64 plan.NewStepLayer("build", plan.NewIncludeFilter([]string{"/app"})),65 },66 expected: false,67 },68 69 {70 name: "overlap excluded by containing layer",71 input: []plan.Layer{72 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules"})),73 plan.NewStepLayer("build", plan.NewFilter([]string{"/app"}, []string{"node_modules"})),74 },75 expected: true,76 },77 78 {79 name: "nested path excluded",80 input: []plan.Layer{81 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules/.cache"})),82 plan.NewStepLayer("build", plan.NewFilter([]string{"/app"}, []string{"node_modules"})),83 },84 expected: true,85 },86 87 {88 name: "relative path overlap not excluded",89 input: []plan.Layer{90 plan.NewStepLayer("mise", plan.NewIncludeFilter([]string{".nvmrc"})),91 plan.NewStepLayer("build", plan.NewFilter([]string{"."}, []string{"node_modules", ".yarn"})),92 },93 expected: false,94 },95 96 {97 name: "relative path overlap is excluded",98 input: []plan.Layer{99 plan.NewStepLayer("mise", plan.NewIncludeFilter([]string{".nvmrc"})),100 plan.NewStepLayer("build", plan.NewFilter([]string{"."}, []string{"node_modules", ".nvmrc"})),101 },102 expected: true,103 },104 105 {106 name: "multiple overlaps some excluded",107 input: []plan.Layer{108 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules", "/app/dist"})),109 plan.NewStepLayer("build", plan.NewFilter([]string{"/app"}, []string{"node_modules"})),110 },111 expected: false, // /app/dist is not excluded, so still overlap112 },113 114 {115 name: "all overlaps excluded",116 input: []plan.Layer{117 plan.NewStepLayer("install", plan.NewIncludeFilter([]string{"/app/node_modules", "/app/.yarn"})),118 plan.NewStepLayer("build", plan.NewFilter([]string{"/app"}, []string{"node_modules", ".yarn"})),119 },120 expected: true,121 },122 }123 124 for _, tt := range tests {125 t.Run(tt.name, func(t *testing.T) {126 got := shouldLLBMerge(tt.input)127 if diff := cmp.Diff(tt.expected, got); diff != "" {128 t.Errorf("shouldLLBMerge() mismatch (-want +got):\n%s", diff)129 }130 })131 }132}133 134func TestIsPathExcluded(t *testing.T) {135 tests := []struct {136 name string137 relPath string138 excludes []string139 expected bool140 }{141 {142 name: "no excludes",143 relPath: "node_modules",144 excludes: []string{},145 expected: false,146 },147 {148 name: "exact match",149 relPath: "node_modules",150 excludes: []string{"node_modules"},151 expected: true,152 },153 {154 name: "nested path with excluded parent",155 relPath: "node_modules/.cache",156 excludes: []string{"node_modules"},157 expected: true,158 },159 {160 name: "dotfile excluded",161 relPath: ".nvmrc",162 excludes: []string{".nvmrc"},163 expected: true,164 },165 {166 name: "dotfile not excluded",167 relPath: ".nvmrc",168 excludes: []string{"node_modules", ".yarn"},169 expected: false,170 },171 {172 name: "deep nested path",173 relPath: "node_modules/foo/bar/baz",174 excludes: []string{"node_modules"},175 expected: true,176 },177 {178 name: "partial name no match",179 relPath: "node_modules_backup",180 excludes: []string{"node_modules"},181 expected: false,182 },183 }184 185 for _, tt := range tests {186 t.Run(tt.name, func(t *testing.T) {187 got := isPathExcluded(tt.relPath, tt.excludes)188 require.Equal(t, tt.expected, got)189 })190 }191}192 193func TestPathOverlap(t *testing.T) {194 tests := []struct {195 name string196 paths1 []string197 paths2 []string198 expected bool199 }{200 {201 name: "no overlap",202 paths1: []string{"/app/node_modules"},203 paths2: []string{"/app/dist"},204 expected: false,205 },206 {207 name: "direct overlap",208 paths1: []string{"/app/node_modules", "/app/dist"},209 paths2: []string{"/app/dist", "/app/src"},210 expected: true,211 },212 {213 name: "prefix overlap",214 paths1: []string{"/app/node_modules/foo"},215 paths2: []string{"/app/node_modules"},216 expected: true,217 },218 {219 name: "root path overlap",220 paths1: []string{"/app/dist"},221 paths2: []string{"/app"},222 expected: true,223 },224 {225 name: "different roots no overlap",226 paths1: []string{"/app/node_modules"},227 paths2: []string{"/var/lib"},228 expected: false,229 },230 {231 name: "similar names no overlap",232 paths1: []string{"/app-foo"},233 paths2: []string{"/app"},234 expected: false,235 },236 }237 238 for _, tt := range tests {239 t.Run(tt.name, func(t *testing.T) {240 got := hasPathOverlap(tt.paths1, tt.paths2)241 require.Equal(t, tt.expected, got)242 })243 }244}245