k8s.io/kube-openapi@v0.0.0-20240228011516-70dd3763d340/pkg/validation/spec/schema_test.go (about)

     1  // Copyright 2015 go-swagger maintainers
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //    http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package spec
    16  
    17  import (
    18  	"encoding/json"
    19  	"testing"
    20  
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/stretchr/testify/require"
    23  	jsontesting "k8s.io/kube-openapi/pkg/util/jsontesting"
    24  )
    25  
    26  var schema = Schema{
    27  	VendorExtensible: VendorExtensible{Extensions: map[string]interface{}{"x-framework": "go-swagger"}},
    28  	SchemaProps: SchemaProps{
    29  		Ref:              MustCreateRef("Cat"),
    30  		Schema:           "schemaURL",
    31  		Type:             []string{"string"},
    32  		Format:           "date",
    33  		Description:      "the description of this schema",
    34  		Title:            "the title",
    35  		Default:          "blah",
    36  		Maximum:          float64Ptr(100),
    37  		ExclusiveMaximum: true,
    38  		ExclusiveMinimum: true,
    39  		Minimum:          float64Ptr(5),
    40  		MaxLength:        int64Ptr(100),
    41  		MinLength:        int64Ptr(5),
    42  		Pattern:          "\\w{1,5}\\w+",
    43  		MaxItems:         int64Ptr(100),
    44  		MinItems:         int64Ptr(5),
    45  		UniqueItems:      true,
    46  		MultipleOf:       float64Ptr(5),
    47  		Enum:             []interface{}{"hello", "world"},
    48  		MaxProperties:    int64Ptr(5),
    49  		MinProperties:    int64Ptr(1),
    50  		Required:         []string{"id", "name"},
    51  		Items:            &SchemaOrArray{Schema: &Schema{SchemaProps: SchemaProps{Type: []string{"string"}}}},
    52  		AllOf:            []Schema{{SchemaProps: SchemaProps{Type: []string{"string"}}}},
    53  		Properties: map[string]Schema{
    54  			"id":   {SchemaProps: SchemaProps{Type: []string{"integer"}, Format: "int64"}},
    55  			"name": {SchemaProps: SchemaProps{Type: []string{"string"}}},
    56  		},
    57  		AdditionalProperties: &SchemaOrBool{Allows: true, Schema: &Schema{SchemaProps: SchemaProps{
    58  			Type:   []string{"integer"},
    59  			Format: "int32",
    60  		}}},
    61  	},
    62  	SwaggerSchemaProps: SwaggerSchemaProps{
    63  		Discriminator: "not this",
    64  		ReadOnly:      true,
    65  		ExternalDocs: &ExternalDocumentation{
    66  			Description: "the documentation etc",
    67  			URL:         "http://readthedocs.org/swagger",
    68  		},
    69  		Example: []interface{}{
    70  			map[string]interface{}{
    71  				"id":   1,
    72  				"name": "a book",
    73  			},
    74  			map[string]interface{}{
    75  				"id":   2,
    76  				"name": "the thing",
    77  			},
    78  		},
    79  	},
    80  }
    81  
    82  var schemaJSON = `{
    83  	"x-framework": "go-swagger",
    84    "$ref": "Cat",
    85    "$schema": "schemaURL",
    86    "description": "the description of this schema",
    87    "maximum": 100,
    88    "minimum": 5,
    89    "exclusiveMaximum": true,
    90    "exclusiveMinimum": true,
    91    "maxLength": 100,
    92    "minLength": 5,
    93    "pattern": "\\w{1,5}\\w+",
    94    "maxItems": 100,
    95    "minItems": 5,
    96    "uniqueItems": true,
    97    "multipleOf": 5,
    98    "enum": ["hello", "world"],
    99    "type": "string",
   100    "format": "date",
   101    "title": "the title",
   102    "default": "blah",
   103    "maxProperties": 5,
   104    "minProperties": 1,
   105    "required": ["id", "name"],
   106    "items": {
   107      "type": "string"
   108    },
   109    "allOf": [
   110      {
   111        "type": "string"
   112      }
   113    ],
   114    "properties": {
   115      "id": {
   116        "type": "integer",
   117        "format": "int64"
   118      },
   119      "name": {
   120        "type": "string"
   121      }
   122    },
   123    "discriminator": "not this",
   124    "readOnly": true,
   125    "externalDocs": {
   126      "description": "the documentation etc",
   127      "url": "http://readthedocs.org/swagger"
   128    },
   129    "example": [
   130      {
   131        "id": 1,
   132        "name": "a book"
   133      },
   134      {
   135        "id": 2,
   136        "name": "the thing"
   137      }
   138    ],
   139    "additionalProperties": {
   140      "type": "integer",
   141      "format": "int32"
   142    }
   143  }
   144  `
   145  
   146  func TestSchema(t *testing.T) {
   147  
   148  	expected := map[string]interface{}{}
   149  	_ = json.Unmarshal([]byte(schemaJSON), &expected)
   150  	b, err := json.Marshal(schema)
   151  	if assert.NoError(t, err) {
   152  		var actual map[string]interface{}
   153  		_ = json.Unmarshal(b, &actual)
   154  		assert.Equal(t, expected, actual)
   155  	}
   156  
   157  	actual2 := Schema{}
   158  	if assert.NoError(t, json.Unmarshal([]byte(schemaJSON), &actual2)) {
   159  		assert.Equal(t, schema.Ref, actual2.Ref)
   160  		assert.Equal(t, schema.Schema, actual2.Schema)
   161  		assert.Equal(t, schema.Description, actual2.Description)
   162  		assert.Equal(t, schema.Maximum, actual2.Maximum)
   163  		assert.Equal(t, schema.Minimum, actual2.Minimum)
   164  		assert.Equal(t, schema.ExclusiveMinimum, actual2.ExclusiveMinimum)
   165  		assert.Equal(t, schema.ExclusiveMaximum, actual2.ExclusiveMaximum)
   166  		assert.Equal(t, schema.MaxLength, actual2.MaxLength)
   167  		assert.Equal(t, schema.MinLength, actual2.MinLength)
   168  		assert.Equal(t, schema.Pattern, actual2.Pattern)
   169  		assert.Equal(t, schema.MaxItems, actual2.MaxItems)
   170  		assert.Equal(t, schema.MinItems, actual2.MinItems)
   171  		assert.True(t, actual2.UniqueItems)
   172  		assert.Equal(t, schema.MultipleOf, actual2.MultipleOf)
   173  		assert.Equal(t, schema.Enum, actual2.Enum)
   174  		assert.Equal(t, schema.Type, actual2.Type)
   175  		assert.Equal(t, schema.Format, actual2.Format)
   176  		assert.Equal(t, schema.Title, actual2.Title)
   177  		assert.Equal(t, schema.MaxProperties, actual2.MaxProperties)
   178  		assert.Equal(t, schema.MinProperties, actual2.MinProperties)
   179  		assert.Equal(t, schema.Required, actual2.Required)
   180  		assert.Equal(t, schema.Items, actual2.Items)
   181  		assert.Equal(t, schema.AllOf, actual2.AllOf)
   182  		assert.Equal(t, schema.Properties, actual2.Properties)
   183  		assert.Equal(t, schema.Discriminator, actual2.Discriminator)
   184  		assert.Equal(t, schema.ReadOnly, actual2.ReadOnly)
   185  		assert.Equal(t, schema.ExternalDocs, actual2.ExternalDocs)
   186  		assert.Equal(t, schema.AdditionalProperties, actual2.AdditionalProperties)
   187  		assert.Equal(t, schema.Extensions, actual2.Extensions)
   188  		examples := actual2.Example.([]interface{})
   189  		expEx := schema.Example.([]interface{})
   190  		ex1 := examples[0].(map[string]interface{})
   191  		ex2 := examples[1].(map[string]interface{})
   192  		exp1 := expEx[0].(map[string]interface{})
   193  		exp2 := expEx[1].(map[string]interface{})
   194  
   195  		assert.EqualValues(t, exp1["id"], ex1["id"])
   196  		assert.Equal(t, exp1["name"], ex1["name"])
   197  		assert.EqualValues(t, exp2["id"], ex2["id"])
   198  		assert.Equal(t, exp2["name"], ex2["name"])
   199  	}
   200  
   201  }
   202  
   203  func TestSchemaRoundtrip(t *testing.T) {
   204  	cases := []jsontesting.RoundTripTestCase{
   205  		{
   206  			// Show at least one field from each embededd struct sitll allows
   207  			// roundtrips successfully
   208  			Name: "UnmarshalEmbedded",
   209  			Object: &Schema{
   210  				VendorExtensible{Extensions: Extensions{
   211  					"x-framework": "go-swagger",
   212  				}},
   213  				SchemaProps{
   214  					Description: "this is a description",
   215  				},
   216  				SwaggerSchemaProps{
   217  					Example: "this is an example",
   218  				},
   219  				map[string]interface{}{
   220  					"unknown/prop": "test prop",
   221  				},
   222  			},
   223  		},
   224  		// Can't add this case due to map[string]interface{} unmarshaling
   225  		// numbers unconditionally into float. But schema uses ints
   226  		// {
   227  		// 	Name:   "BasicCase",
   228  		// 	JSON:   schemaJSON,
   229  		// 	Object: &schema,
   230  		// },
   231  	}
   232  
   233  	for _, tcase := range cases {
   234  		t.Run(tcase.Name, func(t *testing.T) {
   235  			require.NoError(t, tcase.RoundTripTest(&Schema{}))
   236  		})
   237  	}
   238  }
   239  
   240  func BenchmarkSchemaUnmarshal(b *testing.B) {
   241  	for i := 0; i < b.N; i++ {
   242  		sch := &Schema{}
   243  		_ = sch.UnmarshalJSON([]byte(schemaJSON))
   244  	}
   245  }