databricks-cli/bundle/schema/schema_test.go

743 lines
14 KiB
Go
Raw Normal View History

package schema
import (
2023-01-16 12:18:56 +00:00
"container/list"
"encoding/json"
"reflect"
"testing"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
// TODO: add tests to assert that these are valid json schemas. Maybe validate some
// json/yaml documents againts them, by unmarshalling a value
2023-01-17 14:08:17 +00:00
// TODO: See that all golang reflect types are covered (reasonalble limits) within
// these tests
2023-01-17 14:34:49 +00:00
// TODO: test what json schema is generated for an interface{} type. Make sure the behavior makes sense
// TODO: Have a test that combines multiple different cases
// TODO: have a test for what happens when omitempty in different cases: primitives, object, map, array
func TestIntSchema(t *testing.T) {
2023-01-17 14:08:17 +00:00
var elemInt int
expected :=
`{
"type": "number"
}`
Int, err := NewSchema(reflect.TypeOf(elemInt))
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(Int, " ", " ")
assert.NoError(t, err)
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestBooleanSchema(t *testing.T) {
var elem bool
expected :=
`{
"type": "boolean"
}`
Int, err := NewSchema(reflect.TypeOf(elem))
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(Int, " ", " ")
assert.NoError(t, err)
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestStringSchema(t *testing.T) {
var elem string
expected :=
`{
"type": "string"
}`
Int, err := NewSchema(reflect.TypeOf(elem))
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(Int, " ", " ")
assert.NoError(t, err)
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-17 14:34:49 +00:00
func TestStructOfPrimitivesSchema(t *testing.T) {
type Foo struct {
IntVal int `json:"int_val"`
Int8Val int8 `json:"int8_val"`
Int16Val int16 `json:"int16_val"`
Int32Val int32 `json:"int32_val"`
Int64Val int64 `json:"int64_val"`
2023-01-17 14:08:17 +00:00
UIntVal uint `json:"uint_val"`
Uint8Val uint8 `json:"uint8_val"`
Uint16Val uint16 `json:"uint16_val"`
Uint32Val uint32 `json:"uint32_val"`
Uint64Val uint64 `json:"uint64_val"`
2023-01-17 14:08:17 +00:00
Float32Val float32 `json:"float32_val"`
Float64Val float64 `json:"float64_val"`
StringVal string `json:"string_val"`
2023-01-17 14:08:17 +00:00
BoolVal bool `json:"bool_val"`
}
elem := Foo{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
` {
"type": "object",
"properties": {
"bool_val": {
2023-01-17 14:08:17 +00:00
"type": "boolean"
},
"float32_val": {
"type": "number"
},
"float64_val": {
"type": "number"
},
"int16_val": {
"type": "number"
},
"int32_val": {
"type": "number"
},
"int64_val": {
"type": "number"
},
"int8_val": {
"type": "number"
},
"int_val": {
"type": "number"
},
"string_val": {
"type": "string"
},
"uint16_val": {
"type": "number"
},
"uint32_val": {
"type": "number"
},
"uint64_val": {
"type": "number"
},
"uint8_val": {
"type": "number"
2023-01-17 14:08:17 +00:00
},
"uint_val": {
"type": "number"
}
},
"additionalProperties": false
}`
2023-01-13 18:25:42 +00:00
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-17 14:34:49 +00:00
func TestStructOfStructsSchema(t *testing.T) {
type Bar struct {
A int `json:"a"`
B string `json:"b,string"`
}
type Foo struct {
Bar Bar `json:"bar"`
}
type MyStruct struct {
Foo Foo `json:"foo"`
}
elem := MyStruct{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"foo": {
"type": "object",
"properties": {
"bar": {
"type": "object",
"properties": {
"a": {
"type": "number"
},
"b": {
"type": "string"
}
},
"additionalProperties": false
2023-01-17 14:34:49 +00:00
}
},
"additionalProperties": false
2023-01-17 14:34:49 +00:00
}
},
"additionalProperties": false
2023-01-17 14:34:49 +00:00
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestStructOfMapsSchema(t *testing.T) {
type Bar struct {
MyMap map[string]int `json:"my_map"`
}
type Foo struct {
Bar Bar `json:"bar"`
}
elem := Foo{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"bar": {
"type": "object",
"properties": {
"my_map": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestStructOfSliceSchema(t *testing.T) {
type Bar struct {
MySlice []string `json:"my_slice"`
}
type Foo struct {
Bar Bar `json:"bar"`
}
elem := Foo{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"bar": {
"type": "object",
"properties": {
"my_slice": {
"type": "array",
"items": {
"type": "string"
}
}
},
"additionalProperties": false
}
},
"additionalProperties": false
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-17 14:47:31 +00:00
func TestMapOfPrimitivesSchema(t *testing.T) {
var elem map[string]int
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"additionalProperties": {
"type": "number"
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestMapOfStructSchema(t *testing.T) {
type Foo struct {
MyInt int `json:"my_int"`
}
var elem map[string]Foo
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"my_int": {
"type": "number"
}
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-17 16:57:48 +00:00
func TestMapOfMapSchema(t *testing.T) {
var elem map[string]map[string]int
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"additionalProperties": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-17 16:59:58 +00:00
func TestMapOfSliceSchema(t *testing.T) {
var elem map[string][]string
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"additionalProperties": {
"type": "array",
"items": {
"type": "string"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestSliceOfPrimitivesSchema(t *testing.T) {
var elem []float32
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "array",
"items": {
"type": "number"
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestSliceOfSliceSchema(t *testing.T) {
var elem [][]string
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "array",
"items": {
"type": "array",
"items": {
"type": "string"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestSliceOfMapSchema(t *testing.T) {
var elem []map[string]int
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "array",
"items": {
"type": "object",
"additionalProperties": {
"type": "number"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestSliceOfStructSchema(t *testing.T) {
type Foo struct {
MyInt int `json:"my_int"`
}
var elem []Foo
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "array",
"items": {
"type": "object",
"properties": {
"my_int": {
"type": "number"
}
},
"additionalProperties": false
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
func TestObjectSchema(t *testing.T) {
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
}
type Plot struct {
Stakes []string `json:"stakes"`
}
type Story struct {
Hero Person `json:"hero"`
Villian Person `json:"villian"`
Plot Plot `json:"plot"`
}
elem := Story{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"hero": {
"type": "object",
"properties": {
"age": {
"type": "number"
},
"name": {
"type": "string"
}
}
},
"plot": {
"type": "object",
"properties": {
"stakes": {
"type": "array",
2023-01-13 16:28:46 +00:00
"items": {
"type": "string"
}
}
}
},
"villian": {
"type": "object",
"properties": {
"age": {
"type": "number"
},
"name": {
"type": "string"
}
}
}
}
}`
2023-01-13 18:25:42 +00:00
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-13 17:01:53 +00:00
2023-01-13 18:26:50 +00:00
func TestEmbeddedStructSchema(t *testing.T) {
2023-01-13 18:25:42 +00:00
type Person struct {
Name string `json:"name"`
Age int `json:"age,omitempty"`
}
type Location struct {
Country string `json:"country"`
2023-01-13 18:26:50 +00:00
State string `json:"state,omitempty"`
2023-01-13 18:25:42 +00:00
}
type Plot struct {
Events map[string]Person `json:"events"`
}
type Story struct {
Plot Plot `json:"plot"`
*Person
Location
}
elem := Story{}
schema, err := NewSchema(reflect.TypeOf(elem))
assert.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expected :=
`{
"type": "object",
"properties": {
"age": {
"type": "number"
},
"country": {
"type": "string"
},
"name": {
"type": "string"
},
"plot": {
"type": "object",
"properties": {
"events": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"age": {
"type": "number"
},
"name": {
"type": "string"
}
}
}
}
}
},
"state": {
"type": "string"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expected)
2023-01-13 17:01:53 +00:00
assert.Equal(t, expected, string(jsonSchema))
}
2023-01-13 19:03:24 +00:00
2023-01-16 12:18:56 +00:00
func TestErrorWithTrace(t *testing.T) {
debugTrace := list.New()
err := errWithTrace("with empty trace", debugTrace)
assert.ErrorContains(t, err, "[ERROR] with empty trace. traversal trace: root")
debugTrace.PushBack("resources")
err = errWithTrace("with depth = 1", debugTrace)
assert.ErrorContains(t, err, "[ERROR] with depth = 1. traversal trace: root -> resources")
debugTrace.PushBack("pipelines")
debugTrace.PushBack("datasets")
err = errWithTrace("with depth = 4", debugTrace)
assert.ErrorContains(t, err, "[ERROR] with depth = 4. traversal trace: root -> resources -> pipelines -> datasets")
}
func TestNonAnnotatedFieldsAreSkipped(t *testing.T) {
type MyStruct struct {
Foo string
Bar int `json:"bar"`
}
elem := MyStruct{}
schema, err := NewSchema(reflect.TypeOf(elem))
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"bar": {
"type": "number"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
func TestDashFieldsAreSkipped(t *testing.T) {
type MyStruct struct {
Foo string `json:"-"`
Bar int `json:"bar"`
}
elem := MyStruct{}
schema, err := NewSchema(reflect.TypeOf(elem))
require.NoError(t, err)
jsonSchema, err := json.MarshalIndent(schema, " ", " ")
assert.NoError(t, err)
expectedSchema :=
`{
"type": "object",
"properties": {
"bar": {
"type": "number"
}
}
}`
t.Log("[DEBUG] actual: ", string(jsonSchema))
t.Log("[DEBUG] expected: ", expectedSchema)
assert.Equal(t, expectedSchema, string(jsonSchema))
}
2023-01-16 01:30:41 +00:00
// // Only for testing bundle, will be removed
// func TestBundleSchema(t *testing.T) {
// elem := config.Root{}
2023-01-13 19:03:24 +00:00
2023-01-16 01:30:41 +00:00
// schema, err := NewSchema(reflect.TypeOf(elem))
// assert.NoError(t, err)
2023-01-13 19:03:24 +00:00
2023-01-16 01:30:41 +00:00
// jsonSchema, err := json.MarshalIndent(schema, " ", " ")
// assert.NoError(t, err)
2023-01-13 19:03:24 +00:00
2023-01-16 01:30:41 +00:00
// expected :=
// ``
2023-01-13 19:03:24 +00:00
2023-01-16 01:30:41 +00:00
// t.Log("[DEBUG] actual: ", string(jsonSchema))
// t.Log("[DEBUG] expected: ", expected)
// assert.Equal(t, expected, string(jsonSchema))
// }