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  }