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