Skip to content

Commit

Permalink
feat(utils): allow choosing what fields to fill
Browse files Browse the repository at this point in the history
enhance the utils: FillPluginsDefaults* functions to allow individually
selecting whether to fill normal and auto fields with default values.
  • Loading branch information
samugi committed Sep 4, 2024
1 parent 45107a3 commit 76af65d
Show file tree
Hide file tree
Showing 2 changed files with 91 additions and 44 deletions.
56 changes: 28 additions & 28 deletions kong/utils.go
Original file line number Diff line number Diff line change
Expand Up @@ -278,9 +278,13 @@ func backfillResultConfigMap(res Configuration, path []string, configValue inter
return nil
}

type FillRecordOptions struct {
FillDefaults bool
FillAuto bool
}

// fills the config record with default values
// if oldConfig is provided, copies auto fields from it, into config
func fillConfigRecord(schema gjson.Result, config Configuration, oldConfig Configuration) Configuration {
func fillConfigRecord(schema gjson.Result, config Configuration, opts FillRecordOptions) Configuration {
res := config.DeepCopy()
configFields := schema.Get("fields")
// Fetch deprecated fields
Expand All @@ -297,7 +301,7 @@ func fillConfigRecord(schema gjson.Result, config Configuration, oldConfig Confi
}

if fname == "config" {
newConfig := fillConfigRecord(value.Get(fname), config, oldConfig)
newConfig := fillConfigRecord(value.Get(fname), config, opts)
res = newConfig
return true
}
Expand Down Expand Up @@ -350,7 +354,7 @@ func fillConfigRecord(schema gjson.Result, config Configuration, oldConfig Confi
default:
fieldConfig = subConfig.(map[string]interface{})
}
newSubConfig := fillConfigRecord(value.Get(fname), fieldConfig, oldConfig)
newSubConfig := fillConfigRecord(value.Get(fname), fieldConfig, opts)
res[fname] = map[string]interface{}(newSubConfig)
return true
}
Expand All @@ -370,7 +374,7 @@ func fillConfigRecord(schema gjson.Result, config Configuration, oldConfig Confi
for i, configRecord := range subConfigArray {
// Check if element is of type record, if it is, set default values by recursively calling `fillConfigRecord`
if configRecordMap, ok := configRecord.(map[string]interface{}); ok {
processedConfigRecord := fillConfigRecord(value.Get(fname).Get("elements"), configRecordMap, oldConfig)
processedConfigRecord := fillConfigRecord(value.Get(fname).Get("elements"), configRecordMap, opts)
processedSubConfigArray[i] = processedConfigRecord
continue
}
Expand All @@ -384,17 +388,17 @@ func fillConfigRecord(schema gjson.Result, config Configuration, oldConfig Confi
}
}

// handle `auto` fields by copying them from oldConfig if they don't have
// a value. When fields marked as `auto` are passed to kong without a value
// they are auto generated by the gateway. In that case, comparing with
// "defaults" doesn't work, so in order to compute a correct diff they must
// be copied from the oldConfig.
auto := value.Get(fname + ".auto")
if auto.Exists() && auto.Bool() && oldConfig != nil {
if v, ok := oldConfig[fname]; ok {
res[fname] = v
return true
}
isAuto := auto.Exists() && auto.Bool()

// if this is an auto field and we are not filling auto fields, skip
if !opts.FillAuto && isAuto {
return true
}

// if this is a normal field and we are not filling defaults, skip
if !opts.FillDefaults && !isAuto {
return true
}

// Check if the record has a default value for the specified field.
Expand Down Expand Up @@ -680,7 +684,7 @@ func FillEntityDefaults(entity interface{}, schema Schema) error {
return nil
}

func fillConfigRecordDefaultsAutoFields(plugin *Plugin, schema map[string]interface{}, oldPlugin *Plugin) error {
func fillConfigRecordDefaultsAutoFields(plugin *Plugin, schema map[string]interface{}, opts FillRecordOptions) error {
jsonb, err := json.Marshal(&schema)
if err != nil {
return err
Expand All @@ -694,11 +698,7 @@ func fillConfigRecordDefaultsAutoFields(plugin *Plugin, schema map[string]interf
plugin.Config = make(Configuration)
}

var oldConfig Configuration
if oldPlugin != nil {
oldConfig = oldPlugin.Config
}
plugin.Config = fillConfigRecord(configSchema, plugin.Config, oldConfig)
plugin.Config = fillConfigRecord(configSchema, plugin.Config, opts)
if plugin.Protocols == nil {
plugin.Protocols = getDefaultProtocols(gjsonSchema)
}
Expand All @@ -711,13 +711,13 @@ func fillConfigRecordDefaultsAutoFields(plugin *Plugin, schema map[string]interf
// FillPluginsDefaults ingests plugin's defaults from its schema.
// Takes in a plugin struct and mutate it in place.
func FillPluginsDefaults(plugin *Plugin, schema Schema) error {
return fillConfigRecordDefaultsAutoFields(plugin, schema, nil)
return fillConfigRecordDefaultsAutoFields(plugin, schema, FillRecordOptions{
FillDefaults: true,
FillAuto: true,
})
}

// same as FillPluginsDefaults but also fills auto fields.
// `oldPlugin` (which repsesents the plugin from the old/existing Kong config
// is used to copy auto fields from it when they are not set in `plugin“.
// keeping both for compatibility: these utils are public
func FillPluginsDefaultsAutoFields(plugin *Plugin, schema map[string]interface{}, oldPlugin *Plugin) error {
return fillConfigRecordDefaultsAutoFields(plugin, schema, oldPlugin)
// same as FillPluginsDefaults but allows configuring whether to fill defaults and auto fields.
func FillPluginsDefaultsWithOpts(plugin *Plugin, schema map[string]interface{}, opts FillRecordOptions) error {
return fillConfigRecordDefaultsAutoFields(plugin, schema, opts)
}
79 changes: 63 additions & 16 deletions kong/utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1836,7 +1836,10 @@ func Test_fillConfigRecord(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
configSchema, err := getConfigSchema(tc.schema)
require.NoError(t, err)
config := fillConfigRecord(configSchema, tc.config, nil)
config := fillConfigRecord(configSchema, tc.config, FillRecordOptions{
FillDefaults: true,
FillAuto: true,
})
require.NotNil(t, config)
if diff := cmp.Diff(config, tc.expected); diff != "" {
t.Errorf("unexpected diff:\n%s", diff)
Expand Down Expand Up @@ -1939,19 +1942,25 @@ const fillConfigRecordTestSchemaWithAutoFields = `{
"type": "record",
"fields": [
{
"foo_string": {
"default_string": {
"type": "string",
"default": "abc"
}
},
{
"auto_string_1": {
"type": "string",
"auto": true
}
},
{
"bar_string": {
"auto_string_2": {
"type": "string",
"auto": true
}
},
{
"baz_string": {
"auto_string_3": {
"type": "string",
"auto": true
}
Expand Down Expand Up @@ -2021,7 +2030,10 @@ func Test_fillConfigRecord_shorthand_fields(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
configSchema, err := getConfigSchema(tc.schema)
require.NoError(t, err)
config := fillConfigRecord(configSchema, tc.config, nil)
config := fillConfigRecord(configSchema, tc.config, FillRecordOptions{
FillDefaults: true,
FillAuto: true,
})
require.NotNil(t, config)
if diff := cmp.Diff(config, tc.expected); diff != "" {
t.Errorf("unexpected diff:\n%s", diff)
Expand All @@ -2030,23 +2042,22 @@ func Test_fillConfigRecord_shorthand_fields(t *testing.T) {
}
}

func Test_fillConfigRecord_auto_fields(t *testing.T) {
func Test_fillConfigRecord_defaults_only(t *testing.T) {
tests := []struct {
name string
schema gjson.Result
config Configuration
expected Configuration
}{
{
name: "fills auto fields with values from oldConfig",
name: "fills defaults with opts to fill defaults only",
schema: gjson.Parse(fillConfigRecordTestSchemaWithAutoFields),
config: Configuration{
"baz_string": "789",
"auto_string_3": "789",
},
expected: Configuration{
"foo_string": "123",
"bar_string": "456",
"baz_string": "789",
"default_string": "abc",
"auto_string_3": "789",
},
},
}
Expand All @@ -2055,12 +2066,48 @@ func Test_fillConfigRecord_auto_fields(t *testing.T) {
t.Run(tc.name, func(t *testing.T) {
configSchema, err := getConfigSchema(tc.schema)
require.NoError(t, err)
oldConfig := Configuration{
"foo_string": "123",
"bar_string": "456",
"baz_string": "000",
config := fillConfigRecord(configSchema, tc.config, FillRecordOptions{
FillDefaults: true,
FillAuto: false,
})
require.NotNil(t, config)
if diff := cmp.Diff(config, tc.expected); diff != "" {
t.Errorf("unexpected diff:\n%s", diff)
}
config := fillConfigRecord(configSchema, tc.config, oldConfig)
})
}
}

func Test_fillConfigRecord_auto_only(t *testing.T) {
tests := []struct {
name string
schema gjson.Result
config Configuration
expected Configuration
}{
{
name: "fills defaults with opts to fill auto only",
schema: gjson.Parse(fillConfigRecordTestSchemaWithAutoFields),
config: Configuration{
"auto_string_3": "789",
},
expected: Configuration{
"auto_string_1": nil,
"auto_string_2": nil,
"auto_string_3": "789",
// defalt_string missing
},
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
configSchema, err := getConfigSchema(tc.schema)
require.NoError(t, err)
config := fillConfigRecord(configSchema, tc.config, FillRecordOptions{
FillDefaults: false,
FillAuto: true,
})
require.NotNil(t, config)
if diff := cmp.Diff(config, tc.expected); diff != "" {
t.Errorf("unexpected diff:\n%s", diff)
Expand Down

0 comments on commit 76af65d

Please sign in to comment.