github.com/snyk/vervet/v3@v3.7.0/merge_test.go (about) 1 package vervet_test 2 3 import ( 4 "testing" 5 6 qt "github.com/frankban/quicktest" 7 "github.com/getkin/kin-openapi/openapi3" 8 "github.com/google/go-cmp/cmp/cmpopts" 9 10 "github.com/snyk/vervet/v3" 11 "github.com/snyk/vervet/v3/testdata" 12 ) 13 14 var openapiCmp = qt.CmpEquals(cmpopts.IgnoreUnexported(openapi3.Schema{})) 15 16 func TestMergeComponents(t *testing.T) { 17 c := qt.New(t) 18 c.Run("component without replace", func(c *qt.C) { 19 src := mustLoadFile(c, "merge_test_src.yaml") 20 dstOrig := mustLoadFile(c, "merge_test_dst.yaml") 21 dst := mustLoadFile(c, "merge_test_dst.yaml") 22 vervet.Merge(dst, src, false) 23 24 c.Assert(dst.Components.Schemas["Foo"], openapiCmp, dstOrig.Components.Schemas["Foo"]) 25 c.Assert(dst.Components.Schemas["Bar"], openapiCmp, src.Components.Schemas["Bar"]) 26 c.Assert(dst.Components.Schemas["Baz"], openapiCmp, dstOrig.Components.Schemas["Baz"]) 27 28 c.Assert(dst.Components.Parameters["Foo"], openapiCmp, dstOrig.Components.Parameters["Foo"]) 29 c.Assert(dst.Components.Parameters["Bar"], openapiCmp, src.Components.Parameters["Bar"]) 30 c.Assert(dst.Components.Parameters["Baz"], openapiCmp, dstOrig.Components.Parameters["Baz"]) 31 32 c.Assert(dst.Components.Headers["Foo"], openapiCmp, dstOrig.Components.Headers["Foo"]) 33 c.Assert(dst.Components.Headers["Bar"], openapiCmp, src.Components.Headers["Bar"]) 34 c.Assert(dst.Components.Headers["Baz"], openapiCmp, dstOrig.Components.Headers["Baz"]) 35 36 c.Assert(dst.Components.RequestBodies["Foo"], openapiCmp, dstOrig.Components.RequestBodies["Foo"]) 37 c.Assert(dst.Components.RequestBodies["Bar"], openapiCmp, src.Components.RequestBodies["Bar"]) 38 c.Assert(dst.Components.RequestBodies["Baz"], openapiCmp, dstOrig.Components.RequestBodies["Baz"]) 39 40 c.Assert(dst.Components.Responses["200"], openapiCmp, dstOrig.Components.Responses["200"]) 41 c.Assert(dst.Components.Responses["201"], openapiCmp, src.Components.Responses["201"]) 42 c.Assert(dst.Components.Responses["202"], openapiCmp, dstOrig.Components.Responses["202"]) 43 44 c.Assert(dst.Components.SecuritySchemes["Foo"], openapiCmp, dstOrig.Components.SecuritySchemes["Foo"]) 45 c.Assert(dst.Components.SecuritySchemes["Bar"], openapiCmp, src.Components.SecuritySchemes["Bar"]) 46 c.Assert(dst.Components.SecuritySchemes["Baz"], openapiCmp, dstOrig.Components.SecuritySchemes["Baz"]) 47 48 c.Assert(dst.Components.Examples["Foo"], openapiCmp, dstOrig.Components.Examples["Foo"]) 49 c.Assert(dst.Components.Examples["Bar"], openapiCmp, src.Components.Examples["Bar"]) 50 c.Assert(dst.Components.Examples["Baz"], openapiCmp, dstOrig.Components.Examples["Baz"]) 51 }) 52 c.Run("component with replace", func(c *qt.C) { 53 src := mustLoadFile(c, "merge_test_src.yaml") 54 dstOrig := mustLoadFile(c, "merge_test_dst.yaml") 55 dst := mustLoadFile(c, "merge_test_dst.yaml") 56 vervet.Merge(dst, src, true) 57 58 c.Assert(dst.Components.Schemas["Foo"], openapiCmp, src.Components.Schemas["Foo"]) 59 c.Assert(dst.Components.Schemas["Bar"], openapiCmp, src.Components.Schemas["Bar"]) 60 c.Assert(dst.Components.Schemas["Baz"], openapiCmp, dstOrig.Components.Schemas["Baz"]) 61 62 c.Assert(dst.Components.Parameters["Foo"], openapiCmp, src.Components.Parameters["Foo"]) 63 c.Assert(dst.Components.Parameters["Bar"], openapiCmp, src.Components.Parameters["Bar"]) 64 c.Assert(dst.Components.Parameters["Baz"], openapiCmp, dstOrig.Components.Parameters["Baz"]) 65 66 c.Assert(dst.Components.Headers["Foo"], openapiCmp, src.Components.Headers["Foo"]) 67 c.Assert(dst.Components.Headers["Bar"], openapiCmp, src.Components.Headers["Bar"]) 68 c.Assert(dst.Components.Headers["Baz"], openapiCmp, dstOrig.Components.Headers["Baz"]) 69 70 c.Assert(dst.Components.RequestBodies["Foo"], openapiCmp, src.Components.RequestBodies["Foo"]) 71 c.Assert(dst.Components.RequestBodies["Bar"], openapiCmp, src.Components.RequestBodies["Bar"]) 72 c.Assert(dst.Components.RequestBodies["Baz"], openapiCmp, dstOrig.Components.RequestBodies["Baz"]) 73 74 c.Assert(dst.Components.RequestBodies["200"], openapiCmp, src.Components.RequestBodies["200"]) 75 c.Assert(dst.Components.RequestBodies["201"], openapiCmp, src.Components.RequestBodies["201"]) 76 c.Assert(dst.Components.RequestBodies["202"], openapiCmp, dstOrig.Components.RequestBodies["202"]) 77 78 c.Assert(dst.Components.SecuritySchemes["Foo"], openapiCmp, src.Components.SecuritySchemes["Foo"]) 79 c.Assert(dst.Components.SecuritySchemes["Bar"], openapiCmp, src.Components.SecuritySchemes["Bar"]) 80 c.Assert(dst.Components.SecuritySchemes["Baz"], openapiCmp, dstOrig.Components.SecuritySchemes["Baz"]) 81 82 c.Assert(dst.Components.Examples["Foo"], openapiCmp, src.Components.Examples["Foo"]) 83 c.Assert(dst.Components.Examples["Bar"], openapiCmp, src.Components.Examples["Bar"]) 84 c.Assert(dst.Components.Examples["Baz"], openapiCmp, dstOrig.Components.Examples["Baz"]) 85 }) 86 c.Run("component with missing sections", func(c *qt.C) { 87 src := mustLoadFile(c, "merge_test_src.yaml") 88 dstOrig := mustLoadFile(c, "merge_test_dst_missing_components.yaml") 89 dst := mustLoadFile(c, "merge_test_dst_missing_components.yaml") 90 vervet.Merge(dst, src, true) 91 92 c.Assert(dst.Components.Schemas["Foo"], openapiCmp, src.Components.Schemas["Foo"]) 93 c.Assert(dst.Components.Schemas["Bar"], openapiCmp, src.Components.Schemas["Bar"]) 94 c.Assert(dst.Components.Schemas["Baz"], openapiCmp, dstOrig.Components.Schemas["Baz"]) 95 96 c.Assert(dst.Components.Parameters["Foo"], openapiCmp, src.Components.Parameters["Foo"]) 97 c.Assert(dst.Components.Parameters["Bar"], openapiCmp, src.Components.Parameters["Bar"]) 98 c.Assert(dst.Components.Parameters["Baz"], openapiCmp, dstOrig.Components.Parameters["Baz"]) 99 100 c.Assert(dst.Components.Headers["Foo"], openapiCmp, src.Components.Headers["Foo"]) 101 c.Assert(dst.Components.Headers["Bar"], openapiCmp, src.Components.Headers["Bar"]) 102 c.Assert(dst.Components.Headers["Baz"], openapiCmp, dstOrig.Components.Headers["Baz"]) 103 104 c.Assert(dst.Components.RequestBodies["Foo"], openapiCmp, src.Components.RequestBodies["Foo"]) 105 c.Assert(dst.Components.RequestBodies["Bar"], openapiCmp, src.Components.RequestBodies["Bar"]) 106 c.Assert(dst.Components.RequestBodies["Baz"], openapiCmp, dstOrig.Components.RequestBodies["Baz"]) 107 108 c.Assert(dst.Components.RequestBodies["200"], openapiCmp, src.Components.RequestBodies["200"]) 109 c.Assert(dst.Components.RequestBodies["201"], openapiCmp, src.Components.RequestBodies["201"]) 110 c.Assert(dst.Components.RequestBodies["202"], openapiCmp, dstOrig.Components.RequestBodies["202"]) 111 112 c.Assert(dst.Components.SecuritySchemes["Foo"], openapiCmp, src.Components.SecuritySchemes["Foo"]) 113 c.Assert(dst.Components.SecuritySchemes["Bar"], openapiCmp, src.Components.SecuritySchemes["Bar"]) 114 c.Assert(dst.Components.SecuritySchemes["Baz"], openapiCmp, dstOrig.Components.SecuritySchemes["Baz"]) 115 116 c.Assert(dst.Components.Examples["Foo"], openapiCmp, src.Components.Examples["Foo"]) 117 c.Assert(dst.Components.Examples["Bar"], openapiCmp, src.Components.Examples["Bar"]) 118 c.Assert(dst.Components.Examples["Baz"], openapiCmp, dstOrig.Components.Examples["Baz"]) 119 }) 120 } 121 122 func TestMergeTags(t *testing.T) { 123 srcYaml := ` 124 tags: 125 - name: foo 126 description: foo resource (src) 127 - name: bar 128 description: bar resource (src) 129 ` 130 dstYaml := ` 131 tags: 132 - name: foo 133 description: foo resource (dst) 134 - name: baz 135 description: baz resource (dst) 136 ` 137 c := qt.New(t) 138 c.Run("tags without replace", func(c *qt.C) { 139 src := mustLoad(c, srcYaml) 140 dst := mustLoad(c, dstYaml) 141 vervet.Merge(dst, src, false) 142 c.Assert(dst.Tags, qt.DeepEquals, openapi3.Tags{{ 143 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 144 Name: "bar", 145 Description: "bar resource (src)", 146 }, { 147 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 148 Name: "baz", 149 Description: "baz resource (dst)", 150 }, { 151 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 152 Name: "foo", 153 Description: "foo resource (dst)", 154 }}) 155 }) 156 c.Run("tags with replace", func(c *qt.C) { 157 src := mustLoad(c, srcYaml) 158 dst := mustLoad(c, dstYaml) 159 vervet.Merge(dst, src, true) 160 c.Assert(dst.Tags, qt.DeepEquals, openapi3.Tags{{ 161 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 162 Name: "bar", 163 Description: "bar resource (src)", 164 }, { 165 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 166 Name: "baz", 167 Description: "baz resource (dst)", 168 }, { 169 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 170 Name: "foo", 171 Description: "foo resource (src)", 172 }}) 173 }) 174 } 175 176 func TestMergeTopLevel(t *testing.T) { 177 srcYaml := ` 178 info: 179 title: Src 180 version: src 181 security: 182 - Foo: [] 183 - Bar: 184 - read 185 - write 186 servers: 187 - url: https://example.com/foo 188 description: Foo (src) 189 - url: https://example.com/bar 190 description: Bar (src) 191 ` 192 dstYaml := ` 193 info: 194 title: Dst 195 version: dst 196 security: 197 - Foo: 198 - up 199 - down 200 - Baz: 201 - strange 202 - crunchy 203 servers: 204 - url: https://example.com/foo 205 description: Foo (dst) 206 - url: https://example.com/baz 207 description: Baz (dst) 208 ` 209 c := qt.New(t) 210 c.Run("servers without replace", func(c *qt.C) { 211 src := mustLoad(c, srcYaml) 212 dst := mustLoad(c, dstYaml) 213 vervet.Merge(dst, src, false) 214 c.Assert(dst.Info, qt.DeepEquals, &openapi3.Info{ 215 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 216 Title: "Dst", 217 Version: "dst", 218 }) 219 c.Assert(dst.Security, qt.DeepEquals, openapi3.SecurityRequirements{{ 220 "Foo": []string{"up", "down"}, 221 }, { 222 "Baz": []string{"strange", "crunchy"}, 223 }}) 224 c.Assert(dst.Servers, qt.DeepEquals, openapi3.Servers{{ 225 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 226 URL: "https://example.com/foo", 227 Description: "Foo (dst)", 228 }, { 229 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 230 URL: "https://example.com/baz", 231 Description: "Baz (dst)", 232 }}) 233 }) 234 c.Run("servers with replace", func(c *qt.C) { 235 src := mustLoad(c, srcYaml) 236 dst := mustLoad(c, dstYaml) 237 vervet.Merge(dst, src, true) 238 c.Assert(dst.Info, qt.DeepEquals, &openapi3.Info{ 239 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 240 Title: "Src", 241 Version: "src", 242 }) 243 c.Assert(dst.Security, qt.DeepEquals, openapi3.SecurityRequirements{{ 244 "Foo": []string{}, 245 }, { 246 "Bar": []string{"read", "write"}, 247 }}) 248 c.Assert(dst.Servers, qt.DeepEquals, openapi3.Servers{{ 249 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 250 URL: "https://example.com/foo", 251 Description: "Foo (src)", 252 }, { 253 ExtensionProps: openapi3.ExtensionProps{Extensions: map[string]interface{}{}}, 254 URL: "https://example.com/bar", 255 Description: "Bar (src)", 256 }}) 257 }) 258 } 259 260 func TestMergeIntoEmpty(t *testing.T) { 261 c := qt.New(t) 262 srcYaml := ` 263 info: 264 title: Src 265 version: src 266 paths: 267 /foo: 268 get: 269 description: get a foo 270 responses: 271 200: 272 contents: 273 application/json: 274 schema: 275 type: object 276 ` 277 src := mustLoad(c, srcYaml) 278 dst := &openapi3.T{} 279 vervet.Merge(dst, src, false) 280 c.Assert(dst.Paths, qt.HasLen, 1) 281 } 282 283 func mustLoadFile(c *qt.C, path string) *openapi3.T { 284 doc, err := vervet.NewDocumentFile(testdata.Path(path)) 285 c.Assert(err, qt.IsNil) 286 return doc.T 287 } 288 289 func mustLoad(c *qt.C, s string) *openapi3.T { 290 doc, err := openapi3.NewLoader().LoadFromData([]byte(s)) 291 c.Assert(err, qt.IsNil) 292 return doc 293 }