aboutsummaryrefslogtreecommitdiff
path: root/weed/admin/config/schema_test.go
blob: 3d0d74a382fa3da30a95dca7e35209ef0d98f7b5 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
package config

import (
	"testing"
)

// Test structs that mirror the actual configuration structure
type TestBaseConfigForSchema struct {
	Enabled             bool `json:"enabled"`
	ScanIntervalSeconds int  `json:"scan_interval_seconds"`
	MaxConcurrent       int  `json:"max_concurrent"`
}

// ApplySchemaDefaults implements ConfigWithDefaults for test struct
func (c *TestBaseConfigForSchema) ApplySchemaDefaults(schema *Schema) error {
	return schema.ApplyDefaultsToProtobuf(c)
}

// Validate implements ConfigWithDefaults for test struct
func (c *TestBaseConfigForSchema) Validate() error {
	return nil
}

type TestTaskConfigForSchema struct {
	TestBaseConfigForSchema
	TaskSpecificField    float64 `json:"task_specific_field"`
	AnotherSpecificField string  `json:"another_specific_field"`
}

// ApplySchemaDefaults implements ConfigWithDefaults for test struct
func (c *TestTaskConfigForSchema) ApplySchemaDefaults(schema *Schema) error {
	return schema.ApplyDefaultsToProtobuf(c)
}

// Validate implements ConfigWithDefaults for test struct
func (c *TestTaskConfigForSchema) Validate() error {
	return nil
}

func createTestSchema() *Schema {
	return &Schema{
		Fields: []*Field{
			{
				Name:         "enabled",
				JSONName:     "enabled",
				Type:         FieldTypeBool,
				DefaultValue: true,
			},
			{
				Name:         "scan_interval_seconds",
				JSONName:     "scan_interval_seconds",
				Type:         FieldTypeInt,
				DefaultValue: 1800,
			},
			{
				Name:         "max_concurrent",
				JSONName:     "max_concurrent",
				Type:         FieldTypeInt,
				DefaultValue: 3,
			},
			{
				Name:         "task_specific_field",
				JSONName:     "task_specific_field",
				Type:         FieldTypeFloat,
				DefaultValue: 0.25,
			},
			{
				Name:         "another_specific_field",
				JSONName:     "another_specific_field",
				Type:         FieldTypeString,
				DefaultValue: "default_value",
			},
		},
	}
}

func TestApplyDefaults_WithEmbeddedStruct(t *testing.T) {
	schema := createTestSchema()

	// Start with zero values
	config := &TestTaskConfigForSchema{}

	err := schema.ApplyDefaultsToConfig(config)
	if err != nil {
		t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
	}

	// Verify embedded struct fields got default values
	if config.Enabled != true {
		t.Errorf("Expected Enabled=true (default), got %v", config.Enabled)
	}

	if config.ScanIntervalSeconds != 1800 {
		t.Errorf("Expected ScanIntervalSeconds=1800 (default), got %v", config.ScanIntervalSeconds)
	}

	if config.MaxConcurrent != 3 {
		t.Errorf("Expected MaxConcurrent=3 (default), got %v", config.MaxConcurrent)
	}

	// Verify task-specific fields got default values
	if config.TaskSpecificField != 0.25 {
		t.Errorf("Expected TaskSpecificField=0.25 (default), got %v", config.TaskSpecificField)
	}

	if config.AnotherSpecificField != "default_value" {
		t.Errorf("Expected AnotherSpecificField='default_value' (default), got %v", config.AnotherSpecificField)
	}
}

func TestApplyDefaults_PartiallySet(t *testing.T) {
	schema := createTestSchema()

	// Start with some pre-set values
	config := &TestTaskConfigForSchema{
		TestBaseConfigForSchema: TestBaseConfigForSchema{
			Enabled:             true, // Non-zero value, should not be overridden
			ScanIntervalSeconds: 0,    // Should get default
			MaxConcurrent:       5,    // Non-zero value, should not be overridden
		},
		TaskSpecificField:    0.0,      // Should get default
		AnotherSpecificField: "custom", // Non-zero value, should not be overridden
	}

	err := schema.ApplyDefaultsToConfig(config)
	if err != nil {
		t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
	}

	// Verify already-set values are preserved
	if config.Enabled != true {
		t.Errorf("Expected Enabled=true (pre-set), got %v", config.Enabled)
	}

	if config.MaxConcurrent != 5 {
		t.Errorf("Expected MaxConcurrent=5 (pre-set), got %v", config.MaxConcurrent)
	}

	if config.AnotherSpecificField != "custom" {
		t.Errorf("Expected AnotherSpecificField='custom' (pre-set), got %v", config.AnotherSpecificField)
	}

	// Verify zero values got defaults
	if config.ScanIntervalSeconds != 1800 {
		t.Errorf("Expected ScanIntervalSeconds=1800 (default), got %v", config.ScanIntervalSeconds)
	}

	if config.TaskSpecificField != 0.25 {
		t.Errorf("Expected TaskSpecificField=0.25 (default), got %v", config.TaskSpecificField)
	}
}

func TestApplyDefaults_NonPointer(t *testing.T) {
	schema := createTestSchema()
	config := TestTaskConfigForSchema{}
	// This should fail since we need a pointer to modify the struct
	err := schema.ApplyDefaultsToProtobuf(config)
	if err == nil {
		t.Fatal("Expected error for non-pointer config, but got nil")
	}
}

func TestApplyDefaults_NonStruct(t *testing.T) {
	schema := createTestSchema()
	var config interface{} = "not a struct"
	err := schema.ApplyDefaultsToProtobuf(config)
	if err == nil {
		t.Fatal("Expected error for non-struct config, but got nil")
	}
}

func TestApplyDefaults_EmptySchema(t *testing.T) {
	schema := &Schema{Fields: []*Field{}}
	config := &TestTaskConfigForSchema{}

	err := schema.ApplyDefaultsToConfig(config)
	if err != nil {
		t.Fatalf("ApplyDefaultsToConfig failed for empty schema: %v", err)
	}

	// All fields should remain at zero values since no defaults are defined
	if config.Enabled != false {
		t.Errorf("Expected Enabled=false (zero value), got %v", config.Enabled)
	}
}

func TestApplyDefaults_MissingSchemaField(t *testing.T) {
	// Schema with fewer fields than the struct
	schema := &Schema{
		Fields: []*Field{
			{
				Name:         "enabled",
				JSONName:     "enabled",
				Type:         FieldTypeBool,
				DefaultValue: true,
			},
			// Note: missing scan_interval_seconds and other fields
		},
	}

	config := &TestTaskConfigForSchema{}
	err := schema.ApplyDefaultsToConfig(config)
	if err != nil {
		t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
	}

	// Only the field with a schema definition should get a default
	if config.Enabled != true {
		t.Errorf("Expected Enabled=true (has schema), got %v", config.Enabled)
	}

	// Fields without schema should remain at zero values
	if config.ScanIntervalSeconds != 0 {
		t.Errorf("Expected ScanIntervalSeconds=0 (no schema), got %v", config.ScanIntervalSeconds)
	}
}

func BenchmarkApplyDefaults(b *testing.B) {
	schema := createTestSchema()
	config := &TestTaskConfigForSchema{}

	b.ResetTimer()
	for i := 0; i < b.N; i++ {
		_ = schema.ApplyDefaultsToConfig(config)
	}
}