github.com/NVIDIA/aistore@v1.3.23-0.20240517131212-7df6609be51d/cmn/tests/iter_fields_test.go (about)

     1  // Package test provides tests for common low-level types and utilities for all aistore projects
     2  /*
     3   * Copyright (c) 2018-2024, NVIDIA CORPORATION. All rights reserved.
     4   */
     5  package tests_test
     6  
     7  import (
     8  	"github.com/NVIDIA/aistore/api/apc"
     9  	"github.com/NVIDIA/aistore/cmn"
    10  	"github.com/NVIDIA/aistore/cmn/cos"
    11  	"github.com/NVIDIA/aistore/cmn/feat"
    12  	. "github.com/onsi/ginkgo/v2"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  var _ = Describe("IterFields", func() {
    17  	type (
    18  		Foo struct {
    19  			A int `list:"omit"`
    20  			B int `json:"b"`
    21  		}
    22  		bar struct {
    23  			Foo Foo    `json:"foo"`
    24  			C   string `json:"c"`
    25  		}
    26  		barInline struct {
    27  			Foo `json:",inline"`
    28  			C   string `json:"c"`
    29  		}
    30  	)
    31  
    32  	Describe("IterFields", func() {
    33  		DescribeTable("should successfully iterate fields in structs",
    34  			func(v any, expected map[string]any) {
    35  				got := make(map[string]any)
    36  				err := cmn.IterFields(v, func(tag string, field cmn.IterField) (error, bool) {
    37  					got[tag] = field.Value()
    38  					return nil, false
    39  				})
    40  				Expect(err).NotTo(HaveOccurred())
    41  				Expect(got).To(Equal(expected))
    42  			},
    43  			Entry("list BucketProps fields",
    44  				cmn.Bprops{
    45  					Provider: apc.AIS,
    46  					BackendBck: cmn.Bck{
    47  						Name:     "name",
    48  						Provider: apc.GCP,
    49  					},
    50  					EC: cmn.ECConf{
    51  						Enabled:      true,
    52  						ParitySlices: 1024,
    53  					},
    54  					LRU: cmn.LRUConf{},
    55  					Cksum: cmn.CksumConf{
    56  						Type: cos.ChecksumXXHash,
    57  					},
    58  					Extra: cmn.ExtraProps{
    59  						AWS: cmn.ExtraPropsAWS{CloudRegion: "us-central"},
    60  					},
    61  				},
    62  				map[string]any{
    63  					"provider": apc.AIS,
    64  
    65  					"backend_bck.name":     "name",
    66  					"backend_bck.provider": apc.GCP,
    67  
    68  					"mirror.enabled":      false,
    69  					"mirror.copies":       int64(0),
    70  					"mirror.burst_buffer": 0,
    71  
    72  					"ec.enabled":           true,
    73  					"ec.parity_slices":     1024,
    74  					"ec.data_slices":       0,
    75  					"ec.objsize_limit":     int64(0),
    76  					"ec.compression":       "",
    77  					"ec.bundle_multiplier": 0,
    78  					"ec.disk_only":         false,
    79  
    80  					"versioning.enabled":           false,
    81  					"versioning.validate_warm_get": false,
    82  					"versioning.synchronize":       false,
    83  
    84  					"checksum.type":              cos.ChecksumXXHash,
    85  					"checksum.validate_warm_get": false,
    86  					"checksum.validate_cold_get": false,
    87  					"checksum.validate_obj_move": false,
    88  					"checksum.enable_read_range": false,
    89  
    90  					"lru.enabled":           false,
    91  					"lru.dont_evict_time":   cos.Duration(0),
    92  					"lru.capacity_upd_time": cos.Duration(0),
    93  
    94  					"extra.aws.cloud_region": "us-central",
    95  					"extra.aws.endpoint":     "",
    96  					"extra.aws.profile":      "",
    97  					"extra.aws.max_pagesize": int64(0),
    98  
    99  					"access":   apc.AccessAttrs(0),
   100  					"features": feat.Flags(0),
   101  					"created":  int64(0),
   102  
   103  					"write_policy.data": apc.WritePolicy(""),
   104  					"write_policy.md":   apc.WritePolicy(""),
   105  				},
   106  			),
   107  			Entry("list BpropsToSet fields",
   108  				&cmn.BpropsToSet{
   109  					EC: &cmn.ECConfToSet{
   110  						Enabled:      apc.Ptr(true),
   111  						ParitySlices: apc.Ptr(1024),
   112  					},
   113  					LRU: &cmn.LRUConfToSet{},
   114  					Cksum: &cmn.CksumConfToSet{
   115  						Type: apc.Ptr(cos.ChecksumXXHash),
   116  					},
   117  					Access:   apc.Ptr[apc.AccessAttrs](1024),
   118  					Features: apc.Ptr[feat.Flags](1024),
   119  					WritePolicy: &cmn.WritePolicyConfToSet{
   120  						MD: apc.Ptr(apc.WriteDelayed),
   121  					},
   122  				},
   123  				map[string]any{
   124  					"backend_bck.name":     (*string)(nil),
   125  					"backend_bck.provider": (*string)(nil),
   126  
   127  					"mirror.enabled":      (*bool)(nil),
   128  					"mirror.copies":       (*int64)(nil),
   129  					"mirror.burst_buffer": (*int)(nil),
   130  
   131  					"ec.enabled":           apc.Ptr(true),
   132  					"ec.parity_slices":     apc.Ptr(1024),
   133  					"ec.data_slices":       (*int)(nil),
   134  					"ec.objsize_limit":     (*int64)(nil),
   135  					"ec.compression":       (*string)(nil),
   136  					"ec.bundle_multiplier": (*int)(nil),
   137  					"ec.disk_only":         (*bool)(nil),
   138  
   139  					"versioning.enabled":           (*bool)(nil),
   140  					"versioning.validate_warm_get": (*bool)(nil),
   141  					"versioning.synchronize":       (*bool)(nil),
   142  
   143  					"checksum.type":              apc.Ptr(cos.ChecksumXXHash),
   144  					"checksum.validate_warm_get": (*bool)(nil),
   145  					"checksum.validate_cold_get": (*bool)(nil),
   146  					"checksum.validate_obj_move": (*bool)(nil),
   147  					"checksum.enable_read_range": (*bool)(nil),
   148  
   149  					"lru.enabled":           (*bool)(nil),
   150  					"lru.dont_evict_time":   (*cos.Duration)(nil),
   151  					"lru.capacity_upd_time": (*cos.Duration)(nil),
   152  
   153  					"access":   apc.Ptr[apc.AccessAttrs](1024),
   154  					"features": apc.Ptr[feat.Flags](1024),
   155  
   156  					"write_policy.data": (*apc.WritePolicy)(nil),
   157  					"write_policy.md":   apc.Ptr(apc.WriteDelayed),
   158  
   159  					"extra.hdfs.ref_directory": (*string)(nil),
   160  					"extra.aws.cloud_region":   (*string)(nil),
   161  					"extra.aws.endpoint":       (*string)(nil),
   162  					"extra.aws.profile":        (*string)(nil),
   163  					"extra.aws.max_pagesize":   (*int64)(nil),
   164  					"extra.http.original_url":  (*string)(nil),
   165  				},
   166  			),
   167  			Entry("check for omit tag",
   168  				Foo{A: 1, B: 2},
   169  				map[string]any{
   170  					"b": 2,
   171  				},
   172  			),
   173  		)
   174  
   175  		It("list all the fields (not only leafs)", func() {
   176  			v := bar{Foo: Foo{A: 3, B: 10}, C: "string"}
   177  			expected := map[string]any{
   178  				"foo.b": 10,
   179  				"foo":   Foo{A: 3, B: 10},
   180  				"c":     "string",
   181  			}
   182  
   183  			got := make(map[string]any)
   184  			err := cmn.IterFields(v, func(tag string, field cmn.IterField) (error, bool) {
   185  				got[tag] = field.Value()
   186  				return nil, false
   187  			}, cmn.IterOpts{VisitAll: true})
   188  			Expect(err).NotTo(HaveOccurred())
   189  			Expect(got).To(Equal(expected))
   190  		})
   191  
   192  		It("list inline fields", func() {
   193  			v := barInline{Foo: Foo{A: 3, B: 10}, C: "string"}
   194  			expected := map[string]any{
   195  				"b": 10,
   196  				"":  Foo{A: 3, B: 10},
   197  				"c": "string",
   198  			}
   199  
   200  			got := make(map[string]any)
   201  			err := cmn.IterFields(v, func(tag string, field cmn.IterField) (error, bool) {
   202  				got[tag] = field.Value()
   203  				return nil, false
   204  			}, cmn.IterOpts{VisitAll: true})
   205  			Expect(err).NotTo(HaveOccurred())
   206  			Expect(got).To(Equal(expected))
   207  		})
   208  	})
   209  
   210  	Describe("UpdateFieldValue", func() {
   211  		DescribeTable("should successfully update the fields in struct",
   212  			func(v any, values map[string]any, expected any) {
   213  				for name, value := range values {
   214  					err := cmn.UpdateFieldValue(v, name, value)
   215  					Expect(err).NotTo(HaveOccurred())
   216  				}
   217  				Expect(v).To(Equal(expected))
   218  			},
   219  			Entry("update some BucketProps",
   220  				&cmn.Bprops{
   221  					Versioning: cmn.VersionConf{
   222  						ValidateWarmGet: true,
   223  					},
   224  				},
   225  				map[string]any{
   226  					"mirror.enabled":      "true", // type == bool
   227  					"mirror.copies":       "120",  // type == int
   228  					"mirror.burst_buffer": "9560", // type == int64
   229  
   230  					"ec.enabled":       true,
   231  					"ec.parity_slices": 1024,
   232  					"ec.objsize_limit": int64(0),
   233  					"ec.compression":   "",
   234  
   235  					"versioning.enabled": false,
   236  
   237  					"checksum.type": cos.ChecksumXXHash,
   238  
   239  					"access":          "12", // type == uint64
   240  					"write_policy.md": apc.WriteNever,
   241  				},
   242  				&cmn.Bprops{
   243  					Mirror: cmn.MirrorConf{
   244  						Enabled: true,
   245  						Copies:  120,
   246  						Burst:   9560,
   247  					},
   248  					EC: cmn.ECConf{
   249  						Enabled:      true,
   250  						ParitySlices: 1024,
   251  					},
   252  					LRU: cmn.LRUConf{},
   253  					Cksum: cmn.CksumConf{
   254  						Type: cos.ChecksumXXHash,
   255  					},
   256  					Versioning: cmn.VersionConf{
   257  						Enabled:         false,
   258  						ValidateWarmGet: true,
   259  					},
   260  					Access:      12,
   261  					WritePolicy: cmn.WritePolicyConf{MD: apc.WriteNever},
   262  				},
   263  			),
   264  			Entry("update some BpropsToSet",
   265  				&cmn.BpropsToSet{
   266  					Cksum: &cmn.CksumConfToSet{
   267  						ValidateWarmGet: apc.Ptr(true),
   268  					},
   269  				},
   270  				map[string]any{
   271  					"mirror.enabled":      "true", // type == bool
   272  					"mirror.copies":       "120",  // type == int
   273  					"mirror.burst_buffer": "9560", // type == int64
   274  
   275  					"ec.enabled":       true,
   276  					"ec.parity_slices": 1024,
   277  					"ec.objsize_limit": int64(0),
   278  					"ec.compression":   "",
   279  
   280  					"versioning.enabled": false,
   281  
   282  					"checksum.type": cos.ChecksumXXHash,
   283  
   284  					"access":          "12", // type == uint64
   285  					"write_policy.md": apc.WriteNever,
   286  				},
   287  				&cmn.BpropsToSet{
   288  					Versioning: &cmn.VersionConfToSet{
   289  						Enabled: apc.Ptr(false),
   290  					},
   291  					Mirror: &cmn.MirrorConfToSet{
   292  						Enabled: apc.Ptr(true),
   293  						Copies:  apc.Ptr[int64](120),
   294  						Burst:   apc.Ptr(9560),
   295  					},
   296  					EC: &cmn.ECConfToSet{
   297  						Enabled:      apc.Ptr(true),
   298  						ParitySlices: apc.Ptr(1024),
   299  						ObjSizeLimit: apc.Ptr[int64](0),
   300  						Compression:  apc.Ptr(""),
   301  					},
   302  					Cksum: &cmn.CksumConfToSet{
   303  						Type:            apc.Ptr(cos.ChecksumXXHash),
   304  						ValidateWarmGet: apc.Ptr(true),
   305  					},
   306  					Access: apc.Ptr[apc.AccessAttrs](12),
   307  					WritePolicy: &cmn.WritePolicyConfToSet{
   308  						MD: apc.Ptr(apc.WriteNever),
   309  					},
   310  				},
   311  			),
   312  		)
   313  
   314  		DescribeTable("should error on update",
   315  			func(v any, values map[string]any) {
   316  				for name, value := range values {
   317  					err := cmn.UpdateFieldValue(v, name, value)
   318  					Expect(err).To(HaveOccurred())
   319  				}
   320  			},
   321  			Entry("non-pointer struct", cmn.Bprops{}, map[string]any{
   322  				"mirror.enabled": true,
   323  			}),
   324  			Entry("readonly field", &cmn.Bprops{}, map[string]any{
   325  				"provider": apc.AIS,
   326  			}),
   327  			Entry("field not found", &Foo{}, map[string]any{
   328  				"foo.bar": 2,
   329  			}),
   330  		)
   331  
   332  		DescribeTable("should error on update",
   333  			func(orig *cmn.ConfigToSet, merge *cmn.ConfigToSet, expected *cmn.ConfigToSet) {
   334  				orig.Merge(merge)
   335  				Expect(orig).To(Equal(expected))
   336  			},
   337  			Entry("override configuration", &cmn.ConfigToSet{
   338  				Mirror: &cmn.MirrorConfToSet{
   339  					Enabled: apc.Ptr(true),
   340  					Copies:  apc.Ptr[int64](2),
   341  				},
   342  			}, &cmn.ConfigToSet{
   343  				Mirror: &cmn.MirrorConfToSet{
   344  					Enabled: apc.Ptr(false),
   345  				},
   346  			}, &cmn.ConfigToSet{
   347  				Mirror: &cmn.MirrorConfToSet{
   348  					Enabled: apc.Ptr(false),
   349  					Copies:  apc.Ptr[int64](2),
   350  				},
   351  			}),
   352  
   353  			Entry("add new fields", &cmn.ConfigToSet{
   354  				Mirror: &cmn.MirrorConfToSet{
   355  					Enabled: apc.Ptr(true),
   356  					Copies:  apc.Ptr[int64](2),
   357  				},
   358  			}, &cmn.ConfigToSet{
   359  				Mirror: &cmn.MirrorConfToSet{
   360  					Enabled: apc.Ptr(false),
   361  				},
   362  				EC: &cmn.ECConfToSet{
   363  					Enabled: apc.Ptr(true),
   364  				},
   365  			}, &cmn.ConfigToSet{
   366  				Mirror: &cmn.MirrorConfToSet{
   367  					Enabled: apc.Ptr(false),
   368  					Copies:  apc.Ptr[int64](2),
   369  				},
   370  				EC: &cmn.ECConfToSet{
   371  					Enabled: apc.Ptr(true),
   372  				},
   373  			}),
   374  
   375  			Entry("nested fields", &cmn.ConfigToSet{
   376  				Net: &cmn.NetConfToSet{
   377  					HTTP: &cmn.HTTPConfToSet{
   378  						Certificate: apc.Ptr("secret"),
   379  					},
   380  				},
   381  			}, &cmn.ConfigToSet{
   382  				Net: &cmn.NetConfToSet{
   383  					HTTP: &cmn.HTTPConfToSet{
   384  						UseHTTPS: apc.Ptr(true),
   385  					},
   386  				},
   387  			}, &cmn.ConfigToSet{
   388  				Net: &cmn.NetConfToSet{
   389  					HTTP: &cmn.HTTPConfToSet{
   390  						Certificate: apc.Ptr("secret"),
   391  						UseHTTPS:    apc.Ptr(true),
   392  					},
   393  				},
   394  			}),
   395  		)
   396  	})
   397  })