github.com/weaviate/weaviate@v1.24.6/adapters/repos/db/shard_skip_vector_reindex_test.go (about)

     1  //                           _       _
     2  // __      _____  __ ___   ___  __ _| |_ ___
     3  // \ \ /\ / / _ \/ _` \ \ / / |/ _` | __/ _ \
     4  //  \ V  V /  __/ (_| |\ V /| | (_| | ||  __/
     5  //   \_/\_/ \___|\__,_| \_/ |_|\__,_|\__\___|
     6  //
     7  //  Copyright © 2016 - 2024 Weaviate B.V. All rights reserved.
     8  //
     9  //  CONTACT: hello@weaviate.io
    10  //
    11  
    12  package db
    13  
    14  import (
    15  	"encoding/binary"
    16  	"fmt"
    17  	"testing"
    18  	"time"
    19  
    20  	"github.com/google/uuid"
    21  	"github.com/stretchr/testify/assert"
    22  	"github.com/weaviate/weaviate/entities/models"
    23  )
    24  
    25  func TestGeoPropsEqual(t *testing.T) {
    26  	type testCase struct {
    27  		prevProps     map[string]interface{}
    28  		nextProps     map[string]interface{}
    29  		expectedEqual bool
    30  	}
    31  
    32  	ptrFloat32 := func(f float32) *float32 {
    33  		return &f
    34  	}
    35  
    36  	testCases := []testCase{
    37  		{
    38  			prevProps:     map[string]interface{}{},
    39  			nextProps:     map[string]interface{}{},
    40  			expectedEqual: true,
    41  		},
    42  		{
    43  			prevProps: map[string]interface{}{
    44  				"notGeo": "abc",
    45  			},
    46  			nextProps: map[string]interface{}{
    47  				"notGeo": "def",
    48  			},
    49  			expectedEqual: true,
    50  		},
    51  		{
    52  			prevProps: map[string]interface{}{
    53  				"geo": nil,
    54  			},
    55  			nextProps: map[string]interface{}{
    56  				"geo": nil,
    57  			},
    58  			expectedEqual: true,
    59  		},
    60  		{
    61  			prevProps: map[string]interface{}{
    62  				"geo": &models.GeoCoordinates{
    63  					Latitude:  ptrFloat32(1.23),
    64  					Longitude: ptrFloat32(2.34),
    65  				},
    66  			},
    67  			nextProps: map[string]interface{}{
    68  				"geo": nil,
    69  			},
    70  			expectedEqual: false,
    71  		},
    72  		{
    73  			prevProps: map[string]interface{}{
    74  				"geo": &models.GeoCoordinates{
    75  					Latitude:  ptrFloat32(1.23),
    76  					Longitude: ptrFloat32(2.34),
    77  				},
    78  			},
    79  			nextProps:     map[string]interface{}{},
    80  			expectedEqual: false,
    81  		},
    82  		{
    83  			prevProps: map[string]interface{}{
    84  				"geo": nil,
    85  			},
    86  			nextProps: map[string]interface{}{
    87  				"geo": &models.GeoCoordinates{
    88  					Latitude:  ptrFloat32(1.23),
    89  					Longitude: ptrFloat32(2.34),
    90  				},
    91  			},
    92  			expectedEqual: false,
    93  		},
    94  		{
    95  			prevProps: map[string]interface{}{},
    96  			nextProps: map[string]interface{}{
    97  				"geo": &models.GeoCoordinates{
    98  					Latitude:  ptrFloat32(1.23),
    99  					Longitude: ptrFloat32(2.34),
   100  				},
   101  			},
   102  			expectedEqual: false,
   103  		},
   104  		{
   105  			prevProps: map[string]interface{}{
   106  				"geo": &models.GeoCoordinates{
   107  					Latitude:  ptrFloat32(1.23),
   108  					Longitude: ptrFloat32(2.34),
   109  				},
   110  			},
   111  			nextProps: map[string]interface{}{
   112  				"geo": &models.GeoCoordinates{
   113  					Latitude:  ptrFloat32(-1.23),
   114  					Longitude: ptrFloat32(2.34),
   115  				},
   116  			},
   117  			expectedEqual: false,
   118  		},
   119  		{
   120  			prevProps: map[string]interface{}{
   121  				"geo": &models.GeoCoordinates{
   122  					Latitude:  ptrFloat32(1.23),
   123  					Longitude: ptrFloat32(2.34),
   124  				},
   125  			},
   126  			nextProps: map[string]interface{}{
   127  				"geo": &models.GeoCoordinates{
   128  					Latitude:  ptrFloat32(1.23),
   129  					Longitude: ptrFloat32(-2.34),
   130  				},
   131  			},
   132  			expectedEqual: false,
   133  		},
   134  		{
   135  			prevProps: map[string]interface{}{
   136  				"geo": &models.GeoCoordinates{
   137  					Latitude:  ptrFloat32(1.23),
   138  					Longitude: ptrFloat32(2.34),
   139  				},
   140  			},
   141  			nextProps: map[string]interface{}{
   142  				"geo": &models.GeoCoordinates{
   143  					Latitude:  ptrFloat32(-1.23),
   144  					Longitude: ptrFloat32(-2.34),
   145  				},
   146  			},
   147  			expectedEqual: false,
   148  		},
   149  		{
   150  			prevProps: map[string]interface{}{
   151  				"geo": &models.GeoCoordinates{
   152  					Latitude:  ptrFloat32(1.23),
   153  					Longitude: ptrFloat32(2.34),
   154  				},
   155  			},
   156  			nextProps: map[string]interface{}{
   157  				"geo": &models.GeoCoordinates{
   158  					Latitude:  ptrFloat32(1.23),
   159  					Longitude: ptrFloat32(2.34),
   160  				},
   161  			},
   162  			expectedEqual: true,
   163  		},
   164  		{
   165  			prevProps: map[string]interface{}{
   166  				"geo": &models.GeoCoordinates{
   167  					Latitude:  ptrFloat32(1.23),
   168  					Longitude: ptrFloat32(2.34),
   169  				},
   170  			},
   171  			nextProps: map[string]interface{}{
   172  				"geo2": &models.GeoCoordinates{
   173  					Latitude:  ptrFloat32(1.23),
   174  					Longitude: ptrFloat32(2.34),
   175  				},
   176  			},
   177  			expectedEqual: false,
   178  		},
   179  		{
   180  			prevProps: map[string]interface{}{
   181  				"geo": &models.GeoCoordinates{
   182  					Latitude:  ptrFloat32(1.23),
   183  					Longitude: ptrFloat32(2.34),
   184  				},
   185  				"notGeo": "string",
   186  			},
   187  			nextProps: map[string]interface{}{
   188  				"geo": &models.GeoCoordinates{
   189  					Latitude:  ptrFloat32(1.23),
   190  					Longitude: ptrFloat32(2.34),
   191  				},
   192  				"notGeo": "otherString",
   193  			},
   194  			expectedEqual: true,
   195  		},
   196  		{
   197  			prevProps: map[string]interface{}{
   198  				"geo": &models.GeoCoordinates{
   199  					Latitude:  ptrFloat32(1.23),
   200  					Longitude: ptrFloat32(2.34),
   201  				},
   202  				"geo2": &models.GeoCoordinates{
   203  					Latitude:  ptrFloat32(4.56),
   204  					Longitude: ptrFloat32(5.67),
   205  				},
   206  			},
   207  			nextProps: map[string]interface{}{
   208  				"geo": &models.GeoCoordinates{
   209  					Latitude:  ptrFloat32(1.23),
   210  					Longitude: ptrFloat32(2.34),
   211  				},
   212  				"geo2": &models.GeoCoordinates{
   213  					Latitude:  ptrFloat32(4.56),
   214  					Longitude: ptrFloat32(5.67),
   215  				},
   216  			},
   217  			expectedEqual: true,
   218  		},
   219  		{
   220  			prevProps: map[string]interface{}{
   221  				"geo": &models.GeoCoordinates{
   222  					Latitude:  ptrFloat32(1.23),
   223  					Longitude: ptrFloat32(2.34),
   224  				},
   225  				"geo2": &models.GeoCoordinates{
   226  					Latitude:  ptrFloat32(4.56),
   227  					Longitude: ptrFloat32(5.67),
   228  				},
   229  			},
   230  			nextProps: map[string]interface{}{
   231  				"geo": &models.GeoCoordinates{
   232  					Latitude:  ptrFloat32(1.23),
   233  					Longitude: ptrFloat32(2.34),
   234  				},
   235  			},
   236  			expectedEqual: false,
   237  		},
   238  		{
   239  			prevProps: map[string]interface{}{
   240  				"geo": &models.GeoCoordinates{
   241  					Latitude:  ptrFloat32(1.23),
   242  					Longitude: ptrFloat32(2.34),
   243  				},
   244  				"geo2": &models.GeoCoordinates{
   245  					Latitude:  ptrFloat32(4.56),
   246  					Longitude: ptrFloat32(5.67),
   247  				},
   248  			},
   249  			nextProps: map[string]interface{}{
   250  				"geo": &models.GeoCoordinates{
   251  					Latitude:  ptrFloat32(1.23),
   252  					Longitude: ptrFloat32(2.34),
   253  				},
   254  				"geo2": &models.GeoCoordinates{
   255  					Latitude:  ptrFloat32(4.56),
   256  					Longitude: ptrFloat32(-5.67),
   257  				},
   258  			},
   259  			expectedEqual: false,
   260  		},
   261  		{
   262  			prevProps: map[string]interface{}{
   263  				"geoLike": map[string]interface{}{
   264  					"Latitude":  ptrFloat32(1.23),
   265  					"Longitude": ptrFloat32(2.34),
   266  				},
   267  			},
   268  			nextProps: map[string]interface{}{
   269  				"geoLike": map[string]interface{}{
   270  					"Latitude":  ptrFloat32(1.23),
   271  					"Longitude": ptrFloat32(2.34),
   272  				},
   273  			},
   274  			expectedEqual: true,
   275  		},
   276  	}
   277  
   278  	for i, tc := range testCases {
   279  		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
   280  			eq := geoPropsEqual(tc.prevProps, tc.nextProps)
   281  
   282  			if tc.expectedEqual {
   283  				assert.True(t, eq)
   284  			} else {
   285  				assert.False(t, eq)
   286  			}
   287  		})
   288  	}
   289  }
   290  
   291  func TestPropsEqual(t *testing.T) {
   292  	type testCase struct {
   293  		prevProps     map[string]interface{}
   294  		nextProps     map[string]interface{}
   295  		expectedEqual bool
   296  	}
   297  
   298  	_uuid := func(i int) uuid.UUID {
   299  		b := [16]byte{}
   300  		binary.BigEndian.PutUint64(b[:8], 0)
   301  		binary.BigEndian.PutUint64(b[8:], 1234567890+uint64(i))
   302  		return uuid.UUID(b)
   303  	}
   304  	_uuidAsText := func(i int) string {
   305  		u, _ := _uuid(i).MarshalText()
   306  		return string(u)
   307  	}
   308  	_date := func(i int) time.Time {
   309  		return time.Unix(int64(1704063600+i), 0)
   310  	}
   311  	_dateAsText := func(i int) string {
   312  		d, _ := _date(i).MarshalText()
   313  		return string(d)
   314  	}
   315  	_text := func(i int) string {
   316  		return fmt.Sprintf("text%d", i)
   317  	}
   318  	ptrFloat32 := func(f float32) *float32 {
   319  		return &f
   320  	}
   321  
   322  	createPrevProps := func(i int) map[string]interface{} {
   323  		f := float64(i)
   324  		return map[string]interface{}{
   325  			"int":      f,
   326  			"number":   f + 0.5,
   327  			"text":     _text(i),
   328  			"boolean":  i%2 == 0,
   329  			"uuid":     _uuidAsText(i),
   330  			"date":     _dateAsText(i),
   331  			"ints":     []float64{f + 1, f + 2, f + 3},
   332  			"numbers":  []float64{f + 1.5, f + 2.5, f + 3.5},
   333  			"texts":    []string{_text(i + 1), _text(i + 2), _text(i + 3)},
   334  			"booleans": []bool{i%2 != 0, i%2 == 0},
   335  			"uuids":    []string{_uuidAsText(i + 1), _uuidAsText(i + 2), _uuidAsText(i + 3)},
   336  			"dates":    []string{_dateAsText(i + 1), _dateAsText(i + 2), _dateAsText(i + 3)},
   337  			"phone": &models.PhoneNumber{
   338  				DefaultCountry: "pl",
   339  				Input:          fmt.Sprintf("%d", 100_000_000+i),
   340  			},
   341  			"geo": &models.GeoCoordinates{
   342  				Latitude:  ptrFloat32(45.67),
   343  				Longitude: ptrFloat32(-12.34),
   344  			},
   345  			"object": map[string]interface{}{
   346  				"n_int":     f + 10,
   347  				"n_number":  f + 10.5,
   348  				"n_text":    _text(i + 10),
   349  				"n_boolean": i%2 == 0,
   350  				"n_uuid":    _uuidAsText(i + 10),
   351  				"n_date":    _dateAsText(i + 10),
   352  				"n_object": map[string]interface{}{
   353  					"nn_int": f + 20,
   354  				},
   355  			},
   356  			"objects": []interface{}{
   357  				map[string]interface{}{
   358  					"n_ints":     []float64{f + 11, f + 12, f + 13},
   359  					"n_numbers":  []float64{f + 11.5, f + 12.5, f + 13.5},
   360  					"n_texts":    []string{_text(i + 11), _text(i + 12), _text(i + 13)},
   361  					"n_booleans": []bool{i%2 != 0, i%2 == 0},
   362  					"n_uuids":    []string{_uuidAsText(i + 11), _uuidAsText(i + 12), _uuidAsText(i + 13)},
   363  					"n_dates":    []string{_dateAsText(i + 11), _dateAsText(i + 12), _dateAsText(i + 13)},
   364  					"n_objects": []interface{}{
   365  						map[string]interface{}{
   366  							"nn_ints": []float64{f + 21, f + 22, f + 23},
   367  						},
   368  					},
   369  				},
   370  			},
   371  		}
   372  	}
   373  	createNextProps := func(i int) map[string]interface{} {
   374  		props := createPrevProps(i)
   375  		props["uuid"] = _uuid(i)
   376  		props["date"] = _date(i)
   377  		props["uuids"] = []uuid.UUID{_uuid(i + 1), _uuid(i + 2), _uuid(i + 3)}
   378  		props["dates"] = []time.Time{_date(i + 1), _date(i + 2), _date(i + 3)}
   379  
   380  		obj := props["object"].(map[string]interface{})
   381  		obj["n_uuid"] = _uuid(i + 10)
   382  		obj["n_date"] = _date(i + 10)
   383  
   384  		objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   385  		objs0["n_uuids"] = []uuid.UUID{_uuid(i + 11), _uuid(i + 12), _uuid(i + 13)}
   386  		objs0["n_dates"] = []time.Time{_date(i + 11), _date(i + 12), _date(i + 13)}
   387  
   388  		return props
   389  	}
   390  
   391  	prevProps := createPrevProps(1)
   392  	nextProps := createNextProps(1)
   393  	testCases := []testCase{
   394  		{
   395  			prevProps:     nil,
   396  			nextProps:     nil,
   397  			expectedEqual: true,
   398  		},
   399  		{
   400  			prevProps:     prevProps,
   401  			nextProps:     nil,
   402  			expectedEqual: false,
   403  		},
   404  		{
   405  			prevProps:     nil,
   406  			nextProps:     nextProps,
   407  			expectedEqual: false,
   408  		},
   409  		{
   410  			prevProps:     prevProps,
   411  			nextProps:     nextProps,
   412  			expectedEqual: true,
   413  		},
   414  		{
   415  			prevProps:     prevProps,
   416  			nextProps:     createNextProps(2),
   417  			expectedEqual: false,
   418  		},
   419  		{
   420  			prevProps: prevProps,
   421  			nextProps: func() map[string]interface{} {
   422  				props := createNextProps(1)
   423  				props["int"] = float64(1000)
   424  				return props
   425  			}(),
   426  			expectedEqual: false,
   427  		},
   428  		{
   429  			prevProps: prevProps,
   430  			nextProps: func() map[string]interface{} {
   431  				props := createNextProps(1)
   432  				props["number"] = float64(1000.5)
   433  				return props
   434  			}(),
   435  			expectedEqual: false,
   436  		},
   437  		{
   438  			prevProps: prevProps,
   439  			nextProps: func() map[string]interface{} {
   440  				props := createNextProps(1)
   441  				props["text"] = _text(1000)
   442  				return props
   443  			}(),
   444  			expectedEqual: false,
   445  		},
   446  		{
   447  			prevProps: prevProps,
   448  			nextProps: func() map[string]interface{} {
   449  				props := createNextProps(1)
   450  				props["boolean"] = true
   451  				return props
   452  			}(),
   453  			expectedEqual: false,
   454  		},
   455  		{
   456  			prevProps: prevProps,
   457  			nextProps: func() map[string]interface{} {
   458  				props := createNextProps(1)
   459  				props["uuid"] = _uuid(1000)
   460  				return props
   461  			}(),
   462  			expectedEqual: false,
   463  		},
   464  		{
   465  			prevProps: prevProps,
   466  			nextProps: func() map[string]interface{} {
   467  				props := createNextProps(1)
   468  				props["date"] = _date(1000)
   469  				return props
   470  			}(),
   471  			expectedEqual: false,
   472  		},
   473  		{
   474  			prevProps: prevProps,
   475  			nextProps: func() map[string]interface{} {
   476  				props := createNextProps(1)
   477  				props["ints"] = []float64{1000, 1001}
   478  				return props
   479  			}(),
   480  			expectedEqual: false,
   481  		},
   482  		{
   483  			prevProps: prevProps,
   484  			nextProps: func() map[string]interface{} {
   485  				props := createNextProps(1)
   486  				props["numbers"] = []float64{1000.5, 1001.5}
   487  				return props
   488  			}(),
   489  			expectedEqual: false,
   490  		},
   491  		{
   492  			prevProps: prevProps,
   493  			nextProps: func() map[string]interface{} {
   494  				props := createNextProps(1)
   495  				props["texts"] = []string{_text(1000), _text(1001)}
   496  				return props
   497  			}(),
   498  			expectedEqual: false,
   499  		},
   500  		{
   501  			prevProps: prevProps,
   502  			nextProps: func() map[string]interface{} {
   503  				props := createNextProps(1)
   504  				props["booleans"] = []bool{false, true}
   505  				return props
   506  			}(),
   507  			expectedEqual: false,
   508  		},
   509  		{
   510  			prevProps: prevProps,
   511  			nextProps: func() map[string]interface{} {
   512  				props := createNextProps(1)
   513  				props["uuids"] = []uuid.UUID{_uuid(1000), _uuid(1001)}
   514  				return props
   515  			}(),
   516  			expectedEqual: false,
   517  		},
   518  		{
   519  			prevProps: prevProps,
   520  			nextProps: func() map[string]interface{} {
   521  				props := createNextProps(1)
   522  				props["dates"] = []time.Time{_date(1000), _date(1001)}
   523  				return props
   524  			}(),
   525  			expectedEqual: false,
   526  		},
   527  		{
   528  			prevProps: prevProps,
   529  			nextProps: func() map[string]interface{} {
   530  				props := createNextProps(1)
   531  				props["phone"] = &models.PhoneNumber{
   532  					DefaultCountry: "pl",
   533  					Input:          fmt.Sprintf("%d", 123_456_789),
   534  				}
   535  				return props
   536  			}(),
   537  			expectedEqual: false,
   538  		},
   539  		{
   540  			prevProps: prevProps,
   541  			nextProps: func() map[string]interface{} {
   542  				props := createNextProps(1)
   543  				props["geo"] = &models.GeoCoordinates{
   544  					Latitude:  ptrFloat32(45.67),
   545  					Longitude: ptrFloat32(12.34),
   546  				}
   547  				return props
   548  			}(),
   549  			expectedEqual: false,
   550  		},
   551  		{
   552  			prevProps: prevProps,
   553  			nextProps: func() map[string]interface{} {
   554  				props := createNextProps(1)
   555  				obj := props["object"].(map[string]interface{})
   556  				obj["n_int"] = float64(1000)
   557  				return props
   558  			}(),
   559  			expectedEqual: false,
   560  		},
   561  		{
   562  			prevProps: prevProps,
   563  			nextProps: func() map[string]interface{} {
   564  				props := createNextProps(1)
   565  				obj := props["object"].(map[string]interface{})
   566  				obj["n_number"] = float64(1000.5)
   567  				return props
   568  			}(),
   569  			expectedEqual: false,
   570  		},
   571  		{
   572  			prevProps: prevProps,
   573  			nextProps: func() map[string]interface{} {
   574  				props := createNextProps(1)
   575  				obj := props["object"].(map[string]interface{})
   576  				obj["n_text"] = _text(1000)
   577  				return props
   578  			}(),
   579  			expectedEqual: false,
   580  		},
   581  		{
   582  			prevProps: prevProps,
   583  			nextProps: func() map[string]interface{} {
   584  				props := createNextProps(1)
   585  				obj := props["object"].(map[string]interface{})
   586  				obj["n_boolean"] = true
   587  				return props
   588  			}(),
   589  			expectedEqual: false,
   590  		},
   591  		{
   592  			prevProps: prevProps,
   593  			nextProps: func() map[string]interface{} {
   594  				props := createNextProps(1)
   595  				obj := props["object"].(map[string]interface{})
   596  				obj["n_uuid"] = _uuid(1000)
   597  				return props
   598  			}(),
   599  			expectedEqual: false,
   600  		},
   601  		{
   602  			prevProps: prevProps,
   603  			nextProps: func() map[string]interface{} {
   604  				props := createNextProps(1)
   605  				obj := props["object"].(map[string]interface{})
   606  				obj["n_date"] = _date(1000)
   607  				return props
   608  			}(),
   609  			expectedEqual: false,
   610  		},
   611  		{
   612  			prevProps: prevProps,
   613  			nextProps: func() map[string]interface{} {
   614  				props := createNextProps(1)
   615  				obj := props["object"].(map[string]interface{})
   616  				nobj := obj["n_object"].(map[string]interface{})
   617  				nobj["nn_int"] = float64(1000)
   618  				return props
   619  			}(),
   620  			expectedEqual: false,
   621  		},
   622  		{
   623  			prevProps: prevProps,
   624  			nextProps: func() map[string]interface{} {
   625  				props := createNextProps(1)
   626  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   627  				objs0["n_ints"] = []float64{1000, 1001}
   628  				return props
   629  			}(),
   630  			expectedEqual: false,
   631  		},
   632  		{
   633  			prevProps: prevProps,
   634  			nextProps: func() map[string]interface{} {
   635  				props := createNextProps(1)
   636  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   637  				objs0["n_numbers"] = []float64{1000.5, 1001.5}
   638  				return props
   639  			}(),
   640  			expectedEqual: false,
   641  		},
   642  		{
   643  			prevProps: prevProps,
   644  			nextProps: func() map[string]interface{} {
   645  				props := createNextProps(1)
   646  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   647  				objs0["n_texts"] = []string{_text(1000), _text(1001)}
   648  				return props
   649  			}(),
   650  			expectedEqual: false,
   651  		},
   652  		{
   653  			prevProps: prevProps,
   654  			nextProps: func() map[string]interface{} {
   655  				props := createNextProps(1)
   656  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   657  				objs0["n_booleans"] = []bool{false, true}
   658  				return props
   659  			}(),
   660  			expectedEqual: false,
   661  		},
   662  		{
   663  			prevProps: prevProps,
   664  			nextProps: func() map[string]interface{} {
   665  				props := createNextProps(1)
   666  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   667  				objs0["n_uuids"] = []uuid.UUID{_uuid(1000), _uuid(1001)}
   668  				return props
   669  			}(),
   670  			expectedEqual: false,
   671  		},
   672  		{
   673  			prevProps: prevProps,
   674  			nextProps: func() map[string]interface{} {
   675  				props := createNextProps(1)
   676  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   677  				objs0["n_dates"] = []time.Time{_date(1000), _date(1001)}
   678  				return props
   679  			}(),
   680  			expectedEqual: false,
   681  		},
   682  		{
   683  			prevProps: prevProps,
   684  			nextProps: func() map[string]interface{} {
   685  				props := createNextProps(1)
   686  				objs0 := props["objects"].([]interface{})[0].(map[string]interface{})
   687  				nobjs0 := objs0["n_objects"].([]interface{})[0].(map[string]interface{})
   688  				nobjs0["nn_ints"] = []float64{1000, 1001}
   689  				return props
   690  			}(),
   691  			expectedEqual: false,
   692  		},
   693  	}
   694  
   695  	for i, tc := range testCases {
   696  		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
   697  			eq := propsEqual(tc.prevProps, tc.nextProps)
   698  
   699  			if tc.expectedEqual {
   700  				assert.True(t, eq)
   701  			} else {
   702  				assert.False(t, eq)
   703  			}
   704  		})
   705  	}
   706  }
   707  
   708  func TestTargetVectorsEqual(t *testing.T) {
   709  	vec1 := []float32{1, 2, 3}
   710  	vec2 := []float32{2, 3, 4}
   711  	vec3 := []float32{3, 4, 5}
   712  	vec4 := []float32{4, 5, 6}
   713  
   714  	type testCase struct {
   715  		prevVecs      map[string][]float32
   716  		nextVecs      map[string][]float32
   717  		expectedEqual bool
   718  	}
   719  
   720  	testCases := []testCase{
   721  		{
   722  			prevVecs:      nil,
   723  			nextVecs:      nil,
   724  			expectedEqual: true,
   725  		},
   726  		{
   727  			prevVecs:      map[string][]float32{},
   728  			nextVecs:      nil,
   729  			expectedEqual: true,
   730  		},
   731  		{
   732  			prevVecs:      nil,
   733  			nextVecs:      map[string][]float32{},
   734  			expectedEqual: true,
   735  		},
   736  		{
   737  			prevVecs:      map[string][]float32{},
   738  			nextVecs:      map[string][]float32{},
   739  			expectedEqual: true,
   740  		},
   741  		{
   742  			prevVecs:      map[string][]float32{"vec": vec1},
   743  			nextVecs:      nil,
   744  			expectedEqual: false,
   745  		},
   746  		{
   747  			prevVecs:      nil,
   748  			nextVecs:      map[string][]float32{"vec": vec1},
   749  			expectedEqual: false,
   750  		},
   751  		{
   752  			prevVecs:      map[string][]float32{"vec": vec1},
   753  			nextVecs:      map[string][]float32{},
   754  			expectedEqual: false,
   755  		},
   756  		{
   757  			prevVecs:      map[string][]float32{},
   758  			nextVecs:      map[string][]float32{"vec": vec1},
   759  			expectedEqual: false,
   760  		},
   761  
   762  		{
   763  			prevVecs:      map[string][]float32{"vec": nil},
   764  			nextVecs:      nil,
   765  			expectedEqual: true,
   766  		},
   767  		{
   768  			prevVecs:      nil,
   769  			nextVecs:      map[string][]float32{"vec": nil},
   770  			expectedEqual: true,
   771  		},
   772  		{
   773  			prevVecs:      map[string][]float32{"vec": nil},
   774  			nextVecs:      map[string][]float32{},
   775  			expectedEqual: true,
   776  		},
   777  		{
   778  			prevVecs:      map[string][]float32{},
   779  			nextVecs:      map[string][]float32{"vec": nil},
   780  			expectedEqual: true,
   781  		},
   782  		{
   783  			prevVecs:      map[string][]float32{"vec": vec1},
   784  			nextVecs:      map[string][]float32{"vec": nil},
   785  			expectedEqual: false,
   786  		},
   787  		{
   788  			prevVecs:      map[string][]float32{"vec": nil},
   789  			nextVecs:      map[string][]float32{"vec": vec1},
   790  			expectedEqual: false,
   791  		},
   792  		{
   793  			prevVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3},
   794  			nextVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3},
   795  			expectedEqual: true,
   796  		},
   797  		{
   798  			prevVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3},
   799  			nextVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec4": vec4},
   800  			expectedEqual: false,
   801  		},
   802  		{
   803  			prevVecs:      map[string][]float32{"vec": vec1},
   804  			nextVecs:      map[string][]float32{"vec": vec2},
   805  			expectedEqual: false,
   806  		},
   807  		{
   808  			prevVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3},
   809  			nextVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3, "vec4": vec4},
   810  			expectedEqual: false,
   811  		},
   812  		{
   813  			prevVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3, "vec4": vec4},
   814  			nextVecs:      map[string][]float32{"vec1": vec1, "vec2": vec2, "vec3": vec3},
   815  			expectedEqual: false,
   816  		},
   817  	}
   818  
   819  	for i, tc := range testCases {
   820  		t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
   821  			eq := targetVectorsEqual(tc.prevVecs, tc.nextVecs)
   822  
   823  			if tc.expectedEqual {
   824  				assert.True(t, eq)
   825  			} else {
   826  				assert.False(t, eq)
   827  			}
   828  		})
   829  	}
   830  }