k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/aggregator/aggregator_test.go (about)

     1  /*
     2  Copyright 2017 The Kubernetes Authors.
     3  
     4  Licensed under the Apache License, Version 2.0 (the "License");
     5  you may not use this file except in compliance with the License.
     6  You may obtain a copy of the License at
     7  
     8      http://www.apache.org/licenses/LICENSE-2.0
     9  
    10  Unless required by applicable law or agreed to in writing, software
    11  distributed under the License is distributed on an "AS IS" BASIS,
    12  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13  See the License for the specific language governing permissions and
    14  limitations under the License.
    15  */
    16  
    17  package aggregator
    18  
    19  import (
    20  	"encoding/json"
    21  	"fmt"
    22  	"os"
    23  	"path/filepath"
    24  	"reflect"
    25  	"testing"
    26  
    27  	"github.com/stretchr/testify/assert"
    28  	"github.com/stretchr/testify/require"
    29  
    30  	"k8s.io/kube-openapi/pkg/handler"
    31  	"k8s.io/kube-openapi/pkg/validation/spec"
    32  	"sigs.k8s.io/yaml"
    33  )
    34  
    35  type DebugSpec struct {
    36  	*spec.Swagger
    37  }
    38  
    39  func (d DebugSpec) String() string {
    40  	bytes, err := d.Swagger.MarshalJSON()
    41  	if err != nil {
    42  		return fmt.Sprintf("DebugSpec.String failed: %s", err)
    43  	}
    44  	return string(bytes)
    45  }
    46  func TestFilterSpecs(t *testing.T) {
    47  	var spec1, spec1_filtered *spec.Swagger
    48  	yaml.Unmarshal([]byte(`
    49  swagger: "2.0"
    50  paths:
    51    /test:
    52      post:
    53        tags:
    54        - "test"
    55        summary: "Test API"
    56        operationId: "addTest"
    57        parameters:
    58        - in: "body"
    59          name: "body"
    60          description: "test object"
    61          required: true
    62          schema:
    63            $ref: "#/definitions/Test"
    64        responses:
    65          405:
    66            description: "Invalid input"
    67            $ref: "#/definitions/InvalidInput"
    68    /othertest:
    69      post:
    70        tags:
    71        - "test2"
    72        summary: "Test2 API"
    73        operationId: "addTest2"
    74        consumes:
    75        - "application/json"
    76        produces:
    77        - "application/xml"
    78        parameters:
    79        - in: "body"
    80          name: "body"
    81          description: "test2 object"
    82          required: true
    83          schema:
    84            $ref: "#/definitions/Test2"
    85  definitions:
    86    Test:
    87      type: "object"
    88      properties:
    89        id:
    90          type: "integer"
    91          format: "int64"
    92        status:
    93          type: "string"
    94          description: "Status"
    95    InvalidInput:
    96      type: "string"
    97      format: "string"
    98    Test2:
    99      type: "object"
   100      properties:
   101        other:
   102          $ref: "#/definitions/Other"
   103    Other:
   104      type: "string"
   105  `), &spec1)
   106  
   107  	yaml.Unmarshal([]byte(`
   108  swagger: "2.0"
   109  paths:
   110    /test:
   111      post:
   112        tags:
   113        - "test"
   114        summary: "Test API"
   115        operationId: "addTest"
   116        parameters:
   117        - in: "body"
   118          name: "body"
   119          description: "test object"
   120          required: true
   121          schema:
   122            $ref: "#/definitions/Test"
   123        responses:
   124          405:
   125            description: "Invalid input"
   126            $ref: "#/definitions/InvalidInput"
   127  definitions:
   128    Test:
   129      type: "object"
   130      properties:
   131        id:
   132          type: "integer"
   133          format: "int64"
   134        status:
   135          type: "string"
   136          description: "Status"
   137    InvalidInput:
   138      type: "string"
   139      format: "string"
   140  `), &spec1_filtered)
   141  
   142  	ast := assert.New(t)
   143  	orig_spec1, _ := cloneSpec(spec1)
   144  	new_spec1 := FilterSpecByPathsWithoutSideEffects(spec1, []string{"/test"})
   145  	ast.Equal(DebugSpec{spec1_filtered}, DebugSpec{new_spec1})
   146  	ast.Equal(DebugSpec{orig_spec1}, DebugSpec{spec1}, "unexpected mutation of input")
   147  }
   148  
   149  func TestFilterSpecsWithUnusedDefinitions(t *testing.T) {
   150  	var spec1, spec1Filtered *spec.Swagger
   151  	yaml.Unmarshal([]byte(`
   152  swagger: "2.0"
   153  paths:
   154    /test:
   155      post:
   156        tags:
   157        - "test"
   158        summary: "Test API"
   159        operationId: "addTest"
   160        parameters:
   161        - in: "body"
   162          name: "body"
   163          description: "test object"
   164          required: true
   165          schema:
   166            $ref: "#/definitions/Test"
   167        responses:
   168          405:
   169            description: "Invalid input"
   170            $ref: "#/definitions/InvalidInput"
   171    /othertest:
   172      post:
   173        tags:
   174        - "test2"
   175        summary: "Test2 API"
   176        operationId: "addTest2"
   177        consumes:
   178        - "application/json"
   179        produces:
   180        - "application/xml"
   181        parameters:
   182        - in: "body"
   183          name: "body"
   184          description: "test2 object"
   185          required: true
   186          schema:
   187            $ref: "#/definitions/Test2"
   188  definitions:
   189    Test:
   190      type: "object"
   191      properties:
   192        id:
   193          type: "integer"
   194          format: "int64"
   195        status:
   196          type: "string"
   197          description: "Status"
   198    InvalidInput:
   199      type: "string"
   200      format: "string"
   201    Test2:
   202      type: "object"
   203      properties:
   204        other:
   205          $ref: "#/definitions/Other"
   206    Other:
   207      type: "string"
   208    Unused:
   209      type: "object"
   210  `), &spec1)
   211  
   212  	yaml.Unmarshal([]byte(`
   213  swagger: "2.0"
   214  paths:
   215    /test:
   216      post:
   217        tags:
   218        - "test"
   219        summary: "Test API"
   220        operationId: "addTest"
   221        parameters:
   222        - in: "body"
   223          name: "body"
   224          description: "test object"
   225          required: true
   226          schema:
   227            $ref: "#/definitions/Test"
   228        responses:
   229          405:
   230            description: "Invalid input"
   231            $ref: "#/definitions/InvalidInput"
   232  definitions:
   233    Test:
   234      type: "object"
   235      properties:
   236        id:
   237          type: "integer"
   238          format: "int64"
   239        status:
   240          type: "string"
   241          description: "Status"
   242    InvalidInput:
   243      type: "string"
   244      format: "string"
   245    Unused:
   246      type: "object"
   247  `), &spec1Filtered)
   248  
   249  	ast := assert.New(t)
   250  	orig_spec1, _ := cloneSpec(spec1)
   251  	new_spec1 := FilterSpecByPathsWithoutSideEffects(spec1, []string{"/test"})
   252  	ast.Equal(DebugSpec{spec1Filtered}, DebugSpec{new_spec1})
   253  	ast.Equal(DebugSpec{orig_spec1}, DebugSpec{spec1}, "unexpected mutation of input")
   254  }
   255  
   256  func TestMergeSpecsSimple(t *testing.T) {
   257  	var spec1, spec2, expected *spec.Swagger
   258  	require.NoError(t, yaml.Unmarshal([]byte(`
   259  swagger: "2.0"
   260  paths:
   261    /test:
   262      post:
   263        tags:
   264        - "test"
   265        summary: "Test API"
   266        operationId: "addTest"
   267        parameters:
   268        - in: "body"
   269          name: "body"
   270          description: "test object"
   271          required: true
   272          schema:
   273            $ref: "#/definitions/Test"
   274        - $ref: "#/parameters/a"
   275        responses:
   276          405:
   277            description: "Invalid input"
   278            $ref: "#/definitions/InvalidInput"
   279  definitions:
   280    Test:
   281      type: "object"
   282      properties:
   283        id:
   284          type: "integer"
   285          format: "int64"
   286        status:
   287          type: "string"
   288          description: "Status"
   289    InvalidInput:
   290      type: "string"
   291      format: "string"
   292  parameters:
   293    a:
   294      in: query
   295      name: a
   296      schema:
   297         $ref: "#/definitions/Test"
   298  `), &spec1))
   299  
   300  	require.NoError(t, yaml.Unmarshal([]byte(`
   301  swagger: "2.0"
   302  paths:
   303    /othertest:
   304      post:
   305        tags:
   306        - "test2"
   307        summary: "Test2 API"
   308        operationId: "addTest2"
   309        consumes:
   310        - "application/json"
   311        produces:
   312        - "application/xml"
   313        parameters:
   314        - in: "body"
   315          name: "body"
   316          description: "test2 object"
   317          required: true
   318          schema:
   319            $ref: "#/definitions/Test2"
   320        - $ref: "#/parameters/b"
   321  definitions:
   322    Test2:
   323      type: "object"
   324      properties:
   325        other:
   326          $ref: "#/definitions/Other"
   327    Other:
   328      type: "string"
   329  parameters:
   330    b:
   331      in: query
   332      name: b
   333      schema:
   334        $ref: "#/definitions/Test2"
   335  `), &spec2))
   336  
   337  	require.NoError(t, yaml.Unmarshal([]byte(`
   338  swagger: "2.0"
   339  paths:
   340    /test:
   341      post:
   342        tags:
   343        - "test"
   344        summary: "Test API"
   345        operationId: "addTest"
   346        parameters:
   347        - in: "body"
   348          name: "body"
   349          description: "test object"
   350          required: true
   351          schema:
   352            $ref: "#/definitions/Test"
   353        - $ref: "#/parameters/a"
   354        responses:
   355          405:
   356            description: "Invalid input"
   357            $ref: "#/definitions/InvalidInput"
   358    /othertest:
   359      post:
   360        tags:
   361        - "test2"
   362        summary: "Test2 API"
   363        operationId: "addTest2"
   364        consumes:
   365        - "application/json"
   366        produces:
   367        - "application/xml"
   368        parameters:
   369        - in: "body"
   370          name: "body"
   371          description: "test2 object"
   372          required: true
   373          schema:
   374            $ref: "#/definitions/Test2"
   375        - $ref: "#/parameters/b"
   376  definitions:
   377    Test:
   378      type: "object"
   379      properties:
   380        id:
   381          type: "integer"
   382          format: "int64"
   383        status:
   384          type: "string"
   385          description: "Status"
   386    InvalidInput:
   387      type: "string"
   388      format: "string"
   389    Test2:
   390      type: "object"
   391      properties:
   392        other:
   393          $ref: "#/definitions/Other"
   394    Other:
   395      type: "string"
   396  parameters:
   397    a:
   398      in: query
   399      name: a
   400      schema:
   401        $ref: "#/definitions/Test"
   402    b:
   403      in: query
   404      name: b
   405      schema:
   406        $ref: "#/definitions/Test2"
   407  `), &expected))
   408  
   409  	ast := assert.New(t)
   410  	orig_spec2, _ := cloneSpec(spec2)
   411  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
   412  		return
   413  	}
   414  	ast.Equal(DebugSpec{expected}.String(), DebugSpec{spec1}.String())
   415  	ast.Equal(DebugSpec{orig_spec2}.String(), DebugSpec{spec2}.String(), "unexpected mutation of input")
   416  }
   417  
   418  func TestMergeSpecsEmptyDefinitions(t *testing.T) {
   419  	var spec1, spec2, expected *spec.Swagger
   420  	require.NoError(t, yaml.Unmarshal([]byte(`
   421  swagger: "2.0"
   422  paths:
   423    /test:
   424      post:
   425        tags:
   426        - "test"
   427        summary: "Test API"
   428        operationId: "addTest"
   429        parameters:
   430        - in: "body"
   431          name: "body"
   432          description: "test object"
   433          required: true
   434        responses:
   435          405:
   436            description: "Invalid input"
   437  `), &spec1))
   438  
   439  	require.NoError(t, yaml.Unmarshal([]byte(`
   440  swagger: "2.0"
   441  paths:
   442    /othertest:
   443      post:
   444        tags:
   445        - "test2"
   446        summary: "Test2 API"
   447        operationId: "addTest2"
   448        consumes:
   449        - "application/json"
   450        produces:
   451        - "application/xml"
   452        parameters:
   453        - in: "body"
   454          name: "body"
   455          description: "test2 object"
   456          required: true
   457          schema:
   458            $ref: "#/definitions/Test2"
   459  definitions:
   460    Test2:
   461      type: "object"
   462      properties:
   463        other:
   464          $ref: "#/definitions/Other"
   465    Other:
   466      type: "string"
   467  `), &spec2))
   468  
   469  	require.NoError(t, yaml.Unmarshal([]byte(`
   470  swagger: "2.0"
   471  paths:
   472    /test:
   473      post:
   474        tags:
   475        - "test"
   476        summary: "Test API"
   477        operationId: "addTest"
   478        parameters:
   479        - in: "body"
   480          name: "body"
   481          description: "test object"
   482          required: true
   483        responses:
   484          405:
   485            description: "Invalid input"
   486    /othertest:
   487      post:
   488        tags:
   489        - "test2"
   490        summary: "Test2 API"
   491        operationId: "addTest2"
   492        consumes:
   493        - "application/json"
   494        produces:
   495        - "application/xml"
   496        parameters:
   497        - in: "body"
   498          name: "body"
   499          description: "test2 object"
   500          required: true
   501          schema:
   502            $ref: "#/definitions/Test2"
   503  definitions:
   504    Test2:
   505      type: "object"
   506      properties:
   507        other:
   508          $ref: "#/definitions/Other"
   509    Other:
   510      type: "string"
   511  `), &expected))
   512  
   513  	ast := assert.New(t)
   514  	orig_spec2, _ := cloneSpec(spec2)
   515  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
   516  		return
   517  	}
   518  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
   519  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
   520  }
   521  
   522  func TestMergeSpecsEmptyPaths(t *testing.T) {
   523  	var spec1, spec2, expected *spec.Swagger
   524  	yaml.Unmarshal([]byte(`
   525  swagger: "2.0"
   526  definitions:
   527    Test:
   528      type: "object"
   529      properties:
   530        id:
   531          type: "integer"
   532          format: "int64"
   533        status:
   534          type: "string"
   535          description: "Status"
   536    InvalidInput:
   537      type: "string"
   538      format: "string"
   539  `), &spec1)
   540  
   541  	yaml.Unmarshal([]byte(`
   542  swagger: "2.0"
   543  paths:
   544    /othertest:
   545      post:
   546        tags:
   547        - "test2"
   548        summary: "Test2 API"
   549        operationId: "addTest2"
   550        consumes:
   551        - "application/json"
   552        produces:
   553        - "application/xml"
   554        parameters:
   555        - in: "body"
   556          name: "body"
   557          description: "test2 object"
   558          required: true
   559          schema:
   560            $ref: "#/definitions/Test2"
   561  definitions:
   562    Test2:
   563      type: "object"
   564      properties:
   565        other:
   566          $ref: "#/definitions/Other"
   567    Other:
   568      type: "string"
   569  `), &spec2)
   570  
   571  	yaml.Unmarshal([]byte(`
   572  swagger: "2.0"
   573  paths:
   574    /othertest:
   575      post:
   576        tags:
   577        - "test2"
   578        summary: "Test2 API"
   579        operationId: "addTest2"
   580        consumes:
   581        - "application/json"
   582        produces:
   583        - "application/xml"
   584        parameters:
   585        - in: "body"
   586          name: "body"
   587          description: "test2 object"
   588          required: true
   589          schema:
   590            $ref: "#/definitions/Test2"
   591  definitions:
   592    Test:
   593      type: "object"
   594      properties:
   595        id:
   596          type: "integer"
   597          format: "int64"
   598        status:
   599          type: "string"
   600          description: "Status"
   601    InvalidInput:
   602      type: "string"
   603      format: "string"
   604    Test2:
   605      type: "object"
   606      properties:
   607        other:
   608          $ref: "#/definitions/Other"
   609    Other:
   610      type: "string"
   611  `), &expected)
   612  
   613  	ast := assert.New(t)
   614  	orig_spec2, _ := cloneSpec(spec2)
   615  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
   616  		return
   617  	}
   618  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
   619  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
   620  }
   621  
   622  func TestMergeSpecsReuseModel(t *testing.T) {
   623  	var spec1, spec2, expected *spec.Swagger
   624  	require.NoError(t, yaml.Unmarshal([]byte(`
   625  swagger: "2.0"
   626  paths:
   627    /test:
   628      post:
   629        tags:
   630        - "test"
   631        summary: "Test API"
   632        operationId: "addTest"
   633        parameters:
   634        - in: "body"
   635          name: "body"
   636          description: "test object"
   637          required: true
   638          schema:
   639            $ref: "#/definitions/Test"
   640        - $ref: "#/parameters/a"
   641        responses:
   642          405:
   643            description: "Invalid input"
   644            $ref: "#/definitions/InvalidInput"
   645  definitions:
   646    Test:
   647      type: "object"
   648      properties:
   649        id:
   650          type: "integer"
   651          format: "int64"
   652        status:
   653          type: "string"
   654          description: "Status"
   655    InvalidInput:
   656      type: "string"
   657      format: "string"
   658  parameters:
   659    a:
   660      in: query
   661      name: a
   662      schema:
   663         $ref: "#/definitions/Test"
   664  `), &spec1))
   665  
   666  	require.NoError(t, yaml.Unmarshal([]byte(`
   667  swagger: "2.0"
   668  paths:
   669    /othertest:
   670      post:
   671        tags:
   672        - "test2"
   673        summary: "Test2 API"
   674        operationId: "addTest2"
   675        consumes:
   676        - "application/json"
   677        produces:
   678        - "application/xml"
   679        parameters:
   680        - in: "body"
   681          name: "body"
   682          description: "test2 object"
   683          required: true
   684          schema:
   685            $ref: "#/definitions/Test"
   686        - $ref: "#/parameters/a"
   687  definitions:
   688    Test:
   689      type: "object"
   690      properties:
   691        id:
   692          type: "integer"
   693          format: "int64"
   694        status:
   695          type: "string"
   696          description: "Status"
   697    InvalidInput:
   698      type: "string"
   699      format: "string"
   700  parameters:
   701    a:
   702      in: query
   703      name: a
   704      schema:
   705         $ref: "#/definitions/Test"
   706  `), &spec2))
   707  
   708  	require.NoError(t, yaml.Unmarshal([]byte(`
   709  swagger: "2.0"
   710  paths:
   711    /test:
   712      post:
   713        tags:
   714        - "test"
   715        summary: "Test API"
   716        operationId: "addTest"
   717        parameters:
   718        - in: "body"
   719          name: "body"
   720          description: "test object"
   721          required: true
   722          schema:
   723            $ref: "#/definitions/Test"
   724        - $ref: "#/parameters/a"
   725        responses:
   726          405:
   727            description: "Invalid input"
   728            $ref: "#/definitions/InvalidInput"
   729    /othertest:
   730      post:
   731        tags:
   732        - "test2"
   733        summary: "Test2 API"
   734        operationId: "addTest2"
   735        consumes:
   736        - "application/json"
   737        produces:
   738        - "application/xml"
   739        parameters:
   740        - in: "body"
   741          name: "body"
   742          description: "test2 object"
   743          required: true
   744          schema:
   745            $ref: "#/definitions/Test"
   746        - $ref: "#/parameters/a"
   747  definitions:
   748    Test:
   749      type: "object"
   750      properties:
   751        id:
   752          type: "integer"
   753          format: "int64"
   754        status:
   755          type: "string"
   756          description: "Status"
   757    InvalidInput:
   758      type: "string"
   759      format: "string"
   760  parameters:
   761    a:
   762      in: query
   763      name: a
   764      schema:
   765         $ref: "#/definitions/Test"
   766  `), &expected))
   767  
   768  	ast := assert.New(t)
   769  	orig_spec2, _ := cloneSpec(spec2)
   770  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
   771  		return
   772  	}
   773  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
   774  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
   775  }
   776  
   777  func TestMergeSpecsRenameModel(t *testing.T) {
   778  	var spec1, spec2, expected *spec.Swagger
   779  	require.NoError(t, yaml.Unmarshal([]byte(`
   780  swagger: "2.0"
   781  paths:
   782    /test:
   783      post:
   784        tags:
   785        - "test"
   786        summary: "Test API"
   787        operationId: "addTest"
   788        parameters:
   789        - in: "body"
   790          name: "body"
   791          description: "test object"
   792          required: true
   793          schema:
   794            $ref: "#/definitions/Test"
   795        - $ref: "#/parameters/a"
   796        responses:
   797          405:
   798            description: "Invalid input"
   799            $ref: "#/definitions/InvalidInput"
   800  definitions:
   801    Test:
   802      type: "object"
   803      properties:
   804        id:
   805          type: "integer"
   806          format: "int64"
   807        status:
   808          type: "string"
   809          description: "Status"
   810    InvalidInput:
   811      type: "string"
   812      format: "string"
   813  parameters:
   814    a:
   815      in: query
   816      name: a
   817      schema:
   818         $ref: "#/definitions/Test"
   819  `), &spec1))
   820  
   821  	require.NoError(t, yaml.Unmarshal([]byte(`
   822  swagger: "2.0"
   823  paths:
   824    /othertest:
   825      post:
   826        tags:
   827        - "test2"
   828        summary: "Test2 API"
   829        operationId: "addTest2"
   830        consumes:
   831        - "application/json"
   832        produces:
   833        - "application/xml"
   834        parameters:
   835        - in: "body"
   836          name: "body"
   837          description: "test2 object"
   838          required: true
   839          schema:
   840            $ref: "#/definitions/Test"
   841        - $ref: "#/parameters/a"
   842  definitions:
   843    Test:
   844      description: "This Test has a description"
   845      type: "object"
   846      properties:
   847        id:
   848          type: "integer"
   849          format: "int64"
   850    InvalidInput:
   851      type: "string"
   852      format: "string"
   853  parameters:
   854    a:
   855      in: query
   856      name: a
   857      schema:
   858         $ref: "#/definitions/Test"
   859  `), &spec2))
   860  
   861  	require.NoError(t, yaml.Unmarshal([]byte(`
   862  swagger: "2.0"
   863  paths:
   864    /test:
   865      post:
   866        tags:
   867        - "test"
   868        summary: "Test API"
   869        operationId: "addTest"
   870        parameters:
   871        - in: "body"
   872          name: "body"
   873          description: "test object"
   874          required: true
   875          schema:
   876            $ref: "#/definitions/Test"
   877        - $ref: "#/parameters/a"
   878        responses:
   879          405:
   880            description: "Invalid input"
   881            $ref: "#/definitions/InvalidInput"
   882    /othertest:
   883      post:
   884        tags:
   885        - "test2"
   886        summary: "Test2 API"
   887        operationId: "addTest2"
   888        consumes:
   889        - "application/json"
   890        produces:
   891        - "application/xml"
   892        parameters:
   893        - in: "body"
   894          name: "body"
   895          description: "test2 object"
   896          required: true
   897          schema:
   898            $ref: "#/definitions/Test_v2"
   899        - $ref: "#/parameters/a_v2"
   900  definitions:
   901    Test:
   902      type: "object"
   903      properties:
   904        id:
   905          type: "integer"
   906          format: "int64"
   907        status:
   908          type: "string"
   909          description: "Status"
   910    Test_v2:
   911      description: "This Test has a description"
   912      type: "object"
   913      properties:
   914        id:
   915          type: "integer"
   916          format: "int64"
   917    InvalidInput:
   918      type: "string"
   919      format: "string"
   920  parameters:
   921    a:
   922      in: query
   923      name: a
   924      schema:
   925         $ref: "#/definitions/Test"
   926    a_v2:
   927      in: query
   928      name: a
   929      schema:
   930         $ref: "#/definitions/Test_v2"
   931  `), &expected))
   932  
   933  	ast := assert.New(t)
   934  	orig_spec2, _ := cloneSpec(spec2)
   935  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
   936  		return
   937  	}
   938  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1}, DebugSpec{spec1}.String())
   939  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
   940  }
   941  
   942  func TestMergeSpecsRenameModelWithExistingV2InDestination(t *testing.T) {
   943  	var spec1, spec2, expected *spec.Swagger
   944  	require.NoError(t, yaml.Unmarshal([]byte(`
   945  swagger: "2.0"
   946  paths:
   947    /test:
   948      post:
   949        parameters:
   950        - name: "body"
   951          schema:
   952            $ref: "#/definitions/Test"
   953        - $ref: "#/parameters/a"
   954    /testv2:
   955      post:
   956        parameters:
   957        - name: "body"
   958          schema:
   959            $ref: "#/definitions/Test_v2"
   960        - $ref: "#/parameters/a_v2"
   961  definitions:
   962    Test:
   963      type: "object"
   964    Test_v2:
   965      description: "This is an existing Test_v2 in destination schema"
   966      type: "object"
   967  parameters:
   968    a:
   969      in: query
   970      name: a
   971      schema:
   972         $ref: "#/definitions/Test"
   973    a_v2:
   974      in: query
   975      name: a
   976      schema:
   977         $ref: "#/definitions/Test_v2"
   978  `), &spec1))
   979  
   980  	require.NoError(t, yaml.Unmarshal([]byte(`
   981  swagger: "2.0"
   982  paths:
   983    /othertest:
   984      post:
   985        parameters:
   986        - name: "body"
   987          schema:
   988            $ref: "#/definitions/Test"
   989        - $ref: "#/parameters/a"
   990  definitions:
   991    Test:
   992      description: "This Test has a description"
   993      type: "object"
   994  parameters:
   995    a:
   996      in: query
   997      name: a
   998      schema:
   999         $ref: "#/definitions/Test"
  1000  `), &spec2))
  1001  
  1002  	require.NoError(t, yaml.Unmarshal([]byte(`
  1003  swagger: "2.0"
  1004  paths:
  1005    /test:
  1006      post:
  1007        parameters:
  1008        - name: "body"
  1009          schema:
  1010            $ref: "#/definitions/Test"
  1011        - $ref: "#/parameters/a"
  1012    /testv2:
  1013      post:
  1014        parameters:
  1015        - name: "body"
  1016          schema:
  1017            $ref: "#/definitions/Test_v2"
  1018        - $ref: "#/parameters/a_v2"
  1019    /othertest:
  1020      post:
  1021        parameters:
  1022        - name: "body"
  1023          schema:
  1024            $ref: "#/definitions/Test_v3"
  1025        - $ref: "#/parameters/a_v3"
  1026  definitions:
  1027    Test:
  1028      type: "object"
  1029    Test_v2:
  1030      description: "This is an existing Test_v2 in destination schema"
  1031      type: "object"
  1032    Test_v3:
  1033      description: "This Test has a description"
  1034      type: "object"
  1035  parameters:
  1036    a:
  1037      in: query
  1038      name: a
  1039      schema:
  1040         $ref: "#/definitions/Test"
  1041    a_v2:
  1042      in: query
  1043      name: a
  1044      schema:
  1045         $ref: "#/definitions/Test_v2"
  1046    a_v3:
  1047      in: query
  1048      name: a
  1049      schema:
  1050         $ref: "#/definitions/Test_v3"
  1051  `), &expected))
  1052  
  1053  	ast := assert.New(t)
  1054  	orig_spec2, _ := cloneSpec(spec2)
  1055  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  1056  		return
  1057  	}
  1058  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  1059  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
  1060  }
  1061  
  1062  func TestMergeSpecsMultipleRenamesOfModelsAndLateConflict(t *testing.T) {
  1063  	var spec1, spec2, expected *spec.Swagger
  1064  	require.NoError(t, yaml.Unmarshal([]byte(`
  1065  swagger: "2.0"
  1066  paths:
  1067    /test:
  1068      post:
  1069        parameters:
  1070        - name: "body"
  1071          schema:
  1072            $ref: "#/definitions/Test"
  1073        - $ref: "#/parameters/a"
  1074    /test3:
  1075      post:
  1076        parameters:
  1077        - name: "body"
  1078          schema:
  1079            $ref: "#/definitions/Test_v3"
  1080        - $ref: "#/parameters/a_v3"
  1081  definitions:
  1082    Test:
  1083      description: "I used to be Test in destination"
  1084      type: "object"
  1085    Test_v3:
  1086      description: "I used to be Test_v3 in destination"
  1087      type: "object"
  1088  parameters:
  1089    a:
  1090      in: query
  1091      name: a
  1092      schema:
  1093         $ref: "#/definitions/Test"
  1094    a_v3:
  1095      in: query
  1096      name: a
  1097      schema:
  1098         $ref: "#/definitions/Test_v3"
  1099  `), &spec1))
  1100  
  1101  	require.NoError(t, yaml.Unmarshal([]byte(`
  1102  swagger: "2.0"
  1103  paths:
  1104    /othertest:
  1105      post:
  1106        parameters:
  1107        - name: "body"
  1108          schema:
  1109            $ref: "#/definitions/Test"
  1110        - $ref: "#/parameters/a"
  1111    /othertest2:
  1112      post:
  1113        parameters:
  1114        - name: "body"
  1115          schema:
  1116            $ref: "#/definitions/Test_v2"
  1117        - $ref: "#/parameters/a_v2"
  1118  definitions:
  1119    Test:
  1120      description: "I used to be Test in source"
  1121      type: "object"
  1122    Test_v2:
  1123      description: "I used to be Test_v2 in source"
  1124      type: "object"
  1125  parameters:
  1126    a:
  1127      in: query
  1128      name: a
  1129      schema:
  1130         $ref: "#/definitions/Test"
  1131    a_v2:
  1132      in: query
  1133      name: a
  1134      schema:
  1135         $ref: "#/definitions/Test_v2"
  1136  `), &spec2))
  1137  
  1138  	require.NoError(t, yaml.Unmarshal([]byte(`
  1139  swagger: "2.0"
  1140  paths:
  1141    /test:
  1142      post:
  1143        parameters:
  1144        - name: "body"
  1145          schema:
  1146            $ref: "#/definitions/Test"
  1147        - $ref: "#/parameters/a"
  1148    /test3:
  1149      post:
  1150        parameters:
  1151        - name: "body"
  1152          schema:
  1153            $ref: "#/definitions/Test_v3"
  1154        - $ref: "#/parameters/a_v3"
  1155    /othertest2:
  1156      post:
  1157        parameters:
  1158        - name: "body"
  1159          schema:
  1160            $ref: "#/definitions/Test_v2"
  1161        - $ref: "#/parameters/a_v2"
  1162    /othertest:
  1163      post:
  1164        parameters:
  1165        - name: "body"
  1166          schema:
  1167            $ref: "#/definitions/Test_v4"
  1168        - $ref: "#/parameters/a_v4"
  1169  definitions:
  1170    Test:
  1171      description: "I used to be Test in destination"
  1172      type: "object"
  1173    Test_v2:
  1174      description: "I used to be Test_v2 in source"
  1175      type: "object"
  1176    Test_v3:
  1177      description: "I used to be Test_v3 in destination"
  1178      type: "object"
  1179    Test_v4:
  1180      description: "I used to be Test in source"
  1181      type: "object"
  1182  parameters:
  1183    a:
  1184      in: query
  1185      name: a
  1186      schema:
  1187         $ref: "#/definitions/Test"
  1188    a_v2:
  1189      in: query
  1190      name: a
  1191      schema:
  1192         $ref: "#/definitions/Test_v2"
  1193    a_v3:
  1194      in: query
  1195      name: a
  1196      schema:
  1197         $ref: "#/definitions/Test_v3"
  1198    a_v4:
  1199      in: query
  1200      name: a
  1201      schema:
  1202         $ref: "#/definitions/Test_v4"
  1203  `), &expected))
  1204  
  1205  	ast := assert.New(t)
  1206  	orig_spec2, _ := cloneSpec(spec2)
  1207  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  1208  		return
  1209  	}
  1210  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  1211  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
  1212  }
  1213  
  1214  func TestMergeSpecsRenameModelWithExistingV2InSource(t *testing.T) {
  1215  	var spec1, spec2, expected *spec.Swagger
  1216  	require.NoError(t, yaml.Unmarshal([]byte(`
  1217  swagger: "2.0"
  1218  paths:
  1219    /test:
  1220      post:
  1221        parameters:
  1222        - name: "body"
  1223          schema:
  1224            $ref: "#/definitions/Test"
  1225        - $ref: "#/parameters/a"
  1226  definitions:
  1227    Test:
  1228      type: "object"
  1229  parameters:
  1230    a:
  1231      in: query
  1232      name: a
  1233      schema:
  1234         $ref: "#/definitions/Test"
  1235  `), &spec1))
  1236  
  1237  	require.NoError(t, yaml.Unmarshal([]byte(`
  1238  swagger: "2.0"
  1239  paths:
  1240    /othertest:
  1241      post:
  1242        parameters:
  1243        - name: "body"
  1244          schema:
  1245            $ref: "#/definitions/Test"
  1246        - $ref: "#/parameters/a"
  1247    /testv2:
  1248      post:
  1249        parameters:
  1250        - name: "body"
  1251          schema:
  1252            $ref: "#/definitions/Test_v2"
  1253        - $ref: "#/parameters/a_v2"
  1254  definitions:
  1255    Test:
  1256      description: "This Test has a description"
  1257      type: "object"
  1258    Test_v2:
  1259      description: "This is an existing Test_v2 in source schema"
  1260      type: "object"
  1261  parameters:
  1262    a:
  1263      in: query
  1264      name: a
  1265      schema:
  1266         $ref: "#/definitions/Test"
  1267    a_v2:
  1268      in: query
  1269      name: a
  1270      schema:
  1271        $ref: "#/definitions/Test_v2"
  1272  `), &spec2))
  1273  
  1274  	require.NoError(t, yaml.Unmarshal([]byte(`
  1275  swagger: "2.0"
  1276  paths:
  1277    /test:
  1278      post:
  1279        parameters:
  1280        - name: "body"
  1281          schema:
  1282            $ref: "#/definitions/Test"
  1283        - $ref: "#/parameters/a"
  1284    /testv2:
  1285      post:
  1286        parameters:
  1287        - name: "body"
  1288          schema:
  1289            $ref: "#/definitions/Test_v2"
  1290        - $ref: "#/parameters/a_v2"
  1291    /othertest:
  1292      post:
  1293        parameters:
  1294        - name: "body"
  1295          schema:
  1296            $ref: "#/definitions/Test_v3"
  1297        - $ref: "#/parameters/a_v3"
  1298  definitions:
  1299    Test:
  1300      type: "object"
  1301    Test_v2:
  1302      description: "This is an existing Test_v2 in source schema"
  1303      type: "object"
  1304    Test_v3:
  1305      description: "This Test has a description"
  1306      type: "object"
  1307  parameters:
  1308    a:
  1309      in: query
  1310      name: a
  1311      schema:
  1312        $ref: "#/definitions/Test"
  1313    a_v2:
  1314      in: query
  1315      name: a
  1316      schema:
  1317        $ref: "#/definitions/Test_v2"
  1318    a_v3:
  1319      in: query
  1320      name: a
  1321      schema:
  1322        $ref: "#/definitions/Test_v3"
  1323  `), &expected))
  1324  
  1325  	ast := assert.New(t)
  1326  	orig_spec2, _ := cloneSpec(spec2)
  1327  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  1328  		return
  1329  	}
  1330  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  1331  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
  1332  }
  1333  
  1334  // This tests if there are three specs, where the first two use the same object definition,
  1335  // while the third one uses its own.
  1336  // We expect the merged schema to contain two versions of the object, not three
  1337  func TestTwoMergeSpecsFirstTwoSchemasHaveSameDefinition(t *testing.T) {
  1338  	var spec1, spec2, spec3, expected *spec.Swagger
  1339  	yaml.Unmarshal([]byte(`
  1340  swagger: "2.0"
  1341  paths:
  1342    /test:
  1343      post:
  1344        parameters:
  1345        - name: "body"
  1346          schema:
  1347            $ref: "#/definitions/Test"
  1348  definitions:
  1349    Test:
  1350      description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
  1351      type: "object"
  1352  `), &spec1)
  1353  
  1354  	yaml.Unmarshal([]byte(`
  1355  swagger: "2.0"
  1356  paths:
  1357    /test2:
  1358      post:
  1359        parameters:
  1360        - name: "body"
  1361          schema:
  1362            $ref: "#/definitions/Test"
  1363  definitions:
  1364    Test:
  1365      description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
  1366      type: "object"
  1367  `), &spec2)
  1368  
  1369  	yaml.Unmarshal([]byte(`
  1370  swagger: "2.0"
  1371  paths:
  1372    /test3:
  1373      post:
  1374        parameters:
  1375        - name: "body"
  1376          schema:
  1377            $ref: "#/definitions/Test"
  1378  definitions:
  1379    Test:
  1380      description: "spec3 has its own definition (the description doesn't match)"
  1381      type: "object"
  1382  `), &spec3)
  1383  
  1384  	yaml.Unmarshal([]byte(`
  1385  swagger: "2.0"
  1386  paths:
  1387    /test:
  1388      post:
  1389        parameters:
  1390        - name: "body"
  1391          schema:
  1392            $ref: "#/definitions/Test"
  1393    /test2:
  1394      post:
  1395        parameters:
  1396        - name: "body"
  1397          schema:
  1398            $ref: "#/definitions/Test"
  1399    /test3:
  1400      post:
  1401        parameters:
  1402        - name: "body"
  1403          schema:
  1404            $ref: "#/definitions/Test_v2"
  1405  definitions:
  1406    Test:
  1407      description: "spec1 and spec2 use the same object definition, while spec3 doesn't"
  1408      type: "object"
  1409    Test_v2:
  1410      description: "spec3 has its own definition (the description doesn't match)"
  1411      type: "object"
  1412  `), &expected)
  1413  
  1414  	ast := assert.New(t)
  1415  	orig_spec2, _ := cloneSpec(spec2)
  1416  	orig_spec3, _ := cloneSpec(spec3)
  1417  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  1418  		return
  1419  	}
  1420  	if !ast.NoError(MergeSpecs(spec1, spec3)) {
  1421  		return
  1422  	}
  1423  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  1424  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of spec2 input")
  1425  	ast.Equal(DebugSpec{orig_spec3}, DebugSpec{spec3}, "unexpected mutation of spec3 input")
  1426  }
  1427  
  1428  // This tests if there are three specs, where the last two use the same object definition,
  1429  // while the first one uses its own.
  1430  // We expect the merged schema to contain two versions of the object, not three
  1431  func TestTwoMergeSpecsLastTwoSchemasHaveSameDefinition(t *testing.T) {
  1432  	var spec1, spec2, spec3, expected *spec.Swagger
  1433  	yaml.Unmarshal([]byte(`
  1434  swagger: "2.0"
  1435  paths:
  1436    /test:
  1437      post:
  1438        parameters:
  1439        - name: "body"
  1440          schema:
  1441            $ref: "#/definitions/Test"
  1442  definitions:
  1443    Test:
  1444      type: "object"
  1445  `), &spec1)
  1446  
  1447  	yaml.Unmarshal([]byte(`
  1448  swagger: "2.0"
  1449  paths:
  1450    /othertest:
  1451      post:
  1452        parameters:
  1453        - name: "body"
  1454          schema:
  1455            $ref: "#/definitions/Test"
  1456  definitions:
  1457    Test:
  1458      description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
  1459      type: "object"
  1460  `), &spec2)
  1461  
  1462  	yaml.Unmarshal([]byte(`
  1463  swagger: "2.0"
  1464  paths:
  1465    /othertest2:
  1466      post:
  1467        parameters:
  1468        - name: "body"
  1469          schema:
  1470            $ref: "#/definitions/Test"
  1471  definitions:
  1472    Test:
  1473      description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
  1474      type: "object"
  1475  `), &spec3)
  1476  
  1477  	yaml.Unmarshal([]byte(`
  1478  swagger: "2.0"
  1479  paths:
  1480    /test:
  1481      post:
  1482        parameters:
  1483        - name: "body"
  1484          schema:
  1485            $ref: "#/definitions/Test"
  1486    /othertest:
  1487      post:
  1488        parameters:
  1489        - name: "body"
  1490          schema:
  1491            $ref: "#/definitions/Test_v2"
  1492    /othertest2:
  1493      post:
  1494        parameters:
  1495        - name: "body"
  1496          schema:
  1497            $ref: "#/definitions/Test_v2"
  1498  definitions:
  1499    Test:
  1500      type: "object"
  1501    Test_v2:
  1502      description: "spec2 and spec3 use the same object definition, while spec1 doesn't"
  1503      type: "object"
  1504  `), &expected)
  1505  
  1506  	ast := assert.New(t)
  1507  	orig_spec2, _ := cloneSpec(spec2)
  1508  	orig_spec3, _ := cloneSpec(spec3)
  1509  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  1510  		return
  1511  	}
  1512  	if !ast.NoError(MergeSpecs(spec1, spec3)) {
  1513  		return
  1514  	}
  1515  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  1516  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of spec2 input")
  1517  	ast.Equal(DebugSpec{orig_spec3}, DebugSpec{spec3}, "unexpected mutation of spec3 input")
  1518  
  1519  }
  1520  
  1521  func TestSafeMergeSpecsSimple(t *testing.T) {
  1522  	var fooSpec, barSpec, expected *spec.Swagger
  1523  	yaml.Unmarshal([]byte(`
  1524  swagger: "2.0"
  1525  paths:
  1526    /foo:
  1527      post:
  1528        summary: "Foo API"
  1529        operationId: "fooTest"
  1530        parameters:
  1531        - in: "body"
  1532          name: "body"
  1533          description: "foo object"
  1534          required: true
  1535          schema:
  1536            $ref: "#/definitions/Foo"
  1537        responses:
  1538          200:
  1539            description: "OK"
  1540  definitions:
  1541    Foo:
  1542      type: "object"
  1543      properties:
  1544        id:
  1545          type: "integer"
  1546          format: "int64"
  1547  `), &fooSpec)
  1548  
  1549  	yaml.Unmarshal([]byte(`
  1550  swagger: "2.0"
  1551  paths:
  1552    /bar:
  1553      post:
  1554        summary: "Bar API"
  1555        operationId: "barTest"
  1556        parameters:
  1557        - in: "body"
  1558          name: "body"
  1559          description: "bar object"
  1560          required: true
  1561          schema:
  1562            $ref: "#/definitions/Bar"
  1563        responses:
  1564          200:
  1565            description: "OK"
  1566  definitions:
  1567    Bar:
  1568      type: "object"
  1569      properties:
  1570        id:
  1571          type: "integer"
  1572          format: "int64"
  1573  `), &barSpec)
  1574  
  1575  	yaml.Unmarshal([]byte(`
  1576  swagger: "2.0"
  1577  paths:
  1578    /foo:
  1579      post:
  1580        summary: "Foo API"
  1581        operationId: "fooTest"
  1582        parameters:
  1583        - in: "body"
  1584          name: "body"
  1585          description: "foo object"
  1586          required: true
  1587          schema:
  1588            $ref: "#/definitions/Foo"
  1589        responses:
  1590          200:
  1591            description: "OK"
  1592    /bar:
  1593      post:
  1594        summary: "Bar API"
  1595        operationId: "barTest"
  1596        parameters:
  1597        - in: "body"
  1598          name: "body"
  1599          description: "bar object"
  1600          required: true
  1601          schema:
  1602            $ref: "#/definitions/Bar"
  1603        responses:
  1604          200:
  1605            description: "OK"
  1606  definitions:
  1607      Foo:
  1608        type: "object"
  1609        properties:
  1610          id:
  1611            type: "integer"
  1612            format: "int64"
  1613      Bar:
  1614        type: "object"
  1615        properties:
  1616          id:
  1617            type: "integer"
  1618            format: "int64"
  1619    `), &expected)
  1620  
  1621  	ast := assert.New(t)
  1622  	orig_barSpec, err := cloneSpec(barSpec)
  1623  	if !ast.NoError(err) {
  1624  		return
  1625  	}
  1626  	if !ast.NoError(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec)) {
  1627  		return
  1628  	}
  1629  	ast.Equal(DebugSpec{expected}, DebugSpec{fooSpec})
  1630  	ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
  1631  }
  1632  
  1633  func TestSafeMergeSpecsReuseModel(t *testing.T) {
  1634  	var fooSpec, barSpec, expected *spec.Swagger
  1635  	if err := yaml.Unmarshal([]byte(`
  1636  swagger: "2.0"
  1637  paths:
  1638    /foo:
  1639      post:
  1640        summary: "Foo API"
  1641        operationId: "fooTest"
  1642        parameters:
  1643        - in: "body"
  1644          name: "body"
  1645          description: "foo object"
  1646          required: true
  1647          schema:
  1648            $ref: "#/definitions/Foo"
  1649        responses:
  1650          200:
  1651            description: "OK"
  1652  definitions:
  1653    Foo:
  1654      type: "object"
  1655      properties:
  1656        id:
  1657          type: "integer"
  1658          format: "int64"
  1659      x-kubernetes-group-version-kind:
  1660      - group: group1
  1661        version: v1
  1662        kind: Foo
  1663      - group: group3
  1664        version: v1
  1665        kind: Foo
  1666  `), &fooSpec); err != nil {
  1667  		t.Fatal(err)
  1668  	}
  1669  
  1670  	if err := yaml.Unmarshal([]byte(`
  1671  swagger: "2.0"
  1672  paths:
  1673    /refoo:
  1674      post:
  1675        summary: "Refoo API"
  1676        operationId: "refooTest"
  1677        parameters:
  1678        - in: "body"
  1679          name: "body"
  1680          description: "foo object"
  1681          required: true
  1682          schema:
  1683            $ref: "#/definitions/Foo"
  1684        responses:
  1685          200:
  1686            description: "OK"
  1687  definitions:
  1688    Foo:
  1689      type: "object"
  1690      properties:
  1691        id:
  1692          type: "integer"
  1693          format: "int64"
  1694      x-kubernetes-group-version-kind:
  1695      - group: group2
  1696        version: v1
  1697        kind: Foo
  1698  `), &barSpec); err != nil {
  1699  		t.Fatal(err)
  1700  	}
  1701  
  1702  	if err := yaml.Unmarshal([]byte(`
  1703  swagger: "2.0"
  1704  paths:
  1705    /foo:
  1706      post:
  1707        summary: "Foo API"
  1708        operationId: "fooTest"
  1709        parameters:
  1710        - in: "body"
  1711          name: "body"
  1712          description: "foo object"
  1713          required: true
  1714          schema:
  1715            $ref: "#/definitions/Foo"
  1716        responses:
  1717          200:
  1718            description: "OK"
  1719    /refoo:
  1720      post:
  1721        summary: "Refoo API"
  1722        operationId: "refooTest"
  1723        parameters:
  1724        - in: "body"
  1725          name: "body"
  1726          description: "foo object"
  1727          required: true
  1728          schema:
  1729            $ref: "#/definitions/Foo"
  1730        responses:
  1731          200:
  1732            description: "OK"
  1733  definitions:
  1734      Foo:
  1735        type: "object"
  1736        properties:
  1737          id:
  1738            type: "integer"
  1739            format: "int64"
  1740        x-kubernetes-group-version-kind:
  1741        - group: group1
  1742          version: v1
  1743          kind: Foo
  1744        - group: group2
  1745          version: v1
  1746          kind: Foo
  1747        - group: group3
  1748          version: v1
  1749          kind: Foo
  1750    `), &expected); err != nil {
  1751  		t.Fatal(err)
  1752  	}
  1753  
  1754  	ast := assert.New(t)
  1755  	orig_barSpec, err := cloneSpec(barSpec)
  1756  	if !ast.NoError(err) {
  1757  		return
  1758  	}
  1759  	if !ast.NoError(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec)) {
  1760  		return
  1761  	}
  1762  	ast.Equal(DebugSpec{expected}, DebugSpec{fooSpec})
  1763  	ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
  1764  }
  1765  
  1766  func TestSafeMergeSpecsReuseModelFails(t *testing.T) {
  1767  	var fooSpec, barSpec, expected *spec.Swagger
  1768  	yaml.Unmarshal([]byte(`
  1769  swagger: "2.0"
  1770  paths:
  1771    /foo:
  1772      post:
  1773        summary: "Foo API"
  1774        operationId: "fooTest"
  1775        parameters:
  1776        - in: "body"
  1777          name: "body"
  1778          description: "foo object"
  1779          required: true
  1780          schema:
  1781            $ref: "#/definitions/Foo"
  1782        responses:
  1783          200:
  1784            description: "OK"
  1785  definitions:
  1786    Foo:
  1787      type: "object"
  1788      properties:
  1789        id:
  1790          type: "integer"
  1791          format: "int64"
  1792  `), &fooSpec)
  1793  
  1794  	yaml.Unmarshal([]byte(`
  1795  swagger: "2.0"
  1796  paths:
  1797    /refoo:
  1798      post:
  1799        summary: "Refoo API"
  1800        operationId: "refooTest"
  1801        parameters:
  1802        - in: "body"
  1803          name: "body"
  1804          description: "foo object"
  1805          required: true
  1806          schema:
  1807            $ref: "#/definitions/Foo"
  1808        responses:
  1809          200:
  1810            description: "OK"
  1811  definitions:
  1812    Foo:
  1813      type: "object"
  1814      properties:
  1815        id:
  1816          type: "integer"
  1817          format: "int64"
  1818        new_field:
  1819          type: "string"
  1820  `), &barSpec)
  1821  
  1822  	yaml.Unmarshal([]byte(`
  1823  swagger: "2.0"
  1824  paths:
  1825    /foo:
  1826      post:
  1827        summary: "Foo API"
  1828        operationId: "fooTest"
  1829        parameters:
  1830        - in: "body"
  1831          name: "body"
  1832          description: "foo object"
  1833          required: true
  1834          schema:
  1835            $ref: "#/definitions/Foo"
  1836        responses:
  1837          200:
  1838            description: "OK"
  1839    /refoo:
  1840      post:
  1841        summary: "Refoo API"
  1842        operationId: "refooTest"
  1843        parameters:
  1844        - in: "body"
  1845          name: "body"
  1846          description: "foo object"
  1847          required: true
  1848          schema:
  1849            $ref: "#/definitions/Foo"
  1850        responses:
  1851          200:
  1852            description: "OK"
  1853  definitions:
  1854      Foo:
  1855        type: "object"
  1856        properties:
  1857          id:
  1858            type: "integer"
  1859            format: "int64"
  1860    `), &expected)
  1861  
  1862  	ast := assert.New(t)
  1863  	ast.Error(MergeSpecsFailOnDefinitionConflict(fooSpec, barSpec))
  1864  }
  1865  
  1866  func TestMergeSpecsIgnorePathConflicts(t *testing.T) {
  1867  	var fooSpec, barSpec, expected *spec.Swagger
  1868  	yaml.Unmarshal([]byte(`
  1869  swagger: "2.0"
  1870  paths:
  1871    /foo:
  1872      post:
  1873        summary: "Foo API"
  1874        operationId: "fooTest"
  1875        parameters:
  1876        - in: "body"
  1877          name: "body"
  1878          description: "foo object"
  1879          required: true
  1880          schema:
  1881            $ref: "#/definitions/Foo"
  1882        responses:
  1883          200:
  1884            description: "OK"
  1885  definitions:
  1886    Foo:
  1887      type: "object"
  1888      properties:
  1889        id:
  1890          type: "integer"
  1891          format: "int64"
  1892  `), &fooSpec)
  1893  
  1894  	yaml.Unmarshal([]byte(`
  1895  swagger: "2.0"
  1896  paths:
  1897    /foo:
  1898      post:
  1899        summary: "Should be ignored"
  1900    /bar:
  1901      post:
  1902        summary: "Bar API"
  1903        operationId: "barTest"
  1904        parameters:
  1905        - in: "body"
  1906          name: "body"
  1907          description: "bar object"
  1908          required: true
  1909          schema:
  1910            $ref: "#/definitions/Bar"
  1911        responses:
  1912          200:
  1913            description: "OK"
  1914  definitions:
  1915    Bar:
  1916      type: "object"
  1917      properties:
  1918        id:
  1919          type: "integer"
  1920          format: "int64"
  1921  `), &barSpec)
  1922  
  1923  	yaml.Unmarshal([]byte(`
  1924  swagger: "2.0"
  1925  paths:
  1926    /foo:
  1927      post:
  1928        summary: "Foo API"
  1929        operationId: "fooTest"
  1930        parameters:
  1931        - in: "body"
  1932          name: "body"
  1933          description: "foo object"
  1934          required: true
  1935          schema:
  1936            $ref: "#/definitions/Foo"
  1937        responses:
  1938          200:
  1939            description: "OK"
  1940    /bar:
  1941      post:
  1942        summary: "Bar API"
  1943        operationId: "barTest"
  1944        parameters:
  1945        - in: "body"
  1946          name: "body"
  1947          description: "bar object"
  1948          required: true
  1949          schema:
  1950            $ref: "#/definitions/Bar"
  1951        responses:
  1952          200:
  1953            description: "OK"
  1954  definitions:
  1955      Foo:
  1956        type: "object"
  1957        properties:
  1958          id:
  1959            type: "integer"
  1960            format: "int64"
  1961      Bar:
  1962        type: "object"
  1963        properties:
  1964          id:
  1965            type: "integer"
  1966            format: "int64"
  1967    `), &expected)
  1968  
  1969  	ast := assert.New(t)
  1970  	actual, _ := cloneSpec(fooSpec)
  1971  	orig_barSpec, _ := cloneSpec(barSpec)
  1972  	if !ast.Error(MergeSpecs(actual, barSpec)) {
  1973  		return
  1974  	}
  1975  	ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
  1976  
  1977  	actual, _ = cloneSpec(fooSpec)
  1978  	if !ast.NoError(MergeSpecsIgnorePathConflictDeprecated(actual, barSpec)) {
  1979  		return
  1980  	}
  1981  	ast.Equal(DebugSpec{expected}, DebugSpec{actual})
  1982  	ast.Equal(DebugSpec{orig_barSpec}, DebugSpec{barSpec}, "unexpected mutation of input")
  1983  }
  1984  
  1985  func TestMergeSpecsIgnorePathConflictsAllConflicting(t *testing.T) {
  1986  	var fooSpec *spec.Swagger
  1987  	yaml.Unmarshal([]byte(`
  1988  swagger: "2.0"
  1989  paths:
  1990    /foo:
  1991      post:
  1992        summary: "Foo API"
  1993        operationId: "fooTest"
  1994        parameters:
  1995        - in: "body"
  1996          name: "body"
  1997          description: "foo object"
  1998          required: true
  1999          schema:
  2000            $ref: "#/definitions/Foo"
  2001        responses:
  2002          200:
  2003            description: "OK"
  2004  definitions:
  2005    Foo:
  2006      type: "object"
  2007      properties:
  2008        id:
  2009          type: "integer"
  2010          format: "int64"
  2011  `), &fooSpec)
  2012  
  2013  	ast := assert.New(t)
  2014  	foo2Spec, _ := cloneSpec(fooSpec)
  2015  	actual, _ := cloneSpec(fooSpec)
  2016  	if !ast.NoError(MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(actual, foo2Spec)) {
  2017  		return
  2018  	}
  2019  	ast.Equal(DebugSpec{fooSpec}, DebugSpec{actual})
  2020  	ast.Equal(DebugSpec{fooSpec}, DebugSpec{foo2Spec}, "unexpected mutation of input")
  2021  }
  2022  
  2023  func TestMergeSpecsIgnorePathConflictsWithKubeSpec(t *testing.T) {
  2024  	ast := assert.New(t)
  2025  
  2026  	specs, expected := loadTestData()
  2027  	sp, specs := specs[0], specs[1:]
  2028  
  2029  	origSpecs := make([]*spec.Swagger, len(specs))
  2030  	for i := range specs {
  2031  		cpy, err := cloneSpec(specs[i])
  2032  		if err != nil {
  2033  			t.Fatal(err)
  2034  		}
  2035  		ast.NoError(err)
  2036  		origSpecs[i] = cpy
  2037  	}
  2038  
  2039  	for i := range specs {
  2040  		if err := MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(sp, specs[i]); err != nil {
  2041  			t.Fatalf("merging spec %d failed: %v", i, err)
  2042  		}
  2043  	}
  2044  
  2045  	ast.Equal(DebugSpec{expected}, DebugSpec{sp})
  2046  
  2047  	for i := range specs {
  2048  		ast.Equal(DebugSpec{origSpecs[i]}, DebugSpec{specs[i]}, "unexpected mutation of specs[%d]", i)
  2049  	}
  2050  }
  2051  
  2052  func BenchmarkMergeSpecsIgnorePathConflictsWithKubeSpec(b *testing.B) {
  2053  	b.StopTimer()
  2054  	b.ReportAllocs()
  2055  	b.ResetTimer()
  2056  
  2057  	specs, _ := loadTestData()
  2058  	start, specs := specs[0], specs[1:]
  2059  
  2060  	for n := 0; n < b.N; n++ {
  2061  		sp, err := cloneSpec(start)
  2062  		if err != nil {
  2063  			b.Fatal(err)
  2064  		}
  2065  
  2066  		b.StartTimer()
  2067  		for i := range specs {
  2068  			if err := MergeSpecsIgnorePathConflictRenamingDefinitionsAndParameters(sp, specs[i]); err != nil {
  2069  				panic(err)
  2070  			}
  2071  		}
  2072  
  2073  		specBytes, _ := sp.MarshalJSON()
  2074  		handler.ToProtoBinary(specBytes)
  2075  
  2076  		b.StopTimer()
  2077  	}
  2078  }
  2079  
  2080  func TestMergeSpecReplacesAllPossibleRefs(t *testing.T) {
  2081  	var spec1, spec2, expected *spec.Swagger
  2082  	yaml.Unmarshal([]byte(`
  2083  swagger: "2.0"
  2084  paths:
  2085    /test:
  2086      post:
  2087        parameters:
  2088        - name: "body"
  2089          schema:
  2090            $ref: "#/definitions/Test"
  2091  definitions:
  2092    Test:
  2093      type: "object"
  2094      properties:
  2095        foo:
  2096          $ref: "#/definitions/TestProperty"
  2097    TestProperty:
  2098      type: "object"
  2099  `), &spec1)
  2100  
  2101  	yaml.Unmarshal([]byte(`
  2102  swagger: "2.0"
  2103  paths:
  2104    /test2:
  2105      post:
  2106        parameters:
  2107        - name: "test2"
  2108          schema:
  2109            $ref: "#/definitions/Test2"
  2110        - name: "test3"
  2111          schema:
  2112            $ref: "#/definitions/Test3"
  2113        - name: "test4"
  2114          schema:
  2115            $ref: "#/definitions/Test4"
  2116        - name: "test5"
  2117          schema:
  2118            $ref: "#/definitions/Test5"
  2119  definitions:
  2120    Test2:
  2121      $ref: "#/definitions/TestProperty"
  2122    Test3:
  2123      type: "object"
  2124      properties:
  2125        withRef:
  2126          $ref: "#/definitions/TestProperty"
  2127        withAllOf:
  2128          type: "object"
  2129          allOf:
  2130          - $ref: "#/definitions/TestProperty"
  2131          - type: object
  2132            properties:
  2133              test:
  2134                $ref: "#/definitions/TestProperty"
  2135        withAnyOf:
  2136          type: "object"
  2137          anyOf:
  2138          - $ref: "#/definitions/TestProperty"
  2139          - type: object
  2140            properties:
  2141              test:
  2142                $ref: "#/definitions/TestProperty"
  2143        withOneOf:
  2144          type: "object"
  2145          oneOf:
  2146          - $ref: "#/definitions/TestProperty"
  2147          - type: object
  2148            properties:
  2149              test:
  2150                $ref: "#/definitions/TestProperty"
  2151        withNot:
  2152          type: "object"
  2153          not:
  2154            $ref: "#/definitions/TestProperty"
  2155      patternProperties:
  2156        "prefix.*":
  2157          $ref: "#/definitions/TestProperty"
  2158      additionalProperties:
  2159        $ref: "#/definitions/TestProperty"
  2160      definitions:
  2161        SomeDefinition:
  2162          $ref: "#/definitions/TestProperty"
  2163    Test4:
  2164      type: "array"
  2165      items:
  2166        $ref: "#/definitions/TestProperty"
  2167      additionalItems:
  2168        $ref: "#/definitions/TestProperty"
  2169    Test5:
  2170      type: "array"
  2171      items:
  2172      - $ref: "#/definitions/TestProperty"
  2173      - $ref: "#/definitions/TestProperty"
  2174    TestProperty:
  2175      description: "This TestProperty is different from the one in spec1"
  2176      type: "object"
  2177  `), &spec2)
  2178  
  2179  	yaml.Unmarshal([]byte(`
  2180  swagger: "2.0"
  2181  paths:
  2182    /test:
  2183      post:
  2184        parameters:
  2185        - name: "body"
  2186          schema:
  2187            $ref: "#/definitions/Test"
  2188    /test2:
  2189      post:
  2190        parameters:
  2191        - name: "test2"
  2192          schema:
  2193            $ref: "#/definitions/Test2"
  2194        - name: "test3"
  2195          schema:
  2196            $ref: "#/definitions/Test3"
  2197        - name: "test4"
  2198          schema:
  2199            $ref: "#/definitions/Test4"
  2200        - name: "test5"
  2201          schema:
  2202            $ref: "#/definitions/Test5"
  2203  definitions:
  2204    Test:
  2205      type: "object"
  2206      properties:
  2207        foo:
  2208          $ref: "#/definitions/TestProperty"
  2209    TestProperty:
  2210      type: "object"
  2211    Test2:
  2212      $ref: "#/definitions/TestProperty_v2"
  2213    Test3:
  2214      type: "object"
  2215      properties:
  2216        withRef:
  2217          $ref: "#/definitions/TestProperty_v2"
  2218        withAllOf:
  2219          type: "object"
  2220          allOf:
  2221          - $ref: "#/definitions/TestProperty_v2"
  2222          - type: object
  2223            properties:
  2224              test:
  2225                $ref: "#/definitions/TestProperty_v2"
  2226        withAnyOf:
  2227          type: "object"
  2228          anyOf:
  2229          - $ref: "#/definitions/TestProperty_v2"
  2230          - type: object
  2231            properties:
  2232              test:
  2233                $ref: "#/definitions/TestProperty_v2"
  2234        withOneOf:
  2235          type: "object"
  2236          oneOf:
  2237          - $ref: "#/definitions/TestProperty_v2"
  2238          - type: object
  2239            properties:
  2240              test:
  2241                $ref: "#/definitions/TestProperty_v2"
  2242        withNot:
  2243          type: "object"
  2244          not:
  2245            $ref: "#/definitions/TestProperty_v2"
  2246      patternProperties:
  2247        "prefix.*":
  2248          $ref: "#/definitions/TestProperty_v2"
  2249      additionalProperties:
  2250        $ref: "#/definitions/TestProperty_v2"
  2251      definitions:
  2252        SomeDefinition:
  2253          $ref: "#/definitions/TestProperty_v2"
  2254    Test4:
  2255      type: "array"
  2256      items:
  2257        $ref: "#/definitions/TestProperty_v2"
  2258      additionalItems:
  2259        $ref: "#/definitions/TestProperty_v2"
  2260    Test5:
  2261      type: "array"
  2262      items:
  2263      - $ref: "#/definitions/TestProperty_v2"
  2264      - $ref: "#/definitions/TestProperty_v2"
  2265    TestProperty_v2:
  2266      description: "This TestProperty is different from the one in spec1"
  2267      type: "object"
  2268  `), &expected)
  2269  
  2270  	ast := assert.New(t)
  2271  	orig_spec2, _ := cloneSpec(spec2)
  2272  	if !ast.NoError(MergeSpecs(spec1, spec2)) {
  2273  		return
  2274  	}
  2275  	ast.Equal(DebugSpec{expected}, DebugSpec{spec1})
  2276  	ast.Equal(DebugSpec{orig_spec2}, DebugSpec{spec2}, "unexpected mutation of input")
  2277  }
  2278  
  2279  func loadTestData() ([]*spec.Swagger, *spec.Swagger) {
  2280  	loadSpec := func(fileName string) *spec.Swagger {
  2281  		bs, err := os.ReadFile(filepath.Join("../../test/integration/testdata/aggregator", fileName))
  2282  		if err != nil {
  2283  			panic(err)
  2284  		}
  2285  		sp := spec.Swagger{}
  2286  
  2287  		if err := json.Unmarshal(bs, &sp); err != nil {
  2288  			panic(err)
  2289  		}
  2290  		return &sp
  2291  	}
  2292  
  2293  	specs := []*spec.Swagger{
  2294  		loadSpec("openapi-0.json"),
  2295  		loadSpec("openapi-1.json"),
  2296  		loadSpec("openapi-2.json"),
  2297  	}
  2298  	expected := loadSpec("openapi.json")
  2299  
  2300  	return specs, expected
  2301  }
  2302  
  2303  func TestCloneSpec(t *testing.T) {
  2304  	_, sp := loadTestData()
  2305  	clone, err := cloneSpec(sp)
  2306  	if err != nil {
  2307  		t.Fatalf("unexpected error: %v", err)
  2308  	}
  2309  	ast := assert.New(t)
  2310  	ast.Equal(DebugSpec{sp}, DebugSpec{clone})
  2311  }
  2312  
  2313  func cloneSpec(source *spec.Swagger) (*spec.Swagger, error) {
  2314  	bytes, err := source.MarshalJSON()
  2315  	if err != nil {
  2316  		return nil, err
  2317  	}
  2318  	var ret spec.Swagger
  2319  	err = json.Unmarshal(bytes, &ret)
  2320  	if err != nil {
  2321  		return nil, err
  2322  	}
  2323  	return &ret, nil
  2324  }
  2325  
  2326  func TestMergedGVKs(t *testing.T) {
  2327  	gvk1 := map[string]interface{}{"group": "group1", "version": "v1", "kind": "Foo"}
  2328  	gvk2 := map[string]interface{}{"group": "group2", "version": "v1", "kind": "Bar"}
  2329  	gvk3 := map[string]interface{}{"group": "group3", "version": "v1", "kind": "Abc"}
  2330  	gvk4 := map[string]interface{}{"group": "group4", "version": "v1", "kind": "Abc"}
  2331  
  2332  	tests := []struct {
  2333  		name        string
  2334  		gvks1       interface{}
  2335  		gvks2       interface{}
  2336  		want        interface{}
  2337  		wantChanged bool
  2338  		wantErr     bool
  2339  	}{
  2340  		{"nil", nil, nil, nil, false, false},
  2341  		{"first only", []interface{}{gvk1, gvk2}, nil, []interface{}{gvk1, gvk2}, false, false},
  2342  		{"second only", nil, []interface{}{gvk1, gvk2}, []interface{}{gvk1, gvk2}, true, false},
  2343  		{"both", []interface{}{gvk1, gvk2}, []interface{}{gvk3}, []interface{}{gvk1, gvk2, gvk3}, true, false},
  2344  		{"equal, different order", []interface{}{gvk1, gvk2, gvk3}, []interface{}{gvk3, gvk2, gvk1}, []interface{}{gvk1, gvk2, gvk3}, false, false},
  2345  		{"ordered", []interface{}{gvk3, gvk1, gvk4}, []interface{}{gvk2}, []interface{}{gvk1, gvk2, gvk3, gvk4}, true, false},
  2346  		{"not ordered when not changed", []interface{}{gvk3, gvk1, gvk4}, []interface{}{}, []interface{}{gvk3, gvk1, gvk4}, false, false},
  2347  		{"empty", []interface{}{}, []interface{}{}, []interface{}{}, false, false},
  2348  		{"overlapping", []interface{}{gvk1, gvk2}, []interface{}{gvk2, gvk3}, []interface{}{gvk1, gvk2, gvk3}, true, false},
  2349  		{"first no slice", 42, []interface{}{gvk1}, nil, false, true},
  2350  		{"second no slice", []interface{}{gvk1}, 42, nil, false, true},
  2351  		{"no map in slice", []interface{}{42}, []interface{}{gvk1}, nil, false, true},
  2352  	}
  2353  	for _, tt := range tests {
  2354  		t.Run(tt.name, func(t *testing.T) {
  2355  			var ext1, ext2 map[string]interface{}
  2356  			if tt.gvks1 != nil {
  2357  				ext1 = map[string]interface{}{"x-kubernetes-group-version-kind": tt.gvks1}
  2358  			}
  2359  			if tt.gvks2 != nil {
  2360  				ext2 = map[string]interface{}{"x-kubernetes-group-version-kind": tt.gvks2}
  2361  			}
  2362  
  2363  			got, gotChanged, gotErr := mergedGVKs(
  2364  				&spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: ext1}},
  2365  				&spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: ext2}},
  2366  			)
  2367  			if (gotErr != nil) != tt.wantErr {
  2368  				t.Errorf("mergedGVKs() error = %v, wantErr %v", gotErr, tt.wantErr)
  2369  				return
  2370  			}
  2371  			if gotChanged != tt.wantChanged {
  2372  				t.Errorf("mergedGVKs() changed = %v, want %v", gotChanged, tt.wantChanged)
  2373  			}
  2374  			if !reflect.DeepEqual(got, tt.want) {
  2375  				t.Errorf("mergedGVKs() got = %v, want %v", got, tt.want)
  2376  			}
  2377  		})
  2378  	}
  2379  }
  2380  
  2381  func TestDeepEqualDefinitionsModuloGVKs(t *testing.T) {
  2382  	tests := []struct {
  2383  		name  string
  2384  		s1    *spec.Schema
  2385  		s2    *spec.Schema
  2386  		equal bool
  2387  	}{
  2388  		{name: "nil", equal: true},
  2389  		{name: "nil, non-nil", s1: nil, s2: &spec.Schema{}},
  2390  		{name: "equal", s1: &spec.Schema{}, s2: &spec.Schema{}, equal: true},
  2391  		{name: "different", s1: &spec.Schema{SchemaProps: spec.SchemaProps{ID: "abc"}}, s2: &spec.Schema{}},
  2392  		{name: "equal modulo: nil, empty",
  2393  			s1:    &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: nil}},
  2394  			s2:    &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{}}},
  2395  			equal: true,
  2396  		},
  2397  		{name: "equal modulo: nil, gvk",
  2398  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: nil}},
  2399  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2400  				gvkKey: true,
  2401  			}}},
  2402  			equal: true,
  2403  		},
  2404  		{name: "equal modulo: empty, gvk",
  2405  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{}}},
  2406  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2407  				gvkKey: true,
  2408  			}}},
  2409  			equal: true,
  2410  		},
  2411  		{name: "equal modulo: non-empty, gvk",
  2412  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{"foo": "bar"}}},
  2413  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2414  				gvkKey: true,
  2415  				"foo":  "bar",
  2416  			}}},
  2417  			equal: true,
  2418  		},
  2419  		{name: "equal modulo: gvk, gvk",
  2420  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2421  				gvkKey: false,
  2422  				"foo":  "bar",
  2423  			}}},
  2424  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2425  				gvkKey: true,
  2426  				"foo":  "bar",
  2427  			}}},
  2428  			equal: true,
  2429  		},
  2430  		{name: "different values",
  2431  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2432  				gvkKey: false,
  2433  				"foo":  "bar",
  2434  			}}},
  2435  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2436  				gvkKey: true,
  2437  				"foo":  "abc",
  2438  			}}},
  2439  		},
  2440  		{name: "different sizes",
  2441  			s1: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2442  				gvkKey: false,
  2443  				"foo":  "bar",
  2444  				"xyz":  "123",
  2445  			}}},
  2446  			s2: &spec.Schema{VendorExtensible: spec.VendorExtensible{Extensions: spec.Extensions{
  2447  				gvkKey: true,
  2448  				"foo":  "abc",
  2449  			}}},
  2450  		},
  2451  	}
  2452  	for _, tt := range tests {
  2453  		t.Run(tt.name, func(t *testing.T) {
  2454  			if got := deepEqualDefinitionsModuloGVKs(tt.s1, tt.s2); got != tt.equal {
  2455  				t.Errorf("deepEqualDefinitionsModuloGVKs(s1, v2) = %v, want %v", got, tt.equal)
  2456  			}
  2457  
  2458  			if got := deepEqualDefinitionsModuloGVKs(tt.s2, tt.s1); got != tt.equal {
  2459  				t.Errorf("deepEqualDefinitionsModuloGVKs(s2, s1) = %v, want %v", got, tt.equal)
  2460  			}
  2461  		})
  2462  	}
  2463  }