11package manifest
22
33import (
4+ "bytes"
5+ "fmt"
6+ "io/ioutil"
7+ "path/filepath"
48 "testing"
59
610 "github.com/containers/image/v5/pkg/compression"
@@ -11,6 +15,86 @@ import (
1115 "github.com/stretchr/testify/require"
1216)
1317
18+ func TestValidateUnambiguousManifestFormat (t * testing.T ) {
19+ const allAllowedFields = allowedFieldFirstUnusedBit - 1
20+ const mt = "text/plain" // Just some MIME type that shows up in error messages
21+
22+ type test struct {
23+ manifest string
24+ allowed allowedManifestFields
25+ }
26+
27+ // Smoke tests: Success
28+ for _ , c := range []test {
29+ {"{}" , allAllowedFields },
30+ {"{}" , 0 },
31+ } {
32+ err := validateUnambiguousManifestFormat ([]byte (c .manifest ), mt , c .allowed )
33+ assert .NoError (t , err , c )
34+ }
35+ // Smoke tests: Failure
36+ for _ , c := range []test {
37+ {"{}" , allowedFieldFirstUnusedBit }, // Invalid "allowed"
38+ {"@" , allAllowedFields }, // Invalid JSON
39+ } {
40+ err := validateUnambiguousManifestFormat ([]byte (c .manifest ), mt , c .allowed )
41+ assert .Error (t , err , c )
42+ }
43+
44+ fields := map [allowedManifestFields ]string {
45+ allowedFieldConfig : "config" ,
46+ allowedFieldFSLayers : "fsLayers" ,
47+ allowedFieldHistory : "history" ,
48+ allowedFieldLayers : "layers" ,
49+ allowedFieldManifests : "manifests" ,
50+ }
51+ // Ensure this test covers all defined allowedManifestFields values
52+ allFields := allowedManifestFields (0 )
53+ for k := range fields {
54+ allFields |= k
55+ }
56+ assert .Equal (t , allAllowedFields , allFields )
57+
58+ // Every single field is allowed by its bit, and rejected by any other bit
59+ for bit , fieldName := range fields {
60+ json := []byte (fmt .Sprintf (`{"%s":[]}` , fieldName ))
61+ err := validateUnambiguousManifestFormat (json , mt , bit )
62+ assert .NoError (t , err , fieldName )
63+ err = validateUnambiguousManifestFormat (json , mt , allAllowedFields ^ bit )
64+ assert .Error (t , err , fieldName )
65+ }
66+ }
67+
68+ // Test that parser() rejects all of the provided manifest fixtures.
69+ // Intended to help test manifest parsers' detection of schema mismatches.
70+ func testManifestFixturesAreRejected (t * testing.T , parser func ([]byte ) error , fixtures []string ) {
71+ for _ , fixture := range fixtures {
72+ manifest , err := ioutil .ReadFile (filepath .Join ("fixtures" , fixture ))
73+ require .NoError (t , err , fixture )
74+ err = parser (manifest )
75+ assert .Error (t , err , fixture )
76+ }
77+ }
78+
79+ // Test that parser() rejects validManifest with an added top-level field with any of the provided field names.
80+ // Intended to help test callers of validateUnambiguousManifestFormat.
81+ func testValidManifestWithExtraFieldsIsRejected (t * testing.T , parser func ([]byte ) error ,
82+ validManifest []byte , fields []string ) {
83+ for _ , field := range fields {
84+ // end (the final '}') is not always at len(validManifest)-1 because the manifest can end with
85+ // white space.
86+ end := bytes .LastIndexByte (validManifest , '}' )
87+ require .NotEqual (t , end , - 1 )
88+ updatedManifest := []byte (string (validManifest [:end ]) +
89+ fmt .Sprintf (`,"%s":[]}` , field ))
90+ err := parser (updatedManifest )
91+ assert .Error (t , err , field )
92+ // Make sure it is the error from validateUnambiguousManifestFormat, not something that
93+ // went wrong with creating updatedManifest.
94+ assert .Contains (t , err .Error (), "rejecting ambiguous manifest" )
95+ }
96+ }
97+
1498func TestLayerInfosToStrings (t * testing.T ) {
1599 strings := layerInfosToStrings ([]LayerInfo {})
16100 assert .Equal (t , []string {}, strings )
0 commit comments