diff --git a/internal/manifest/manifest.go b/internal/manifest/manifest.go index dbe04b3e..728471b9 100644 --- a/internal/manifest/manifest.go +++ b/internal/manifest/manifest.go @@ -130,7 +130,6 @@ func Validate(manifest *Manifest) (err error) { return err } - // TODO duplicated should not be a problem, here an in delete below. pathToSlices := map[string][]string{} err = manifest.IterateContents("", func(content Content) error { if !sliceExist[content.Slice] { @@ -145,6 +144,7 @@ func Validate(manifest *Manifest) (err error) { return err } + done := map[string]bool{} err = manifest.IteratePaths("", func(path Path) error { pathSlices, ok := pathToSlices[path.Path] if !ok { @@ -155,15 +155,14 @@ func Validate(manifest *Manifest) (err error) { if !slices.Equal(pathSlices, path.Slices) { return fmt.Errorf(`path %s and content have diverging slices: %q != %q`, path.Path, path.Slices, pathSlices) } - // TODO This disallows duplicates. - delete(pathToSlices, path.Path) + done[path.Path] = true return nil }) if err != nil { return err } - if len(pathToSlices) > 0 { + if len(done) != len(pathToSlices) { for path := range pathToSlices { return fmt.Errorf(`content path %s has no matching entry in paths`, path) } diff --git a/internal/manifest/manifest_test.go b/internal/manifest/manifest_test.go index 38cc1896..a1fc0f3b 100644 --- a/internal/manifest/manifest_test.go +++ b/internal/manifest/manifest_test.go @@ -22,108 +22,120 @@ type manifestContents struct { var manifestTests = []struct { summary string input string - mfest manifestContents + mfest *manifestContents valError string readError string -}{ - { - summary: "All types", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":13} - {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} - {"kind":"content","slice":"pkg1_myslice","path":"/dir/file"} - {"kind":"content","slice":"pkg1_myslice","path":"/dir/foo/bar/"} - {"kind":"content","slice":"pkg1_myslice","path":"/dir/link/file"} - {"kind":"content","slice":"pkg2_myotherslice","path":"/dir/foo/bar/"} - {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} - {"kind":"package","name":"pkg2","version":"v2","sha256":"hash2","arch":"arch2"} - {"kind":"path","path":"/dir/file","mode":"0644","slices":["pkg1_myslice"],"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","final_sha256":"8067926c032c090867013d14fb0eb21ae858344f62ad07086fd32375845c91a6","size":21} - {"kind":"path","path":"/dir/foo/bar/","mode":"01777","slices":["pkg2_myotherslice","pkg1_myslice"]} - {"kind":"path","path":"/dir/link/file","mode":"0644","slices":["pkg1_myslice"],"link":"/dir/file"} - {"kind":"path","path":"/manifest/manifest.wall","mode":"0644","slices":["pkg1_manifest"]} - {"kind":"slice","name":"pkg1_manifest"} - {"kind":"slice","name":"pkg1_myslice"} - {"kind":"slice","name":"pkg2_myotherslice"} - `, - mfest: manifestContents{ - Paths: []manifest.Path{ - {Kind: "path", Path: "/dir/file", Mode: "0644", Slices: []string{"pkg1_myslice"}, Hash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", FinalHash: "8067926c032c090867013d14fb0eb21ae858344f62ad07086fd32375845c91a6", Size: 0x15, Link: ""}, - {Kind: "path", Path: "/dir/foo/bar/", Mode: "01777", Slices: []string{"pkg2_myotherslice", "pkg1_myslice"}, Hash: "", FinalHash: "", Size: 0x0, Link: ""}, - {Kind: "path", Path: "/dir/link/file", Mode: "0644", Slices: []string{"pkg1_myslice"}, Hash: "", FinalHash: "", Size: 0x0, Link: "/dir/file"}, - {Kind: "path", Path: "/manifest/manifest.wall", Mode: "0644", Slices: []string{"pkg1_manifest"}, Hash: "", FinalHash: "", Size: 0x0, Link: ""}, - }, - Packages: []manifest.Package{ - {Kind: "package", Name: "pkg1", Version: "v1", Digest: "hash1", Arch: "arch1"}, - {Kind: "package", Name: "pkg2", Version: "v2", Digest: "hash2", Arch: "arch2"}, - }, - Slices: []manifest.Slice{ - {Kind: "slice", Name: "pkg1_manifest"}, - {Kind: "slice", Name: "pkg1_myslice"}, - {Kind: "slice", Name: "pkg2_myotherslice"}, - }, - Contents: []manifest.Content{ - {Kind: "content", Slice: "pkg1_manifest", Path: "/manifest/manifest.wall"}, - {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/file"}, - {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/foo/bar/"}, - {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/link/file"}, - {Kind: "content", Slice: "pkg2_myotherslice", Path: "/dir/foo/bar/"}, - }, +}{{ + summary: "All types", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":13} + {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} + {"kind":"content","slice":"pkg1_myslice","path":"/dir/file"} + {"kind":"content","slice":"pkg1_myslice","path":"/dir/foo/bar/"} + {"kind":"content","slice":"pkg1_myslice","path":"/dir/link/file"} + {"kind":"content","slice":"pkg2_myotherslice","path":"/dir/foo/bar/"} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + {"kind":"package","name":"pkg2","version":"v2","sha256":"hash2","arch":"arch2"} + {"kind":"path","path":"/dir/file","mode":"0644","slices":["pkg1_myslice"],"sha256":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","final_sha256":"8067926c032c090867013d14fb0eb21ae858344f62ad07086fd32375845c91a6","size":21} + {"kind":"path","path":"/dir/foo/bar/","mode":"01777","slices":["pkg2_myotherslice","pkg1_myslice"]} + {"kind":"path","path":"/dir/link/file","mode":"0644","slices":["pkg1_myslice"],"link":"/dir/file"} + {"kind":"path","path":"/manifest/manifest.wall","mode":"0644","slices":["pkg1_manifest"]} + {"kind":"slice","name":"pkg1_manifest"} + {"kind":"slice","name":"pkg1_myslice"} + {"kind":"slice","name":"pkg2_myotherslice"} + `, + mfest: &manifestContents{ + Paths: []manifest.Path{ + {Kind: "path", Path: "/dir/file", Mode: "0644", Slices: []string{"pkg1_myslice"}, Hash: "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", FinalHash: "8067926c032c090867013d14fb0eb21ae858344f62ad07086fd32375845c91a6", Size: 0x15, Link: ""}, + {Kind: "path", Path: "/dir/foo/bar/", Mode: "01777", Slices: []string{"pkg2_myotherslice", "pkg1_myslice"}, Hash: "", FinalHash: "", Size: 0x0, Link: ""}, + {Kind: "path", Path: "/dir/link/file", Mode: "0644", Slices: []string{"pkg1_myslice"}, Hash: "", FinalHash: "", Size: 0x0, Link: "/dir/file"}, + {Kind: "path", Path: "/manifest/manifest.wall", Mode: "0644", Slices: []string{"pkg1_manifest"}, Hash: "", FinalHash: "", Size: 0x0, Link: ""}, }, - }, { - summary: "Slice not found", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":1} - {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} - `, - valError: `invalid manifest: slice pkg1_manifest not found in slices`, - }, { - summary: "Package not found", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":1} - {"kind":"slice","name":"pkg1_manifest"} - `, - valError: `invalid manifest: package "pkg1" not found in packages`, - }, { - summary: "Path not found in contents", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":1} - {"kind":"path","path":"/dir/","mode":"01777","slices":["pkg1_myslice"]} - `, - valError: `invalid manifest: path /dir/ has no matching entry in contents`, - }, { - summary: "Content and path have different slices", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":3} - {"kind":"content","slice":"pkg1_myotherslice","path":"/dir/"} - {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} - {"kind":"path","path":"/dir/","mode":"01777","slices":["pkg1_myslice"]} - {"kind":"slice","name":"pkg1_myotherslice"} - `, - valError: `invalid manifest: path /dir/ and content have diverging slices: \["pkg1_myslice"\] != \["pkg1_myotherslice"\]`, - }, { - summary: "Content not found in paths", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":3} - {"kind":"content","slice":"pkg1_myslice","path":"/dir/"} - {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} - {"kind":"slice","name":"pkg1_myslice"} - `, - valError: `invalid manifest: content path /dir/ has no matching entry in paths`, - }, { - summary: "Malformed jsonwall", - input: ` - {"jsonwall":"1.0","schema":"1.0","count":1} - {"kind":"content", "not valid json" - `, - valError: `invalid manifest: cannot read manifest: unexpected end of JSON input`, - }, { - summary: "Unknown schema", - input: ` - {"jsonwall":"1.0","schema":"2.0","count":1} - {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} - `, - readError: `cannot read manifest: unknown schema version "2.0"`, - }} + Packages: []manifest.Package{ + {Kind: "package", Name: "pkg1", Version: "v1", Digest: "hash1", Arch: "arch1"}, + {Kind: "package", Name: "pkg2", Version: "v2", Digest: "hash2", Arch: "arch2"}, + }, + Slices: []manifest.Slice{ + {Kind: "slice", Name: "pkg1_manifest"}, + {Kind: "slice", Name: "pkg1_myslice"}, + {Kind: "slice", Name: "pkg2_myotherslice"}, + }, + Contents: []manifest.Content{ + {Kind: "content", Slice: "pkg1_manifest", Path: "/manifest/manifest.wall"}, + {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/file"}, + {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/foo/bar/"}, + {Kind: "content", Slice: "pkg1_myslice", Path: "/dir/link/file"}, + {Kind: "content", Slice: "pkg2_myotherslice", Path: "/dir/foo/bar/"}, + }, + }, +}, { + summary: "Slice not found", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":1} + {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} + `, + valError: `invalid manifest: slice pkg1_manifest not found in slices`, +}, { + summary: "Package not found", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":1} + {"kind":"slice","name":"pkg1_manifest"} + `, + valError: `invalid manifest: package "pkg1" not found in packages`, +}, { + summary: "Path not found in contents", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":1} + {"kind":"path","path":"/dir/","mode":"01777","slices":["pkg1_myslice"]} + `, + valError: `invalid manifest: path /dir/ has no matching entry in contents`, +}, { + summary: "Content and path have different slices", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":3} + {"kind":"content","slice":"pkg1_myotherslice","path":"/dir/"} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + {"kind":"path","path":"/dir/","mode":"01777","slices":["pkg1_myslice"]} + {"kind":"slice","name":"pkg1_myotherslice"} + `, + valError: `invalid manifest: path /dir/ and content have diverging slices: \["pkg1_myslice"\] != \["pkg1_myotherslice"\]`, +}, { + summary: "Content not found in paths", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":3} + {"kind":"content","slice":"pkg1_myslice","path":"/dir/"} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + {"kind":"slice","name":"pkg1_myslice"} + `, + valError: `invalid manifest: content path /dir/ has no matching entry in paths`, +}, { + summary: "Malformed jsonwall", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":1} + {"kind":"content", "not valid json" + `, + valError: `invalid manifest: cannot read manifest: unexpected end of JSON input`, +}, { + summary: "Unknown schema", + input: ` + {"jsonwall":"1.0","schema":"2.0","count":1} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + `, + readError: `cannot read manifest: unknown schema version "2.0"`, +}, { + summary: "Duplication is not an error", + input: ` + {"jsonwall":"1.0","schema":"1.0","count":8} + {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} + {"kind":"content","slice":"pkg1_manifest","path":"/manifest/manifest.wall"} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + {"kind":"package","name":"pkg1","version":"v1","sha256":"hash1","arch":"arch1"} + {"kind":"path","path":"/manifest/manifest.wall","mode":"0644","slices":["pkg1_manifest"]} + {"kind":"path","path":"/manifest/manifest.wall","mode":"0644","slices":["pkg1_manifest"]} + {"kind":"slice","name":"pkg1_manifest"} + {"kind":"slice","name":"pkg1_manifest"} + `, +}} func (s *S) TestRun(c *C) { for _, test := range manifestTests { @@ -164,11 +176,13 @@ func (s *S) TestRun(c *C) { continue } c.Assert(err, IsNil) - c.Assert(dumpManifestContents(c, mfest), DeepEquals, test.mfest) + if test.mfest != nil { + c.Assert(dumpManifestContents(c, mfest), DeepEquals, test.mfest) + } } } -func dumpManifestContents(c *C, mfest *manifest.Manifest) manifestContents { +func dumpManifestContents(c *C, mfest *manifest.Manifest) *manifestContents { var slices []manifest.Slice err := mfest.IterateSlices("", func(slice manifest.Slice) error { slices = append(slices, slice) @@ -203,5 +217,5 @@ func dumpManifestContents(c *C, mfest *manifest.Manifest) manifestContents { Slices: slices, Contents: contents, } - return mc + return &mc }