@@ -2136,12 +2136,128 @@ func testAdapter(resp3 bool) {
2136
2136
replace := adapter .Copy (ctx , "newKey" , "key" , 0 , true )
2137
2137
Expect (replace .Val ()).To (Equal (int64 (1 )))
2138
2138
})
2139
+ }
2140
+ })
2141
+
2142
+ Describe ("ACL" , func () {
2143
+ if resp3 {
2144
+ TestUserName := "test"
2145
+ It ("should ACL LOG" , func () {
2146
+ Expect (adapter .ACLLogReset (ctx ).Err ()).NotTo (HaveOccurred ())
2147
+ err := adapter .ACLSetUser (ctx , "test" , ">test" , "on" , "allkeys" , "+get" ).Err ()
2148
+ Expect (err ).NotTo (HaveOccurred ())
2149
+
2150
+ for addr := range clientresp3 .Nodes () {
2151
+ clientAcl , err := rueidis .NewClient (rueidis.ClientOption {
2152
+ InitAddress : []string {addr },
2153
+ Username : "test" ,
2154
+ Password : "test" ,
2155
+ DisableCache : true ,
2156
+ })
2157
+ Expect (err ).NotTo (HaveOccurred ())
2158
+ adapterACL := NewAdapter (clientAcl )
2159
+ _ = adapterACL .Set (ctx , "mystring" , "foo" , 0 ).Err ()
2160
+ _ = adapterACL .HSet (ctx , "myhash" , "foo" , "bar" ).Err ()
2161
+ _ = adapterACL .SAdd (ctx , "myset" , "foo" , "bar" ).Err ()
2162
+ clientAcl .Close ()
2163
+ break
2164
+ }
2165
+
2166
+ logEntries , err := adapter .ACLLog (ctx , 10 ).Result ()
2167
+ Expect (err ).NotTo (HaveOccurred ())
2168
+ Expect (len (logEntries )).To (Equal (6 ))
2169
+
2170
+ for _ , entry := range logEntries {
2171
+ Expect (entry .Reason ).To (Equal ("command" ))
2172
+ Expect (entry .Context ).To (Equal ("toplevel" ))
2173
+ Expect (entry .Object ).NotTo (BeEmpty ())
2174
+ Expect (entry .Username ).To (Equal ("test" ))
2175
+ Expect (entry .AgeSeconds ).To (BeNumerically (">=" , 0 ))
2176
+ Expect (entry .ClientInfo ).NotTo (BeNil ())
2177
+ Expect (entry .EntryID ).To (BeNumerically (">=" , 0 ))
2178
+ Expect (entry .TimestampCreated ).To (BeNumerically (">=" , 0 ))
2179
+ Expect (entry .TimestampLastUpdated ).To (BeNumerically (">=" , 0 ))
2180
+ }
2181
+
2182
+ limitedLogEntries , err := adapter .ACLLog (ctx , 2 ).Result ()
2183
+ Expect (err ).NotTo (HaveOccurred ())
2184
+ Expect (len (limitedLogEntries )).To (Equal (2 ))
2185
+
2186
+ // cleanup after creating the user
2187
+ err = adapter .ACLDelUser (ctx , "test" ).Err ()
2188
+ Expect (err ).NotTo (HaveOccurred ())
2189
+ })
2190
+
2191
+ It ("should ACL LOG RESET" , func () {
2192
+ // Call ACL LOG RESET
2193
+ resetCmd := adapter .ACLLogReset (ctx )
2194
+ Expect (resetCmd .Err ()).NotTo (HaveOccurred ())
2195
+ Expect (resetCmd .Val ()).To (Equal ("OK" ))
2196
+
2197
+ // Verify that the log is empty after the reset
2198
+ logEntries , err := adapter .ACLLog (ctx , 10 ).Result ()
2199
+ Expect (err ).NotTo (HaveOccurred ())
2200
+ Expect (len (logEntries )).To (Equal (0 ))
2201
+ })
2202
+
2203
+ It ("list only default user" , func () {
2204
+ res , err := adapter .ACLList (ctx ).Result ()
2205
+ Expect (err ).NotTo (HaveOccurred ())
2206
+ Expect (res ).To (HaveLen (1 ))
2207
+ Expect (res [0 ]).To (ContainSubstring ("default" ))
2208
+ })
2209
+
2210
+ It ("setuser and deluser" , func () {
2211
+ res , err := adapter .ACLList (ctx ).Result ()
2212
+ Expect (err ).NotTo (HaveOccurred ())
2213
+ Expect (res ).To (HaveLen (1 ))
2214
+ Expect (res [0 ]).To (ContainSubstring ("default" ))
2215
+
2216
+ add , err := adapter .ACLSetUser (ctx , TestUserName , "nopass" , "on" , "allkeys" , "+set" , "+get" ).Result ()
2217
+ Expect (err ).NotTo (HaveOccurred ())
2218
+ Expect (add ).To (Equal ("OK" ))
2219
+
2220
+ resAfter , err := adapter .ACLList (ctx ).Result ()
2221
+ Expect (err ).NotTo (HaveOccurred ())
2222
+ Expect (resAfter ).To (HaveLen (2 ))
2223
+ Expect (resAfter [1 ]).To (ContainSubstring (TestUserName ))
2224
+
2225
+ deletedN , err := adapter .ACLDelUser (ctx , TestUserName ).Result ()
2226
+ Expect (err ).NotTo (HaveOccurred ())
2227
+ Expect (deletedN ).To (BeNumerically ("==" , 1 ))
2228
+
2229
+ resAfterDeletion , err := adapter .ACLList (ctx ).Result ()
2230
+ Expect (err ).NotTo (HaveOccurred ())
2231
+ Expect (resAfterDeletion ).To (HaveLen (1 ))
2232
+ Expect (resAfterDeletion [0 ]).To (BeEquivalentTo (res [0 ]))
2233
+ })
2139
2234
2140
2235
It ("should acl dryrun" , func () {
2141
2236
dryRun := adapter .ACLDryRun (ctx , "default" , "get" , "randomKey" )
2142
2237
Expect (dryRun .Err ()).NotTo (HaveOccurred ())
2143
2238
Expect (dryRun .Val ()).To (Equal ("OK" ))
2144
2239
})
2240
+
2241
+ It ("lists acl categories and subcategories" , func () {
2242
+ res , err := adapter .ACLCat (ctx ).Result ()
2243
+ Expect (err ).NotTo (HaveOccurred ())
2244
+ Expect (len (res )).To (BeNumerically (">" , 20 ))
2245
+ Expect (res ).To (ContainElements (
2246
+ "read" ,
2247
+ "write" ,
2248
+ "keyspace" ,
2249
+ "dangerous" ,
2250
+ "slow" ,
2251
+ "set" ,
2252
+ "sortedset" ,
2253
+ "list" ,
2254
+ "hash" ,
2255
+ ))
2256
+
2257
+ res , err = adapter .ACLCatArgs (ctx , & ACLCatArgs {Category : "read" }).Result ()
2258
+ Expect (err ).NotTo (HaveOccurred ())
2259
+ Expect (res ).To (ContainElement ("get" ))
2260
+ })
2145
2261
}
2146
2262
})
2147
2263
@@ -2738,6 +2854,88 @@ func testAdapter(resp3 bool) {
2738
2854
Expect (v ).To (Equal ("c" ))
2739
2855
})
2740
2856
2857
+ if resp3 {
2858
+ It ("should LCS" , func () {
2859
+ err := adapter .MSet (ctx , "LCSkey1{1}" , "ohmytext" , "LCSkey2{1}" , "mynewtext" ).Err ()
2860
+ Expect (err ).NotTo (HaveOccurred ())
2861
+
2862
+ lcs , err := adapter .LCS (ctx , & LCSQuery {
2863
+ Key1 : "LCSkey1{1}" ,
2864
+ Key2 : "LCSkey2{1}" ,
2865
+ }).Result ()
2866
+
2867
+ Expect (err ).NotTo (HaveOccurred ())
2868
+ Expect (lcs .MatchString ).To (Equal ("mytext" ))
2869
+
2870
+ lcs , err = adapter .LCS (ctx , & LCSQuery {
2871
+ Key1 : "LCSnonexistent_key1{1}" ,
2872
+ Key2 : "LCSkey2{1}" ,
2873
+ }).Result ()
2874
+
2875
+ Expect (err ).NotTo (HaveOccurred ())
2876
+ Expect (lcs .MatchString ).To (Equal ("" ))
2877
+
2878
+ lcs , err = adapter .LCS (ctx , & LCSQuery {
2879
+ Key1 : "LCSkey1{1}" ,
2880
+ Key2 : "LCSkey2{1}" ,
2881
+ Len : true ,
2882
+ }).Result ()
2883
+ Expect (err ).NotTo (HaveOccurred ())
2884
+ Expect (lcs .MatchString ).To (Equal ("" ))
2885
+ Expect (lcs .Len ).To (Equal (int64 (6 )))
2886
+
2887
+ lcs , err = adapter .LCS (ctx , & LCSQuery {
2888
+ Key1 : "LCSkey1{1}" ,
2889
+ Key2 : "LCSkey2{1}" ,
2890
+ Idx : true ,
2891
+ }).Result ()
2892
+ Expect (err ).NotTo (HaveOccurred ())
2893
+ Expect (lcs .MatchString ).To (Equal ("" ))
2894
+ Expect (lcs .Len ).To (Equal (int64 (6 )))
2895
+ Expect (lcs .Matches ).To (Equal ([]LCSMatchedPosition {
2896
+ {
2897
+ Key1 : LCSPosition {Start : 4 , End : 7 },
2898
+ Key2 : LCSPosition {Start : 5 , End : 8 },
2899
+ MatchLen : 0 ,
2900
+ },
2901
+ {
2902
+ Key1 : LCSPosition {Start : 2 , End : 3 },
2903
+ Key2 : LCSPosition {Start : 0 , End : 1 },
2904
+ MatchLen : 0 ,
2905
+ },
2906
+ }))
2907
+
2908
+ lcs , err = adapter .LCS (ctx , & LCSQuery {
2909
+ Key1 : "LCSkey1{1}" ,
2910
+ Key2 : "LCSkey2{1}" ,
2911
+ Idx : true ,
2912
+ MinMatchLen : 3 ,
2913
+ WithMatchLen : true ,
2914
+ }).Result ()
2915
+ Expect (err ).NotTo (HaveOccurred ())
2916
+ Expect (lcs .MatchString ).To (Equal ("" ))
2917
+ Expect (lcs .Len ).To (Equal (int64 (6 )))
2918
+ Expect (lcs .Matches ).To (Equal ([]LCSMatchedPosition {
2919
+ {
2920
+ Key1 : LCSPosition {Start : 4 , End : 7 },
2921
+ Key2 : LCSPosition {Start : 5 , End : 8 },
2922
+ MatchLen : 4 ,
2923
+ },
2924
+ }))
2925
+
2926
+ _ , err = adapter .Set (ctx , "keywithstringvalue{1}" , "golang" , 0 ).Result ()
2927
+ Expect (err ).NotTo (HaveOccurred ())
2928
+ _ , err = adapter .LPush (ctx , "keywithnonstringvalue{1}" , "somevalue" ).Result ()
2929
+ Expect (err ).NotTo (HaveOccurred ())
2930
+ _ , err = adapter .LCS (ctx , & LCSQuery {
2931
+ Key1 : "keywithstringvalue{1}" ,
2932
+ Key2 : "keywithnonstringvalue{1}" ,
2933
+ }).Result ()
2934
+ Expect (err ).To (HaveOccurred ())
2935
+ Expect (err .Error ()).To (Equal ("The specified keys must contain string values" ))
2936
+ })
2937
+ }
2938
+
2741
2939
It ("should LIndex" , func () {
2742
2940
lPush := adapter .LPush (ctx , "list" , "World" )
2743
2941
Expect (lPush .Err ()).NotTo (HaveOccurred ())
@@ -7108,6 +7306,98 @@ func testAdapterCache(resp3 bool) {
7108
7306
Expect (x .Err ()).NotTo (HaveOccurred ())
7109
7307
Expect (x .Text ()).To (Equal ("Function 2" ))
7110
7308
})
7309
+
7310
+ It ("Shows function stats" , func () {
7311
+ defer func () {
7312
+ for i := 0 ; i < 30 ; i ++ {
7313
+ adapter .FunctionKill (ctx )
7314
+ }
7315
+ }()
7316
+
7317
+ // We can not run blocking commands in Redis functions, so we're using an infinite loop,
7318
+ // but we're killing the function after calling FUNCTION STATS
7319
+ lib := Library {
7320
+ Name : "mylib1" ,
7321
+ Engine : "LUA" ,
7322
+ Functions : []Function {
7323
+ {
7324
+ Name : "lib1_func1" ,
7325
+ Description : "This is the func-1 of lib 1" ,
7326
+ Flags : []string {"no-writes" },
7327
+ },
7328
+ },
7329
+ Code : `#!lua name=%s
7330
+ local function f1(keys, args)
7331
+ local i = 0
7332
+ while true do
7333
+ i = i + 1
7334
+ end
7335
+ end
7336
+
7337
+ redis.register_function{
7338
+ function_name='%s',
7339
+ description ='%s',
7340
+ callback=f1,
7341
+ flags={'%s'}
7342
+ }` ,
7343
+ }
7344
+ libCode := fmt .Sprintf (lib .Code , lib .Name , lib .Functions [0 ].Name ,
7345
+ lib .Functions [0 ].Description , lib .Functions [0 ].Flags [0 ])
7346
+ err := adapter .FunctionLoad (ctx , libCode ).Err ()
7347
+
7348
+ Expect (err ).NotTo (HaveOccurred ())
7349
+
7350
+ r , err := adapter .FunctionStats (ctx ).Result ()
7351
+ Expect (err ).NotTo (HaveOccurred ())
7352
+ Expect (len (r .Engines )).To (Equal (1 ))
7353
+ Expect (r .Running ()).To (BeFalse ())
7354
+
7355
+ started := make (chan bool , 1 )
7356
+ go func () {
7357
+ defer GinkgoRecover ()
7358
+
7359
+ for addr := range clientresp3 .Nodes () {
7360
+ client2 , err := rueidis .NewClient (rueidis.ClientOption {InitAddress : []string {addr }})
7361
+ Expect (err ).NotTo (HaveOccurred ())
7362
+ adapter2 := NewAdapter (client2 )
7363
+ started <- true
7364
+ adapter2 .FCall (ctx , lib .Functions [0 ].Name , nil ).Result ()
7365
+ break
7366
+ }
7367
+ }()
7368
+
7369
+ <- started
7370
+ time .Sleep (1 * time .Second )
7371
+ r , err = adapter .FunctionStats (ctx ).Result ()
7372
+
7373
+ Expect (err ).NotTo (HaveOccurred ())
7374
+ Expect (len (r .Engines )).To (Equal (1 ))
7375
+ rs , isRunning := r .RunningScript ()
7376
+ Expect (isRunning ).To (BeTrue ())
7377
+ Expect (rs .Name ).To (Equal (lib .Functions [0 ].Name ))
7378
+ Expect (rs .Duration > 0 ).To (BeTrue ())
7379
+
7380
+ close (started )
7381
+ })
7382
+ })
7383
+
7384
+ Describe ("SlowLogGet" , func () {
7385
+ It ("returns slow query result" , func () {
7386
+ const key = "slowlog-log-slower-than"
7387
+
7388
+ old := adapter .ConfigGet (ctx , key ).Val ()
7389
+ adapter .ConfigSet (ctx , key , "0" )
7390
+ defer adapter .ConfigSet (ctx , key , old [key ])
7391
+
7392
+ err := adapter .SlowLogReset (ctx ).Err ()
7393
+ Expect (err ).NotTo (HaveOccurred ())
7394
+
7395
+ adapter .Set (ctx , "test" , "true" , 0 )
7396
+
7397
+ result , err := adapter .SlowLogGet (ctx , - 1 ).Result ()
7398
+ Expect (err ).NotTo (HaveOccurred ())
7399
+ Expect (len (result )).NotTo (BeZero ())
7400
+ })
7111
7401
})
7112
7402
}
7113
7403
0 commit comments