...

Source file src/github.com/go-openapi/spec/resolver_test.go

Documentation: github.com/go-openapi/spec

     1  package spec
     2  
     3  import (
     4  	"encoding/json"
     5  	"net/http"
     6  	"net/http/httptest"
     7  	"os"
     8  	"path/filepath"
     9  	"testing"
    10  
    11  	"github.com/go-openapi/jsonpointer"
    12  	"github.com/stretchr/testify/assert"
    13  	"github.com/stretchr/testify/require"
    14  )
    15  
    16  func TestResolveRef(t *testing.T) {
    17  	var root interface{}
    18  	require.NoError(t, json.Unmarshal([]byte(PetStore20), &root))
    19  
    20  	ref, err := NewRef("#/definitions/Category")
    21  	require.NoError(t, err)
    22  
    23  	sch, err := ResolveRef(root, &ref)
    24  	require.NoError(t, err)
    25  
    26  	b, err := sch.MarshalJSON()
    27  	require.NoError(t, err)
    28  
    29  	assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b))
    30  
    31  	// WithBase variant
    32  	sch, err = ResolveRefWithBase(root, &ref, &ExpandOptions{
    33  		RelativeBase: "/",
    34  	})
    35  	require.NoError(t, err)
    36  
    37  	b, err = sch.MarshalJSON()
    38  	require.NoError(t, err)
    39  
    40  	assert.JSONEq(t, `{"id":"Category","properties":{"id":{"type":"integer","format":"int64"},"name":{"type":"string"}}}`, string(b))
    41  }
    42  
    43  func TestResolveResponse(t *testing.T) {
    44  	specDoc, err := jsonDoc(filepath.Join("fixtures", "expansion", "all-the-things.json"))
    45  	require.NoError(t, err)
    46  
    47  	spec := new(Swagger)
    48  	require.NoError(t, json.Unmarshal(specDoc, spec))
    49  
    50  	// Resolve with root version
    51  	resp := spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]
    52  	resp2, err := ResolveResponse(spec, resp.Ref)
    53  	require.NoError(t, err)
    54  
    55  	// resolve resolves the ref, but dos not expand
    56  	jazon := asJSON(t, resp2)
    57  
    58  	assert.JSONEq(t, `{
    59           "$ref": "#/responses/petResponse"
    60          }`, jazon)
    61  }
    62  
    63  func TestResolveResponseWithBase(t *testing.T) {
    64  	specDoc, err := jsonDoc(crossFileRefFixture)
    65  	require.NoError(t, err)
    66  
    67  	spec := new(Swagger)
    68  	require.NoError(t, json.Unmarshal(specDoc, spec))
    69  
    70  	// Resolve with root version
    71  	resp := spec.Paths.Paths["/"].Get.Responses.StatusCodeResponses[200]
    72  	resp2, err := ResolveResponseWithBase(spec, resp.Ref, &ExpandOptions{RelativeBase: crossFileRefFixture})
    73  	require.NoError(t, err)
    74  
    75  	// resolve resolves the ref, but dos not expand
    76  	jazon := asJSON(t, resp2)
    77  
    78  	assert.JSONEq(t, `{
    79           "$ref": "#/responses/petResponse"
    80          }`, jazon)
    81  }
    82  
    83  func TestResolveParam(t *testing.T) {
    84  	specDoc, err := jsonDoc(filepath.Join("fixtures", "expansion", "all-the-things.json"))
    85  	require.NoError(t, err)
    86  
    87  	var spec Swagger
    88  	require.NoError(t, json.Unmarshal(specDoc, &spec))
    89  
    90  	param := spec.Paths.Paths["/pets/{id}"].Get.Parameters[0]
    91  	par, err := ResolveParameter(spec, param.Ref)
    92  	require.NoError(t, err)
    93  
    94  	jazon := asJSON(t, par)
    95  
    96  	assert.JSONEq(t, `{
    97        "name": "id",
    98        "in": "path",
    99        "description": "ID of pet to fetch",
   100        "required": true,
   101        "type": "integer",
   102        "format": "int64"
   103        }`, jazon)
   104  }
   105  
   106  func TestResolveParamWithBase(t *testing.T) {
   107  	specDoc, err := jsonDoc(crossFileRefFixture)
   108  	require.NoError(t, err)
   109  
   110  	var spec Swagger
   111  	require.NoError(t, json.Unmarshal(specDoc, &spec))
   112  
   113  	param := spec.Paths.Paths["/pets"].Get.Parameters[0]
   114  	par, err := ResolveParameterWithBase(spec, param.Ref, &ExpandOptions{RelativeBase: crossFileRefFixture})
   115  	require.NoError(t, err)
   116  
   117  	jazon := asJSON(t, par)
   118  
   119  	assert.JSONEq(t, `{
   120  "description":"ID of pet to fetch",
   121  "format":"int64",
   122  "in":"path",
   123  "name":"id",
   124  "required":true,
   125  "type":"integer"
   126  }`, jazon)
   127  }
   128  
   129  func TestResolveRemoteRef_RootSame(t *testing.T) {
   130  	fileserver := http.FileServer(http.Dir(specs))
   131  	server := httptest.NewServer(fileserver)
   132  	defer server.Close()
   133  
   134  	rootDoc := new(Swagger)
   135  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   136  	require.NoError(t, err)
   137  	require.NoError(t, json.Unmarshal(b, rootDoc))
   138  
   139  	// the filename doesn't matter because ref will eventually point to refed.json
   140  	specBase := normalizeBase(filepath.Join(specs, "anyotherfile.json"))
   141  
   142  	var result0 Swagger
   143  	ref0, _ := NewRef(server.URL + "/refed.json#")
   144  	resolver0 := defaultSchemaLoader(rootDoc, nil, nil, nil)
   145  	require.NoError(t, resolver0.Resolve(&ref0, &result0, ""))
   146  	assertSpecs(t, result0, *rootDoc)
   147  
   148  	var result1 Swagger
   149  	ref1, _ := NewRef("./refed.json")
   150  	resolver1 := defaultSchemaLoader(rootDoc, &ExpandOptions{
   151  		RelativeBase: specBase,
   152  	}, nil, nil)
   153  	require.NoError(t, resolver1.Resolve(&ref1, &result1, specBase))
   154  	assertSpecs(t, result1, *rootDoc)
   155  }
   156  
   157  func TestResolveRemoteRef_FromFragment(t *testing.T) {
   158  	fileserver := http.FileServer(http.Dir(specs))
   159  	server := httptest.NewServer(fileserver)
   160  	defer server.Close()
   161  
   162  	rootDoc := new(Swagger)
   163  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   164  	require.NoError(t, err)
   165  	require.NoError(t, json.Unmarshal(b, rootDoc))
   166  
   167  	var tgt Schema
   168  	ref, err := NewRef(server.URL + "/refed.json#/definitions/pet")
   169  	require.NoError(t, err)
   170  
   171  	context := newResolverContext(&ExpandOptions{PathLoader: jsonDoc})
   172  	resolver := &schemaLoader{root: rootDoc, cache: defaultResolutionCache(), context: context}
   173  	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   174  	assert.Equal(t, []string{"id", "name"}, tgt.Required)
   175  }
   176  
   177  func TestResolveRemoteRef_FromInvalidFragment(t *testing.T) {
   178  	fileserver := http.FileServer(http.Dir(specs))
   179  	server := httptest.NewServer(fileserver)
   180  	defer server.Close()
   181  
   182  	rootDoc := new(Swagger)
   183  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   184  	require.NoError(t, err)
   185  	require.NoError(t, json.Unmarshal(b, rootDoc))
   186  
   187  	var tgt Schema
   188  	ref, err := NewRef(server.URL + "/refed.json#/definitions/NotThere")
   189  	require.NoError(t, err)
   190  
   191  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   192  	require.Error(t, resolver.Resolve(&ref, &tgt, ""))
   193  }
   194  
   195  /* This next test will have to wait until we do full $ID analysis for every subschema on every file that is referenced */
   196  /* For now, TestResolveRemoteRef_WithNestedResolutionContext replaces this next test */
   197  // func TestResolveRemoteRef_WithNestedResolutionContextWithFragment_WithParentID(t *testing.T) {
   198  // 	server := resolutionContextServer()
   199  // 	defer server.Close()
   200  //
   201  // 	rootDoc := new(Swagger)
   202  // 	b, err := os.ReadFile("fixtures/specs/refed.json")
   203  // 	require.NoError(t, err) && assert.NoError(t, json.Unmarshal(b, rootDoc))
   204  //
   205  //	var tgt Schema
   206  // 	ref, err := NewRef(server.URL + "/resolution2.json#/items/items")
   207  // 	require.NoError(t, err)
   208  //
   209  // 	resolver := defaultSchemaLoader(rootDoc, nil, nil,nil)
   210  // 	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   211  // 	assert.Equal(t, StringOrArray([]string{"file"}), tgt.Type)
   212  // }
   213  
   214  func TestResolveRemoteRef_ToParameter(t *testing.T) {
   215  	fileserver := http.FileServer(http.Dir(specs))
   216  	server := httptest.NewServer(fileserver)
   217  	defer server.Close()
   218  
   219  	rootDoc := new(Swagger)
   220  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   221  	require.NoError(t, err)
   222  	require.NoError(t, json.Unmarshal(b, rootDoc))
   223  
   224  	var tgt Parameter
   225  	ref, err := NewRef(server.URL + "/refed.json#/parameters/idParam")
   226  	require.NoError(t, err)
   227  
   228  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   229  	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   230  
   231  	assert.Equal(t, "id", tgt.Name)
   232  	assert.Equal(t, "path", tgt.In)
   233  	assert.Equal(t, "ID of pet to fetch", tgt.Description)
   234  	assert.True(t, tgt.Required)
   235  	assert.Equal(t, "integer", tgt.Type)
   236  	assert.Equal(t, "int64", tgt.Format)
   237  }
   238  
   239  func TestResolveRemoteRef_ToPathItem(t *testing.T) {
   240  	fileserver := http.FileServer(http.Dir(specs))
   241  	server := httptest.NewServer(fileserver)
   242  	defer server.Close()
   243  
   244  	rootDoc := new(Swagger)
   245  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   246  	require.NoError(t, err)
   247  	require.NoError(t, json.Unmarshal(b, rootDoc))
   248  
   249  	var tgt PathItem
   250  	ref, err := NewRef(server.URL + "/refed.json#/paths/" + jsonpointer.Escape("/pets/{id}"))
   251  	require.NoError(t, err)
   252  
   253  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   254  	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   255  	assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get)
   256  }
   257  
   258  func TestResolveRemoteRef_ToResponse(t *testing.T) {
   259  	fileserver := http.FileServer(http.Dir(specs))
   260  	server := httptest.NewServer(fileserver)
   261  	defer server.Close()
   262  
   263  	rootDoc := new(Swagger)
   264  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   265  	require.NoError(t, err)
   266  	require.NoError(t, json.Unmarshal(b, rootDoc))
   267  
   268  	var tgt Response
   269  	ref, err := NewRef(server.URL + "/refed.json#/responses/petResponse")
   270  	require.NoError(t, err)
   271  
   272  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   273  	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   274  	assert.Equal(t, rootDoc.Responses["petResponse"], tgt)
   275  }
   276  
   277  func TestResolveLocalRef_SameRoot(t *testing.T) {
   278  	rootDoc := new(Swagger)
   279  	require.NoError(t, json.Unmarshal(PetStoreJSONMessage, rootDoc))
   280  
   281  	result := new(Swagger)
   282  	ref, _ := NewRef("#")
   283  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   284  	require.NoError(t, resolver.Resolve(&ref, result, ""))
   285  	assert.Equal(t, rootDoc, result)
   286  }
   287  
   288  func TestResolveLocalRef_FromFragment(t *testing.T) {
   289  	rootDoc := new(Swagger)
   290  	require.NoError(t, json.Unmarshal(PetStoreJSONMessage, rootDoc))
   291  
   292  	var tgt Schema
   293  	ref, err := NewRef("#/definitions/Category")
   294  	require.NoError(t, err)
   295  
   296  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   297  	require.NoError(t, resolver.Resolve(&ref, &tgt, ""))
   298  	assert.Equal(t, "Category", tgt.ID)
   299  }
   300  
   301  func TestResolveLocalRef_FromInvalidFragment(t *testing.T) {
   302  	rootDoc := new(Swagger)
   303  	require.NoError(t, json.Unmarshal(PetStoreJSONMessage, rootDoc))
   304  
   305  	var tgt Schema
   306  	ref, err := NewRef("#/definitions/NotThere")
   307  	require.NoError(t, err)
   308  
   309  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   310  	require.Error(t, resolver.Resolve(&ref, &tgt, ""))
   311  }
   312  
   313  func TestResolveLocalRef_Parameter(t *testing.T) {
   314  	rootDoc := new(Swagger)
   315  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   316  	require.NoError(t, err)
   317  
   318  	basePath := filepath.Join(specs, "refed.json")
   319  	require.NoError(t, json.Unmarshal(b, rootDoc))
   320  
   321  	var tgt Parameter
   322  	ref, err := NewRef("#/parameters/idParam")
   323  	require.NoError(t, err)
   324  
   325  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   326  	require.NoError(t, resolver.Resolve(&ref, &tgt, basePath))
   327  
   328  	assert.Equal(t, "id", tgt.Name)
   329  	assert.Equal(t, "path", tgt.In)
   330  	assert.Equal(t, "ID of pet to fetch", tgt.Description)
   331  	assert.True(t, tgt.Required)
   332  	assert.Equal(t, "integer", tgt.Type)
   333  	assert.Equal(t, "int64", tgt.Format)
   334  }
   335  
   336  func TestResolveLocalRef_PathItem(t *testing.T) {
   337  	rootDoc := new(Swagger)
   338  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   339  	require.NoError(t, err)
   340  
   341  	basePath := filepath.Join(specs, "refed.json")
   342  	require.NoError(t, json.Unmarshal(b, rootDoc))
   343  
   344  	var tgt PathItem
   345  	ref, err := NewRef("#/paths/" + jsonpointer.Escape("/pets/{id}"))
   346  	require.NoError(t, err)
   347  
   348  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   349  	require.NoError(t, resolver.Resolve(&ref, &tgt, basePath))
   350  	assert.Equal(t, rootDoc.Paths.Paths["/pets/{id}"].Get, tgt.Get)
   351  }
   352  
   353  func TestResolveLocalRef_Response(t *testing.T) {
   354  	rootDoc := new(Swagger)
   355  	b, err := os.ReadFile(filepath.Join(specs, "refed.json"))
   356  	require.NoError(t, err)
   357  
   358  	basePath := filepath.Join(specs, "refed.json")
   359  	require.NoError(t, json.Unmarshal(b, rootDoc))
   360  
   361  	var tgt Response
   362  	ref, err := NewRef("#/responses/petResponse")
   363  	require.NoError(t, err)
   364  
   365  	resolver := defaultSchemaLoader(rootDoc, nil, nil, nil)
   366  	require.NoError(t, resolver.Resolve(&ref, &tgt, basePath))
   367  	assert.Equal(t, rootDoc.Responses["petResponse"], tgt)
   368  }
   369  
   370  func TestResolvePathItem(t *testing.T) {
   371  	spec := new(Swagger)
   372  	specDoc, err := jsonDoc(pathItemsFixture)
   373  	require.NoError(t, err)
   374  
   375  	require.NoError(t, json.Unmarshal(specDoc, spec))
   376  
   377  	// Resolve use case
   378  	pth := spec.Paths.Paths["/todos"]
   379  	pathItem, err := ResolvePathItem(spec, pth.Ref, &ExpandOptions{RelativeBase: pathItemsFixture})
   380  	require.NoError(t, err)
   381  
   382  	jazon := asJSON(t, pathItem)
   383  
   384  	assert.JSONEq(t, `{
   385           "get": {
   386            "responses": {
   387             "200": {
   388              "description": "List Todos",
   389              "schema": {
   390               "type": "array",
   391               "items": {
   392                "type": "string"
   393               }
   394              }
   395             },
   396             "404": {
   397              "description": "error"
   398             }
   399            }
   400           }
   401  			 }`, jazon)
   402  }
   403  
   404  func TestResolveExtraItem(t *testing.T) {
   405  	// go-openapi extra goodie: $ref in simple schema Items and Headers
   406  	spec := new(Swagger)
   407  	specDoc, err := jsonDoc(extraRefFixture)
   408  	require.NoError(t, err)
   409  
   410  	require.NoError(t, json.Unmarshal(specDoc, spec))
   411  
   412  	// Resolve param Items use case: here we explicitly resolve the unsuppord case
   413  	parm := spec.Paths.Paths["/employees"].Get.Parameters[0]
   414  	parmItem, err := ResolveItems(spec, parm.Items.Ref, &ExpandOptions{RelativeBase: extraRefFixture})
   415  	require.NoError(t, err)
   416  
   417  	jazon := asJSON(t, parmItem)
   418  
   419  	assert.JSONEq(t, `{
   420           "type": "integer",
   421           "format": "int32"
   422  			 }`, jazon)
   423  
   424  	// Resolve header Items use case: here we explicitly resolve the unsuppord case
   425  	hdr := spec.Paths.Paths["/employees"].Get.Responses.StatusCodeResponses[200].Headers["X-header"]
   426  	hdrItem, err := ResolveItems(spec, hdr.Items.Ref, &ExpandOptions{RelativeBase: extraRefFixture})
   427  	require.NoError(t, err)
   428  
   429  	jazon = asJSON(t, hdrItem)
   430  
   431  	assert.JSONEq(t, `{
   432           "type": "string",
   433           "format": "uuid"
   434  			 }`, jazon)
   435  }
   436  

View as plain text