k8s.io/kubernetes@v1.31.0-alpha.0.0.20240520171757-56147500dadc/cmd/import-boss/main_test.go (about) 1 /* 2 Copyright 2024 The Kubernetes Authors. 3 4 Licensed under the Apache License, Version 2.0 (the "License"); 5 you may not use this file except in compliance with the License. 6 You may obtain a copy of the License at 7 8 http://www.apache.org/licenses/LICENSE-2.0 9 10 Unless required by applicable law or agreed to in writing, software 11 distributed under the License is distributed on an "AS IS" BASIS, 12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 See the License for the specific language governing permissions and 14 limitations under the License. 15 */ 16 17 package main 18 19 import ( 20 "path/filepath" 21 "reflect" 22 goruntime "runtime" 23 "strings" 24 "testing" 25 26 "golang.org/x/tools/go/packages" 27 ) 28 29 func TestRemoveLastDir(t *testing.T) { 30 table := map[string]struct{ newPath, removedDir string }{ 31 "a/b/c": {"a/c", "b"}, 32 } 33 for slashInput, expect := range table { 34 input := filepath.FromSlash(slashInput) 35 36 gotPath, gotRemoved := removeLastDir(input) 37 if e, a := filepath.FromSlash(expect.newPath), gotPath; e != a { 38 t.Errorf("%v: wanted %v, got %v", input, e, a) 39 } 40 if e, a := filepath.FromSlash(expect.removedDir), gotRemoved; e != a { 41 t.Errorf("%v: wanted %v, got %v", input, e, a) 42 } 43 } 44 } 45 46 func TestTransitiveClosure(t *testing.T) { 47 cases := []struct { 48 name string 49 in map[string][]string 50 expected map[string][]string 51 }{ 52 { 53 name: "no transition", 54 in: map[string][]string{ 55 "a": {"b"}, 56 "c": {"d"}, 57 }, 58 expected: map[string][]string{ 59 "a": {"b"}, 60 "c": {"d"}, 61 }, 62 }, 63 { 64 name: "simple", 65 in: map[string][]string{ 66 "a": {"b"}, 67 "b": {"c"}, 68 "c": {"d"}, 69 }, 70 expected: map[string][]string{ 71 "a": {"b", "c", "d"}, 72 "b": {"c", "d"}, 73 "c": {"d"}, 74 }, 75 }, 76 } 77 78 for _, c := range cases { 79 t.Run(c.name, func(t *testing.T) { 80 out := transitiveClosure(c.in) 81 if !reflect.DeepEqual(c.expected, out) { 82 t.Errorf("expected: %#v, got %#v", c.expected, out) 83 } 84 }) 85 } 86 } 87 88 func TestHasTestFiles(t *testing.T) { 89 cases := []struct { 90 input []string 91 expect bool 92 }{{ 93 input: nil, 94 expect: false, 95 }, { 96 input: []string{}, 97 expect: false, 98 }, { 99 input: []string{"foo.go"}, 100 expect: false, 101 }, { 102 input: []string{"foo.go", "bar.go"}, 103 expect: false, 104 }, { 105 input: []string{"foo_test.go"}, 106 expect: true, 107 }, { 108 input: []string{"foo.go", "foo_test.go"}, 109 expect: true, 110 }, { 111 input: []string{"foo.go", "foo_test.go", "bar.go", "bar_test.go"}, 112 expect: true, 113 }} 114 115 for _, tc := range cases { 116 ret := hasTestFiles(tc.input) 117 if ret != tc.expect { 118 t.Errorf("expected %v, got %v: %q", tc.expect, ret, tc.input) 119 } 120 } 121 } 122 123 func TestPackageDir(t *testing.T) { 124 if goruntime.GOOS == "windows" { 125 // TODO: remove skip once the failing test has been fixed. 126 t.Skip("Skip failing test on Windows.") 127 } 128 cases := []struct { 129 input *packages.Package 130 expect string 131 }{{ 132 input: &packages.Package{ 133 PkgPath: "example.com/foo/bar/qux", 134 GoFiles: []string{"/src/prj/file.go"}, 135 IgnoredFiles: []string{"/otherdir/file.go"}, 136 }, 137 expect: "/src/prj", 138 }, { 139 input: &packages.Package{ 140 PkgPath: "example.com/foo/bar/qux", 141 IgnoredFiles: []string{"/src/prj/file.go"}, 142 }, 143 expect: "/src/prj", 144 }, { 145 input: &packages.Package{ 146 PkgPath: "example.com/foo/bar/qux", 147 }, 148 expect: "", 149 }} 150 151 for i, tc := range cases { 152 ret := packageDir(tc.input) 153 if ret != tc.expect { 154 t.Errorf("[%d] expected %v, got %v: %q", i, tc.expect, ret, tc.input) 155 } 156 } 157 } 158 159 func TestHasPathPrefix(t *testing.T) { 160 if goruntime.GOOS == "windows" { 161 // TODO: remove skip once the failing test has been fixed. 162 t.Skip("Skip failing test on Windows.") 163 } 164 cases := []struct { 165 base string 166 pfx string 167 expect bool 168 }{{ 169 base: "", 170 pfx: "", 171 expect: true, 172 }, { 173 base: "/foo/bar", 174 pfx: "", 175 expect: true, 176 }, { 177 base: "", 178 pfx: "/foo", 179 expect: false, 180 }, { 181 base: "/foo", 182 pfx: "/foo", 183 expect: true, 184 }, { 185 base: "/foo/bar", 186 pfx: "/foo", 187 expect: true, 188 }, { 189 base: "/foobar/qux", 190 pfx: "/foo", 191 expect: false, 192 }, { 193 base: "/foo/bar/bat/qux/zrb", 194 pfx: "/foo/bar/bat", 195 expect: true, 196 }} 197 198 for _, tc := range cases { 199 ret := hasPathPrefix(tc.base, tc.pfx) 200 if ret != tc.expect { 201 t.Errorf("expected %v, got %v: (%q, %q)", tc.expect, ret, tc.base, tc.pfx) 202 } 203 } 204 } 205 206 func checkAllErrorStrings(t *testing.T, errs []error, expect []string) { 207 t.Helper() 208 if len(errs) != len(expect) { 209 t.Fatalf("expected %d errors, got %d: %q", len(expect), len(errs), errs) 210 } 211 212 for _, str := range expect { 213 found := false 214 for _, err := range errs { 215 if strings.HasPrefix(err.Error(), str) { 216 found = true 217 break 218 } 219 } 220 if !found { 221 t.Errorf("did not find error %q", str) 222 t.Logf("\tseek: %s\n\t in:", str) 223 for _, err := range errs { 224 t.Logf("\t %s", err.Error()) 225 } 226 } 227 } 228 } 229 230 func TestSimpleForward(t *testing.T) { 231 if goruntime.GOOS == "windows" { 232 // TODO: remove skip once the failing test has been fixed. 233 t.Skip("Skip failing test on Windows.") 234 } 235 pkgs, err := loadPkgs("./testdata/simple-fwd/aaa") 236 if err != nil { 237 t.Fatalf("unexpected failure: %v", err) 238 } 239 if len(pkgs) != 1 { 240 t.Fatalf("expected 1 pkg result, got %d", len(pkgs)) 241 } 242 if pkgs[0].PkgPath != "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" { 243 t.Fatalf("wrong PkgPath: %q", pkgs[0].PkgPath) 244 } 245 246 boss := newBoss(pkgs) 247 errs := boss.Verify(pkgs[0]) 248 249 expect := []string{ 250 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/forbidden" is forbidden`, 251 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/forbidden/f1" is forbidden`, 252 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/neither" did not match any rule`, 253 `"k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/simple-fwd/neither/n1" did not match any rule`, 254 } 255 256 checkAllErrorStrings(t, errs, expect) 257 } 258 259 func TestNestedForward(t *testing.T) { 260 pkgs, err := loadPkgs("./testdata/nested-fwd/aaa") 261 if err != nil { 262 t.Fatalf("unexpected failure: %v", err) 263 } 264 if len(pkgs) != 1 { 265 t.Fatalf("expected 1 pkg result, got %d", len(pkgs)) 266 } 267 if pkgs[0].PkgPath != "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" { 268 t.Fatalf("wrong PkgPath: %q", pkgs[0].PkgPath) 269 } 270 271 boss := newBoss(pkgs) 272 errs := boss.Verify(pkgs[0]) 273 274 expect := []string{ 275 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-both" is forbidden`, 276 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-root" is forbidden`, 277 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/forbidden-by-sub" is forbidden`, 278 `"k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/aaa" -> "k8s.io/kubernetes/cmd/import-boss/testdata/nested-fwd/neither/n1" did not match any rule`, 279 } 280 281 checkAllErrorStrings(t, errs, expect) 282 } 283 284 func TestInverse(t *testing.T) { 285 pkgs, err := loadPkgs("./testdata/inverse/...") 286 if err != nil { 287 t.Fatalf("unexpected failure: %v", err) 288 } 289 if len(pkgs) != 10 { 290 t.Fatalf("expected 10 pkg results, got %d", len(pkgs)) 291 } 292 293 boss := newBoss(pkgs) 294 295 var errs []error 296 for _, pkg := range pkgs { 297 errs = append(errs, boss.Verify(pkg)...) 298 } 299 300 expect := []string{ 301 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/aaa" is forbidden`, 302 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden/f1" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/aaa" is forbidden`, 303 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed/a2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed" did not match any rule`, 304 `"k8s.io/kubernetes/cmd/import-boss/testdata/inverse/forbidden/f2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/inverse/allowed" did not match any rule`, 305 } 306 307 checkAllErrorStrings(t, errs, expect) 308 } 309 310 func TestTransitive(t *testing.T) { 311 pkgs, err := loadPkgs("./testdata/transitive/...") 312 if err != nil { 313 t.Fatalf("unexpected failure: %v", err) 314 } 315 if len(pkgs) != 10 { 316 t.Fatalf("expected 10 pkg results, got %d", len(pkgs)) 317 } 318 319 boss := newBoss(pkgs) 320 321 var errs []error 322 for _, pkg := range pkgs { 323 errs = append(errs, boss.Verify(pkg)...) 324 } 325 326 expect := []string{ 327 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`, 328 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f1" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`, 329 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f2" <-- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/aaa" is forbidden`, 330 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed/a2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed" did not match any rule`, 331 `"k8s.io/kubernetes/cmd/import-boss/testdata/transitive/forbidden/f2" <- "k8s.io/kubernetes/cmd/import-boss/testdata/transitive/allowed" did not match any rule`, 332 } 333 334 checkAllErrorStrings(t, errs, expect) 335 }