Skip to content

Commit

Permalink
Merge pull request #178 from pivotal-k8s/add-map-struct-type
Browse files Browse the repository at this point in the history
Support +mapType, +structType markers
  • Loading branch information
k8s-ci-robot authored Jan 30, 2020
2 parents bf4fb3b + b567921 commit cdac1c7
Show file tree
Hide file tree
Showing 12 changed files with 275 additions and 17 deletions.
10 changes: 10 additions & 0 deletions pkg/generators/extension.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,6 +56,16 @@ var tagToExtension = map[string]extensionAttributes{
kind: types.Slice,
allowedValues: sets.NewString("atomic", "set", "map"),
},
"mapType": {
xName: "x-kubernetes-map-type",
kind: types.Map,
allowedValues: sets.NewString("atomic", "granular"),
},
"structType": {
xName: "x-kubernetes-map-type",
kind: types.Struct,
allowedValues: sets.NewString("atomic", "granular"),
},
}

// Extension encapsulates information necessary to generate an OpenAPI extension.
Expand Down
58 changes: 58 additions & 0 deletions pkg/generators/extension_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,12 @@ func TestSingleTagExtension(t *testing.T) {
extensionName: "x-kubernetes-list-map-keys",
extensionValues: []string{"port"},
},
{
comments: []string{"+mapType=granular"},
extensionTag: "mapType",
extensionName: "x-kubernetes-map-type",
extensionValues: []string{"granular"},
},
{
comments: []string{"+k8s:openapi-gen=x-kubernetes-member-tag:member_test"},
extensionTag: "k8s:openapi-gen",
Expand Down Expand Up @@ -205,6 +211,18 @@ func TestExtensionAllowedValues(t *testing.T) {
},
allowedValues: nil,
},
{
e: extension{
idlTag: "mapType",
},
allowedValues: sets.NewString("atomic", "granular"),
},
{
e: extension{
idlTag: "structType",
},
allowedValues: sets.NewString("atomic", "granular"),
},
{
e: extension{
idlTag: "k8s:openapi-gen",
Expand Down Expand Up @@ -259,6 +277,20 @@ func TestExtensionAllowedValues(t *testing.T) {
values: []string{"atomic"},
},
},
{
e: extension{
idlTag: "mapType",
xName: "x-kubernetes-map-type",
values: []string{"atomic"},
},
},
{
e: extension{
idlTag: "structType",
xName: "x-kubernetes-map-type",
values: []string{"granular"},
},
},
}
for _, test := range successTests {
actualErr := test.e.validateAllowedValues()
Expand Down Expand Up @@ -292,6 +324,20 @@ func TestExtensionAllowedValues(t *testing.T) {
values: []string{"not-allowed"},
},
},
{
e: extension{
idlTag: "mapType",
xName: "x-kubernetes-map-type",
values: []string{"something-pretty-wrong"},
},
},
{
e: extension{
idlTag: "structType",
xName: "x-kubernetes-map-type",
values: []string{"not-quite-right"},
},
},
}
for _, test := range failureTests {
actualErr := test.e.validateAllowedValues()
Expand Down Expand Up @@ -326,6 +372,18 @@ func TestExtensionKind(t *testing.T) {
},
kind: types.Slice,
},
{
e: extension{
idlTag: "mapType",
},
kind: types.Map,
},
{
e: extension{
idlTag: "structType",
},
kind: types.Struct,
},
{
e: extension{
idlTag: "listMapKey",
Expand Down
24 changes: 13 additions & 11 deletions pkg/idl/doc.go
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,14 @@ type ListType string
type ListMapKey string

// MapType annotates a map to further describe its topology. It may
// have only one value: "atomic". Atomic means that the entire map is
// considered as a whole, rather than as distinct values.
// have one of two values: `atomic` or `granular`. `atomic` means that the entire map is
// considered as a whole; actors that wish to update the map can only
// entirely replace it. `granular` means that specific values in the map can be
// updated separately from other fields.
//
// By default, a map will be considered as a set of distinct values that
// can be updated individually. This default WILL NOT generate any
// openapi extension, as this will also be interpreted as the default
// behavior in the openapi definition.
// can be updated individually (i.e. the equivalent of `granular`).
// This default will still generate an OpenAPI extension with key: "x-kubernetes-map-type".
//
// This tag MUST only be used on maps, or the generation step will fail.
//
Expand Down Expand Up @@ -114,13 +115,14 @@ type PatchMergeKey string
type PatchStrategy string

// StructType annotates a struct to further describe its topology. It may
// have only one value: "atomic". Atomic means that the entire struct is
// considered as a whole, rather than as distinct values.
// have one of two values: `atomic` or `granular`. `atomic` means that the entire struct is
// considered as a whole; actors that wish to update the struct can only
// entirely replace it. `granular` means that specific fields in the struct can be
// updated separately from other fields.
//
// By default, a struct will be considered as a set of distinct values that
// can be updated individually. This default WILL NOT generate any
// openapi extension, as this will also be interpreted as the default
// behavior in the openapi definition.
// can be updated individually (`granular`).
// This default will still generate an OpenAPI extension with key: "x-kubernetes-map-type".
//
// This tag MUST only be used on structs, or the generation step will fail.
//
Expand All @@ -133,7 +135,7 @@ type PatchStrategy string
// used on any struct.
//
// Using this tag will generate the following OpenAPI extension:
// "x-kubernetes-struct-type": "atomic"
// "x-kubernetes-map-type": "atomic"
type StructType string

// Union is TBD.
Expand Down
12 changes: 6 additions & 6 deletions test/integration/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,27 @@ $ go test -v .

First, run the generator to create `openapi_generated.go` file which specifies
the `OpenAPIDefinition` for each type, and generate the golden API rule
violation report file . Note that if you do not pass a report
filename (`./testdata/golden.report` in the command below) to let the generator
violation report file. Note that if you do not pass a report
filename (`./testdata/golden.v2.report` in the command below) to let the generator
to print API rule violations to the file, the generator will return error to stderr
on API rule violations.

```bash
$ go run ../../cmd/openapi-gen/openapi-gen.go \
-i "k8s.io/kube-openapi/test/integration/testdata/listtype,k8s.io/kube-openapi/test/integration/testdata/dummytype,k8s.io/kube-openapi/test/integration/testdata/uniontype" \
-i "k8s.io/kube-openapi/test/integration/testdata/custom,k8s.io/kube-openapi/test/integration/testdata/listtype,k8s.io/kube-openapi/test/integration/testdata/maptype,k8s.io/kube-openapi/test/integration/testdata/structtype,k8s.io/kube-openapi/test/integration/testdata/dummytype,k8s.io/kube-openapi/test/integration/testdata/uniontype" \
-o pkg \
-p generated \
-O openapi_generated \
-r ./testdata/golden.report
-r ./testdata/golden.v2.report
```
The generated file `pkg/generated/openapi_generated.go` should have been created.

Next, run the OpenAPI builder to create the Swagger file which includes
the definitions. The output file named `golden.json` will be output in
the definitions. The output file named `golden.v2.json` will be output in
the current directory.

```bash
$ go run builder/main.go testdata/golden.json
$ go run builder/main.go testdata/golden.v2.json
```

After the golden spec is generated, please clean up the generated file
Expand Down
4 changes: 4 additions & 0 deletions test/integration/builder/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,10 @@ func createWebServices() []*restful.WebService {
w.Route(buildRouteForType(w, "custom", "Bak"))
w.Route(buildRouteForType(w, "custom", "Bac"))
w.Route(buildRouteForType(w, "custom", "Bah"))
w.Route(buildRouteForType(w, "maptype", "GranularMap"))
w.Route(buildRouteForType(w, "maptype", "AtomicMap"))
w.Route(buildRouteForType(w, "structtype", "GranularStruct"))
w.Route(buildRouteForType(w, "structtype", "AtomicStruct"))
return []*restful.WebService{w}
}

Expand Down
2 changes: 2 additions & 0 deletions test/integration/integration_suite_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ const (
testdataDir = "./testdata"
testPkgDir = "k8s.io/kube-openapi/test/integration/testdata"
inputDir = testPkgDir + "/listtype" +
"," + testPkgDir + "/maptype" +
"," + testPkgDir + "/structtype" +
"," + testPkgDir + "/dummytype" +
"," + testPkgDir + "/uniontype" +
"," + testPkgDir + "/custom"
Expand Down
143 changes: 143 additions & 0 deletions test/integration/testdata/golden.v2.json
Original file line number Diff line number Diff line change
Expand Up @@ -214,6 +214,82 @@
}
}
},
"/test/maptype/atomicmap": {
"get": {
"schemes": [
"https"
],
"operationId": "func15",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/maptype.AtomicMap"
}
},
"404": {
"$ref": "#/responses/NotFound"
}
}
}
},
"/test/maptype/granularmap": {
"get": {
"schemes": [
"https"
],
"operationId": "func14",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/maptype.GranularMap"
}
},
"404": {
"$ref": "#/responses/NotFound"
}
}
}
},
"/test/structtype/atomicstruct": {
"get": {
"schemes": [
"https"
],
"operationId": "func17",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/structtype.AtomicStruct"
}
},
"404": {
"$ref": "#/responses/NotFound"
}
}
}
},
"/test/structtype/granularstruct": {
"get": {
"schemes": [
"https"
],
"operationId": "func16",
"responses": {
"200": {
"description": "OK",
"schema": {
"$ref": "#/definitions/structtype.GranularStruct"
}
},
"404": {
"$ref": "#/responses/NotFound"
}
}
}
},
"/test/uniontype/inlinedunion": {
"get": {
"schemes": [
Expand Down Expand Up @@ -405,6 +481,73 @@
}
}
},
"maptype.AtomicMap": {
"type": "object",
"required": [
"KeyValue"
],
"properties": {
"KeyValue": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"x-kubernetes-map-type": "atomic"
}
}
},
"maptype.GranularMap": {
"type": "object",
"required": [
"KeyValue"
],
"properties": {
"KeyValue": {
"type": "object",
"additionalProperties": {
"type": "string"
},
"x-kubernetes-map-type": "granular"
}
}
},
"structtype.AtomicStruct": {
"type": "object",
"required": [
"Field",
"OtherField"
],
"properties": {
"Field": {
"x-kubernetes-map-type": "atomic",
"$ref": "#/definitions/structtype.ContainedStruct"
},
"OtherField": {
"type": "integer",
"format": "int32"
}
}
},
"structtype.ContainedStruct": {
"type": "object"
},
"structtype.GranularStruct": {
"type": "object",
"required": [
"Field",
"OtherField"
],
"properties": {
"Field": {
"x-kubernetes-map-type": "granular",
"$ref": "#/definitions/structtype.ContainedStruct"
},
"OtherField": {
"type": "integer",
"format": "int32"
}
}
},
"uniontype.InlinedUnion": {
"type": "object",
"required": [
Expand Down
6 changes: 6 additions & 0 deletions test/integration/testdata/golden.v2.report
Original file line number Diff line number Diff line change
Expand Up @@ -13,4 +13,10 @@ API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/li
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/listtype,MapList,Field
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/listtype,SetList,Field
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/listtype,UntypedList,Field
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/maptype,AtomicMap,KeyValue
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/maptype,GranularMap,KeyValue
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/structtype,AtomicStruct,Field
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/structtype,AtomicStruct,OtherField
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/structtype,GranularStruct,Field
API rule violation: names_match,k8s.io/kube-openapi/test/integration/testdata/structtype,GranularStruct,OtherField
API rule violation: omitempty_match_case,k8s.io/kube-openapi/test/integration/testdata/listtype,Item,C
7 changes: 7 additions & 0 deletions test/integration/testdata/maptype/atomic-map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package maptype

// +k8s:openapi-gen=true
type AtomicMap struct {
// +mapType=atomic
KeyValue map[string]string
}
7 changes: 7 additions & 0 deletions test/integration/testdata/maptype/granular-map.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
package maptype

// +k8s:openapi-gen=true
type GranularMap struct {
// +mapType=granular
KeyValue map[string]string
}
Loading

0 comments on commit cdac1c7

Please sign in to comment.