...

Source file src/github.com/redis/go-redis/v9/vectorset_commands_test.go

Documentation: github.com/redis/go-redis/v9

     1  package redis
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"reflect"
     7  	"testing"
     8  )
     9  
    10  func TestVectorFP32_Value(t *testing.T) {
    11  	v := &VectorFP32{Val: []byte{1, 2, 3}}
    12  	got := v.Value()
    13  	want := []any{"FP32", []byte{1, 2, 3}}
    14  	if !reflect.DeepEqual(got, want) {
    15  		t.Errorf("VectorFP32.Value() = %v, want %v", got, want)
    16  	}
    17  }
    18  
    19  func TestVectorValues_Value(t *testing.T) {
    20  	v := &VectorValues{Val: []float64{1.1, 2.2}}
    21  	got := v.Value()
    22  	want := []any{"Values", 2, 1.1, 2.2}
    23  	if !reflect.DeepEqual(got, want) {
    24  		t.Errorf("VectorValues.Value() = %v, want %v", got, want)
    25  	}
    26  }
    27  
    28  func TestVectorRef_Value(t *testing.T) {
    29  	v := &VectorRef{Name: "foo"}
    30  	got := v.Value()
    31  	want := []any{"ele", "foo"}
    32  	if !reflect.DeepEqual(got, want) {
    33  		t.Errorf("VectorRef.Value() = %v, want %v", got, want)
    34  	}
    35  }
    36  
    37  func TestVAdd(t *testing.T) {
    38  	m := &mockCmdable{}
    39  	c := m.asCmdable()
    40  	vec := &VectorValues{Val: []float64{1, 2}}
    41  	c.VAdd(context.Background(), "k", "e", vec)
    42  	cmd, ok := m.lastCmd.(*BoolCmd)
    43  	if !ok {
    44  		t.Fatalf("expected BoolCmd, got %T", m.lastCmd)
    45  	}
    46  	if cmd.args[0] != "vadd" || cmd.args[1] != "k" || cmd.args[len(cmd.args)-1] != "e" {
    47  		t.Errorf("unexpected args: %v", cmd.args)
    48  	}
    49  }
    50  
    51  func TestVAddWithArgs_AllOptions(t *testing.T) {
    52  	m := &mockCmdable{}
    53  	c := m.asCmdable()
    54  	vec := &VectorValues{Val: []float64{1, 2}}
    55  	args := &VAddArgs{Reduce: 3, Cas: true, NoQuant: true, EF: 5, SetAttr: "attr", M: 2}
    56  	c.VAddWithArgs(context.Background(), "k", "e", vec, args)
    57  	cmd := m.lastCmd.(*BoolCmd)
    58  	found := map[string]bool{}
    59  	for _, a := range cmd.args {
    60  		if s, ok := a.(string); ok {
    61  			found[s] = true
    62  		}
    63  	}
    64  	for _, want := range []string{"reduce", "cas", "noquant", "ef", "setattr", "m"} {
    65  		if !found[want] {
    66  			t.Errorf("missing arg: %s", want)
    67  		}
    68  	}
    69  }
    70  
    71  func TestVCard(t *testing.T) {
    72  	m := &mockCmdable{}
    73  	c := m.asCmdable()
    74  	c.VCard(context.Background(), "k")
    75  	cmd := m.lastCmd.(*IntCmd)
    76  	if cmd.args[0] != "vcard" || cmd.args[1] != "k" {
    77  		t.Errorf("unexpected args: %v", cmd.args)
    78  	}
    79  }
    80  
    81  func TestVDim(t *testing.T) {
    82  	m := &mockCmdable{}
    83  	c := m.asCmdable()
    84  	c.VDim(context.Background(), "k")
    85  	cmd := m.lastCmd.(*IntCmd)
    86  	if cmd.args[0] != "vdim" || cmd.args[1] != "k" {
    87  		t.Errorf("unexpected args: %v", cmd.args)
    88  	}
    89  }
    90  
    91  func TestVEmb(t *testing.T) {
    92  	m := &mockCmdable{}
    93  	c := m.asCmdable()
    94  	c.VEmb(context.Background(), "k", "e", true)
    95  	cmd := m.lastCmd.(*SliceCmd)
    96  	if cmd.args[0] != "vemb" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "raw" {
    97  		t.Errorf("unexpected args: %v", cmd.args)
    98  	}
    99  }
   100  
   101  func TestVGetAttr(t *testing.T) {
   102  	m := &mockCmdable{}
   103  	c := m.asCmdable()
   104  	c.VGetAttr(context.Background(), "k", "e")
   105  	cmd := m.lastCmd.(*StringCmd)
   106  	if cmd.args[0] != "vgetattr" || cmd.args[1] != "k" || cmd.args[2] != "e" {
   107  		t.Errorf("unexpected args: %v", cmd.args)
   108  	}
   109  }
   110  
   111  func TestVInfo(t *testing.T) {
   112  	m := &mockCmdable{}
   113  	c := m.asCmdable()
   114  	c.VInfo(context.Background(), "k")
   115  	cmd := m.lastCmd.(*MapStringInterfaceCmd)
   116  	if cmd.args[0] != "vinfo" || cmd.args[1] != "k" {
   117  		t.Errorf("unexpected args: %v", cmd.args)
   118  	}
   119  }
   120  
   121  func TestVLinks(t *testing.T) {
   122  	m := &mockCmdable{}
   123  	c := m.asCmdable()
   124  	c.VLinks(context.Background(), "k", "e")
   125  	cmd := m.lastCmd.(*StringSliceCmd)
   126  	if cmd.args[0] != "vlinks" || cmd.args[1] != "k" || cmd.args[2] != "e" {
   127  		t.Errorf("unexpected args: %v", cmd.args)
   128  	}
   129  }
   130  
   131  func TestVLinksWithScores(t *testing.T) {
   132  	m := &mockCmdable{}
   133  	c := m.asCmdable()
   134  	c.VLinksWithScores(context.Background(), "k", "e")
   135  	cmd := m.lastCmd.(*VectorScoreSliceCmd)
   136  	if cmd.args[0] != "vlinks" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "withscores" {
   137  		t.Errorf("unexpected args: %v", cmd.args)
   138  	}
   139  }
   140  
   141  func TestVRandMember(t *testing.T) {
   142  	m := &mockCmdable{}
   143  	c := m.asCmdable()
   144  	c.VRandMember(context.Background(), "k")
   145  	cmd := m.lastCmd.(*StringCmd)
   146  	if cmd.args[0] != "vrandmember" || cmd.args[1] != "k" {
   147  		t.Errorf("unexpected args: %v", cmd.args)
   148  	}
   149  }
   150  
   151  func TestVRandMemberCount(t *testing.T) {
   152  	m := &mockCmdable{}
   153  	c := m.asCmdable()
   154  	c.VRandMemberCount(context.Background(), "k", 5)
   155  	cmd := m.lastCmd.(*StringSliceCmd)
   156  	if cmd.args[0] != "vrandmember" || cmd.args[1] != "k" || cmd.args[2] != 5 {
   157  		t.Errorf("unexpected args: %v", cmd.args)
   158  	}
   159  }
   160  
   161  func TestVRem(t *testing.T) {
   162  	m := &mockCmdable{}
   163  	c := m.asCmdable()
   164  	c.VRem(context.Background(), "k", "e")
   165  	cmd := m.lastCmd.(*BoolCmd)
   166  	if cmd.args[0] != "vrem" || cmd.args[1] != "k" || cmd.args[2] != "e" {
   167  		t.Errorf("unexpected args: %v", cmd.args)
   168  	}
   169  }
   170  
   171  func TestVSetAttr_String(t *testing.T) {
   172  	m := &mockCmdable{}
   173  	c := m.asCmdable()
   174  	c.VSetAttr(context.Background(), "k", "e", "foo")
   175  	cmd := m.lastCmd.(*BoolCmd)
   176  	if cmd.args[0] != "vsetattr" || cmd.args[1] != "k" || cmd.args[2] != "e" || cmd.args[3] != "foo" {
   177  		t.Errorf("unexpected args: %v", cmd.args)
   178  	}
   179  }
   180  
   181  func TestVSetAttr_Bytes(t *testing.T) {
   182  	m := &mockCmdable{}
   183  	c := m.asCmdable()
   184  	c.VSetAttr(context.Background(), "k", "e", []byte("bar"))
   185  	cmd := m.lastCmd.(*BoolCmd)
   186  	if cmd.args[3] != "bar" {
   187  		t.Errorf("expected 'bar', got %v", cmd.args[3])
   188  	}
   189  }
   190  
   191  func TestVSetAttr_MarshalStruct(t *testing.T) {
   192  	m := &mockCmdable{}
   193  	c := m.asCmdable()
   194  	val := struct{ A int }{A: 1}
   195  	c.VSetAttr(context.Background(), "k", "e", val)
   196  	cmd := m.lastCmd.(*BoolCmd)
   197  	want, _ := json.Marshal(val)
   198  	if cmd.args[3] != string(want) {
   199  		t.Errorf("expected marshalled struct, got %v", cmd.args[3])
   200  	}
   201  }
   202  
   203  func TestVSetAttr_MarshalError(t *testing.T) {
   204  	m := &mockCmdable{}
   205  	c := m.asCmdable()
   206  	bad := func() {}
   207  	cmd := c.VSetAttr(context.Background(), "k", "e", bad)
   208  	if cmd.Err() == nil {
   209  		t.Error("expected error for non-marshallable value")
   210  	}
   211  }
   212  
   213  func TestVClearAttributes(t *testing.T) {
   214  	m := &mockCmdable{}
   215  	c := m.asCmdable()
   216  	c.VClearAttributes(context.Background(), "k", "e")
   217  	cmd := m.lastCmd.(*BoolCmd)
   218  	if cmd.args[0] != "vsetattr" || cmd.args[3] != "" {
   219  		t.Errorf("unexpected args: %v", cmd.args)
   220  	}
   221  }
   222  
   223  func TestVSim(t *testing.T) {
   224  	m := &mockCmdable{}
   225  	c := m.asCmdable()
   226  	vec := &VectorValues{Val: []float64{1, 2}}
   227  	c.VSim(context.Background(), "k", vec)
   228  	cmd := m.lastCmd.(*StringSliceCmd)
   229  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
   230  		t.Errorf("unexpected args: %v", cmd.args)
   231  	}
   232  }
   233  
   234  func TestVSimWithScores(t *testing.T) {
   235  	m := &mockCmdable{}
   236  	c := m.asCmdable()
   237  	vec := &VectorValues{Val: []float64{1, 2}}
   238  	c.VSimWithScores(context.Background(), "k", vec)
   239  	cmd := m.lastCmd.(*VectorScoreSliceCmd)
   240  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" || cmd.args[len(cmd.args)-1] != "withscores" {
   241  		t.Errorf("unexpected args: %v", cmd.args)
   242  	}
   243  }
   244  
   245  func TestVSimWithArgs_AllOptions(t *testing.T) {
   246  	m := &mockCmdable{}
   247  	c := m.asCmdable()
   248  	vec := &VectorValues{Val: []float64{1, 2}}
   249  	args := &VSimArgs{Count: 2, EF: 3, Filter: "f", FilterEF: 4, Truth: true, NoThread: true}
   250  	c.VSimWithArgs(context.Background(), "k", vec, args)
   251  	cmd := m.lastCmd.(*StringSliceCmd)
   252  	found := map[string]bool{}
   253  	for _, a := range cmd.args {
   254  		if s, ok := a.(string); ok {
   255  			found[s] = true
   256  		}
   257  	}
   258  	for _, want := range []string{"count", "ef", "filter", "filter-ef", "truth", "nothread"} {
   259  		if !found[want] {
   260  			t.Errorf("missing arg: %s", want)
   261  		}
   262  	}
   263  }
   264  
   265  func TestVSimWithArgsWithScores_AllOptions(t *testing.T) {
   266  	m := &mockCmdable{}
   267  	c := m.asCmdable()
   268  	vec := &VectorValues{Val: []float64{1, 2}}
   269  	args := &VSimArgs{Count: 2, EF: 3, Filter: "f", FilterEF: 4, Truth: true, NoThread: true}
   270  	c.VSimWithArgsWithScores(context.Background(), "k", vec, args)
   271  	cmd := m.lastCmd.(*VectorScoreSliceCmd)
   272  	found := map[string]bool{}
   273  	for _, a := range cmd.args {
   274  		if s, ok := a.(string); ok {
   275  			found[s] = true
   276  		}
   277  	}
   278  	for _, want := range []string{"count", "ef", "filter", "filter-ef", "truth", "nothread", "withscores"} {
   279  		if !found[want] {
   280  			t.Errorf("missing arg: %s", want)
   281  		}
   282  	}
   283  }
   284  
   285  // Additional tests for missing coverage
   286  
   287  func TestVectorValues_EmptySlice(t *testing.T) {
   288  	v := &VectorValues{Val: []float64{}}
   289  	got := v.Value()
   290  	want := []any{"Values", 0}
   291  	if !reflect.DeepEqual(got, want) {
   292  		t.Errorf("VectorValues.Value() with empty slice = %v, want %v", got, want)
   293  	}
   294  }
   295  
   296  func TestVEmb_WithoutRaw(t *testing.T) {
   297  	m := &mockCmdable{}
   298  	c := m.asCmdable()
   299  	c.VEmb(context.Background(), "k", "e", false)
   300  	cmd := m.lastCmd.(*SliceCmd)
   301  	if cmd.args[0] != "vemb" || cmd.args[1] != "k" || cmd.args[2] != "e" {
   302  		t.Errorf("unexpected args: %v", cmd.args)
   303  	}
   304  	if len(cmd.args) != 3 {
   305  		t.Errorf("expected 3 args when raw=false, got %d", len(cmd.args))
   306  	}
   307  }
   308  
   309  func TestVAddWithArgs_Q8Option(t *testing.T) {
   310  	m := &mockCmdable{}
   311  	c := m.asCmdable()
   312  	vec := &VectorValues{Val: []float64{1, 2}}
   313  	args := &VAddArgs{Q8: true}
   314  	c.VAddWithArgs(context.Background(), "k", "e", vec, args)
   315  	cmd := m.lastCmd.(*BoolCmd)
   316  	found := false
   317  	for _, a := range cmd.args {
   318  		if s, ok := a.(string); ok && s == "q8" {
   319  			found = true
   320  			break
   321  		}
   322  	}
   323  	if !found {
   324  		t.Error("missing q8 arg")
   325  	}
   326  }
   327  
   328  func TestVAddWithArgs_BinOption(t *testing.T) {
   329  	m := &mockCmdable{}
   330  	c := m.asCmdable()
   331  	vec := &VectorValues{Val: []float64{1, 2}}
   332  	args := &VAddArgs{Bin: true}
   333  	c.VAddWithArgs(context.Background(), "k", "e", vec, args)
   334  	cmd := m.lastCmd.(*BoolCmd)
   335  	found := false
   336  	for _, a := range cmd.args {
   337  		if s, ok := a.(string); ok && s == "bin" {
   338  			found = true
   339  			break
   340  		}
   341  	}
   342  	if !found {
   343  		t.Error("missing bin arg")
   344  	}
   345  }
   346  
   347  func TestVAddWithArgs_NilArgs(t *testing.T) {
   348  	m := &mockCmdable{}
   349  	c := m.asCmdable()
   350  	vec := &VectorValues{Val: []float64{1, 2}}
   351  	c.VAddWithArgs(context.Background(), "k", "e", vec, nil)
   352  	cmd := m.lastCmd.(*BoolCmd)
   353  	if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
   354  		t.Errorf("unexpected args: %v", cmd.args)
   355  	}
   356  }
   357  
   358  func TestVSimWithArgs_NilArgs(t *testing.T) {
   359  	m := &mockCmdable{}
   360  	c := m.asCmdable()
   361  	vec := &VectorValues{Val: []float64{1, 2}}
   362  	c.VSimWithArgs(context.Background(), "k", vec, nil)
   363  	cmd := m.lastCmd.(*StringSliceCmd)
   364  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
   365  		t.Errorf("unexpected args: %v", cmd.args)
   366  	}
   367  }
   368  
   369  func TestVSimWithArgsWithScores_NilArgs(t *testing.T) {
   370  	m := &mockCmdable{}
   371  	c := m.asCmdable()
   372  	vec := &VectorValues{Val: []float64{1, 2}}
   373  	c.VSimWithArgsWithScores(context.Background(), "k", vec, nil)
   374  	cmd := m.lastCmd.(*VectorScoreSliceCmd)
   375  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
   376  		t.Errorf("unexpected args: %v", cmd.args)
   377  	}
   378  	// Should still have withscores
   379  	found := false
   380  	for _, a := range cmd.args {
   381  		if s, ok := a.(string); ok && s == "withscores" {
   382  			found = true
   383  			break
   384  		}
   385  	}
   386  	if !found {
   387  		t.Error("missing withscores arg")
   388  	}
   389  }
   390  
   391  func TestVAdd_WithVectorFP32(t *testing.T) {
   392  	m := &mockCmdable{}
   393  	c := m.asCmdable()
   394  	vec := &VectorFP32{Val: []byte{1, 2, 3, 4}}
   395  	c.VAdd(context.Background(), "k", "e", vec)
   396  	cmd := m.lastCmd.(*BoolCmd)
   397  	if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
   398  		t.Errorf("unexpected args: %v", cmd.args)
   399  	}
   400  	// Check that FP32 format is used
   401  	found := false
   402  	for _, a := range cmd.args {
   403  		if s, ok := a.(string); ok && s == "FP32" {
   404  			found = true
   405  			break
   406  		}
   407  	}
   408  	if !found {
   409  		t.Error("missing FP32 format in args")
   410  	}
   411  }
   412  
   413  func TestVAdd_WithVectorRef(t *testing.T) {
   414  	m := &mockCmdable{}
   415  	c := m.asCmdable()
   416  	vec := &VectorRef{Name: "ref-vector"}
   417  	c.VAdd(context.Background(), "k", "e", vec)
   418  	cmd := m.lastCmd.(*BoolCmd)
   419  	if cmd.args[0] != "vadd" || cmd.args[1] != "k" {
   420  		t.Errorf("unexpected args: %v", cmd.args)
   421  	}
   422  	// Check that ele format is used
   423  	found := false
   424  	for _, a := range cmd.args {
   425  		if s, ok := a.(string); ok && s == "ele" {
   426  			found = true
   427  			break
   428  		}
   429  	}
   430  	if !found {
   431  		t.Error("missing ele format in args")
   432  	}
   433  }
   434  
   435  func TestVSim_WithVectorFP32(t *testing.T) {
   436  	m := &mockCmdable{}
   437  	c := m.asCmdable()
   438  	vec := &VectorFP32{Val: []byte{1, 2, 3, 4}}
   439  	c.VSim(context.Background(), "k", vec)
   440  	cmd := m.lastCmd.(*StringSliceCmd)
   441  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
   442  		t.Errorf("unexpected args: %v", cmd.args)
   443  	}
   444  	// Check that FP32 format is used
   445  	found := false
   446  	for _, a := range cmd.args {
   447  		if s, ok := a.(string); ok && s == "FP32" {
   448  			found = true
   449  			break
   450  		}
   451  	}
   452  	if !found {
   453  		t.Error("missing FP32 format in args")
   454  	}
   455  }
   456  
   457  func TestVSim_WithVectorRef(t *testing.T) {
   458  	m := &mockCmdable{}
   459  	c := m.asCmdable()
   460  	vec := &VectorRef{Name: "ref-vector"}
   461  	c.VSim(context.Background(), "k", vec)
   462  	cmd := m.lastCmd.(*StringSliceCmd)
   463  	if cmd.args[0] != "vsim" || cmd.args[1] != "k" {
   464  		t.Errorf("unexpected args: %v", cmd.args)
   465  	}
   466  	// Check that ele format is used
   467  	found := false
   468  	for _, a := range cmd.args {
   469  		if s, ok := a.(string); ok && s == "ele" {
   470  			found = true
   471  			break
   472  		}
   473  	}
   474  	if !found {
   475  		t.Error("missing ele format in args")
   476  	}
   477  }
   478  
   479  func TestVAddWithArgs_ReduceOption(t *testing.T) {
   480  	m := &mockCmdable{}
   481  	c := m.asCmdable()
   482  	vec := &VectorValues{Val: []float64{1, 2}}
   483  	args := &VAddArgs{Reduce: 128}
   484  	c.VAddWithArgs(context.Background(), "k", "e", vec, args)
   485  	cmd := m.lastCmd.(*BoolCmd)
   486  	// Check that reduce appears early in args (after key)
   487  	if cmd.args[0] != "vadd" || cmd.args[1] != "k" || cmd.args[2] != "reduce" {
   488  		t.Errorf("unexpected args order: %v", cmd.args)
   489  	}
   490  }
   491  
   492  func TestVAddWithArgs_ZeroValues(t *testing.T) {
   493  	m := &mockCmdable{}
   494  	c := m.asCmdable()
   495  	vec := &VectorValues{Val: []float64{1, 2}}
   496  	args := &VAddArgs{Reduce: 0, EF: 0, M: 0} // Zero values should not appear in args
   497  	c.VAddWithArgs(context.Background(), "k", "e", vec, args)
   498  	cmd := m.lastCmd.(*BoolCmd)
   499  	// Check that zero values don't appear
   500  	for _, a := range cmd.args {
   501  		if s, ok := a.(string); ok {
   502  			if s == "reduce" || s == "ef" || s == "m" {
   503  				t.Errorf("zero value option should not appear in args: %s", s)
   504  			}
   505  		}
   506  	}
   507  }
   508  
   509  func TestVSimArgs_IndividualOptions(t *testing.T) {
   510  	tests := []struct {
   511  		name string
   512  		args *VSimArgs
   513  		want string
   514  	}{
   515  		{"Count", &VSimArgs{Count: 5}, "count"},
   516  		{"EF", &VSimArgs{EF: 10}, "ef"},
   517  		{"Filter", &VSimArgs{Filter: "test"}, "filter"},
   518  		{"FilterEF", &VSimArgs{FilterEF: 15}, "filter-ef"},
   519  		{"Truth", &VSimArgs{Truth: true}, "truth"},
   520  		{"NoThread", &VSimArgs{NoThread: true}, "nothread"},
   521  	}
   522  
   523  	for _, tt := range tests {
   524  		t.Run(tt.name, func(t *testing.T) {
   525  			m := &mockCmdable{}
   526  			c := m.asCmdable()
   527  			vec := &VectorValues{Val: []float64{1, 2}}
   528  			c.VSimWithArgs(context.Background(), "k", vec, tt.args)
   529  			cmd := m.lastCmd.(*StringSliceCmd)
   530  			found := false
   531  			for _, a := range cmd.args {
   532  				if s, ok := a.(string); ok && s == tt.want {
   533  					found = true
   534  					break
   535  				}
   536  			}
   537  			if !found {
   538  				t.Errorf("missing arg: %s", tt.want)
   539  			}
   540  		})
   541  	}
   542  }
   543  

View as plain text