schema_test.go 6.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226
  1. package config
  2. import (
  3. "testing"
  4. )
  5. // Test structs that mirror the actual configuration structure
  6. type TestBaseConfigForSchema struct {
  7. Enabled bool `json:"enabled"`
  8. ScanIntervalSeconds int `json:"scan_interval_seconds"`
  9. MaxConcurrent int `json:"max_concurrent"`
  10. }
  11. // ApplySchemaDefaults implements ConfigWithDefaults for test struct
  12. func (c *TestBaseConfigForSchema) ApplySchemaDefaults(schema *Schema) error {
  13. return schema.ApplyDefaultsToProtobuf(c)
  14. }
  15. // Validate implements ConfigWithDefaults for test struct
  16. func (c *TestBaseConfigForSchema) Validate() error {
  17. return nil
  18. }
  19. type TestTaskConfigForSchema struct {
  20. TestBaseConfigForSchema
  21. TaskSpecificField float64 `json:"task_specific_field"`
  22. AnotherSpecificField string `json:"another_specific_field"`
  23. }
  24. // ApplySchemaDefaults implements ConfigWithDefaults for test struct
  25. func (c *TestTaskConfigForSchema) ApplySchemaDefaults(schema *Schema) error {
  26. return schema.ApplyDefaultsToProtobuf(c)
  27. }
  28. // Validate implements ConfigWithDefaults for test struct
  29. func (c *TestTaskConfigForSchema) Validate() error {
  30. return nil
  31. }
  32. func createTestSchema() *Schema {
  33. return &Schema{
  34. Fields: []*Field{
  35. {
  36. Name: "enabled",
  37. JSONName: "enabled",
  38. Type: FieldTypeBool,
  39. DefaultValue: true,
  40. },
  41. {
  42. Name: "scan_interval_seconds",
  43. JSONName: "scan_interval_seconds",
  44. Type: FieldTypeInt,
  45. DefaultValue: 1800,
  46. },
  47. {
  48. Name: "max_concurrent",
  49. JSONName: "max_concurrent",
  50. Type: FieldTypeInt,
  51. DefaultValue: 3,
  52. },
  53. {
  54. Name: "task_specific_field",
  55. JSONName: "task_specific_field",
  56. Type: FieldTypeFloat,
  57. DefaultValue: 0.25,
  58. },
  59. {
  60. Name: "another_specific_field",
  61. JSONName: "another_specific_field",
  62. Type: FieldTypeString,
  63. DefaultValue: "default_value",
  64. },
  65. },
  66. }
  67. }
  68. func TestApplyDefaults_WithEmbeddedStruct(t *testing.T) {
  69. schema := createTestSchema()
  70. // Start with zero values
  71. config := &TestTaskConfigForSchema{}
  72. err := schema.ApplyDefaultsToConfig(config)
  73. if err != nil {
  74. t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
  75. }
  76. // Verify embedded struct fields got default values
  77. if config.Enabled != true {
  78. t.Errorf("Expected Enabled=true (default), got %v", config.Enabled)
  79. }
  80. if config.ScanIntervalSeconds != 1800 {
  81. t.Errorf("Expected ScanIntervalSeconds=1800 (default), got %v", config.ScanIntervalSeconds)
  82. }
  83. if config.MaxConcurrent != 3 {
  84. t.Errorf("Expected MaxConcurrent=3 (default), got %v", config.MaxConcurrent)
  85. }
  86. // Verify task-specific fields got default values
  87. if config.TaskSpecificField != 0.25 {
  88. t.Errorf("Expected TaskSpecificField=0.25 (default), got %v", config.TaskSpecificField)
  89. }
  90. if config.AnotherSpecificField != "default_value" {
  91. t.Errorf("Expected AnotherSpecificField='default_value' (default), got %v", config.AnotherSpecificField)
  92. }
  93. }
  94. func TestApplyDefaults_PartiallySet(t *testing.T) {
  95. schema := createTestSchema()
  96. // Start with some pre-set values
  97. config := &TestTaskConfigForSchema{
  98. TestBaseConfigForSchema: TestBaseConfigForSchema{
  99. Enabled: true, // Non-zero value, should not be overridden
  100. ScanIntervalSeconds: 0, // Should get default
  101. MaxConcurrent: 5, // Non-zero value, should not be overridden
  102. },
  103. TaskSpecificField: 0.0, // Should get default
  104. AnotherSpecificField: "custom", // Non-zero value, should not be overridden
  105. }
  106. err := schema.ApplyDefaultsToConfig(config)
  107. if err != nil {
  108. t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
  109. }
  110. // Verify already-set values are preserved
  111. if config.Enabled != true {
  112. t.Errorf("Expected Enabled=true (pre-set), got %v", config.Enabled)
  113. }
  114. if config.MaxConcurrent != 5 {
  115. t.Errorf("Expected MaxConcurrent=5 (pre-set), got %v", config.MaxConcurrent)
  116. }
  117. if config.AnotherSpecificField != "custom" {
  118. t.Errorf("Expected AnotherSpecificField='custom' (pre-set), got %v", config.AnotherSpecificField)
  119. }
  120. // Verify zero values got defaults
  121. if config.ScanIntervalSeconds != 1800 {
  122. t.Errorf("Expected ScanIntervalSeconds=1800 (default), got %v", config.ScanIntervalSeconds)
  123. }
  124. if config.TaskSpecificField != 0.25 {
  125. t.Errorf("Expected TaskSpecificField=0.25 (default), got %v", config.TaskSpecificField)
  126. }
  127. }
  128. func TestApplyDefaults_NonPointer(t *testing.T) {
  129. schema := createTestSchema()
  130. config := TestTaskConfigForSchema{}
  131. // This should fail since we need a pointer to modify the struct
  132. err := schema.ApplyDefaultsToProtobuf(config)
  133. if err == nil {
  134. t.Fatal("Expected error for non-pointer config, but got nil")
  135. }
  136. }
  137. func TestApplyDefaults_NonStruct(t *testing.T) {
  138. schema := createTestSchema()
  139. var config interface{} = "not a struct"
  140. err := schema.ApplyDefaultsToProtobuf(config)
  141. if err == nil {
  142. t.Fatal("Expected error for non-struct config, but got nil")
  143. }
  144. }
  145. func TestApplyDefaults_EmptySchema(t *testing.T) {
  146. schema := &Schema{Fields: []*Field{}}
  147. config := &TestTaskConfigForSchema{}
  148. err := schema.ApplyDefaultsToConfig(config)
  149. if err != nil {
  150. t.Fatalf("ApplyDefaultsToConfig failed for empty schema: %v", err)
  151. }
  152. // All fields should remain at zero values since no defaults are defined
  153. if config.Enabled != false {
  154. t.Errorf("Expected Enabled=false (zero value), got %v", config.Enabled)
  155. }
  156. }
  157. func TestApplyDefaults_MissingSchemaField(t *testing.T) {
  158. // Schema with fewer fields than the struct
  159. schema := &Schema{
  160. Fields: []*Field{
  161. {
  162. Name: "enabled",
  163. JSONName: "enabled",
  164. Type: FieldTypeBool,
  165. DefaultValue: true,
  166. },
  167. // Note: missing scan_interval_seconds and other fields
  168. },
  169. }
  170. config := &TestTaskConfigForSchema{}
  171. err := schema.ApplyDefaultsToConfig(config)
  172. if err != nil {
  173. t.Fatalf("ApplyDefaultsToConfig failed: %v", err)
  174. }
  175. // Only the field with a schema definition should get a default
  176. if config.Enabled != true {
  177. t.Errorf("Expected Enabled=true (has schema), got %v", config.Enabled)
  178. }
  179. // Fields without schema should remain at zero values
  180. if config.ScanIntervalSeconds != 0 {
  181. t.Errorf("Expected ScanIntervalSeconds=0 (no schema), got %v", config.ScanIntervalSeconds)
  182. }
  183. }
  184. func BenchmarkApplyDefaults(b *testing.B) {
  185. schema := createTestSchema()
  186. config := &TestTaskConfigForSchema{}
  187. b.ResetTimer()
  188. for i := 0; i < b.N; i++ {
  189. _ = schema.ApplyDefaultsToConfig(config)
  190. }
  191. }