mirror of
				https://github.com/redis/go-redis.git
				synced 2025-11-04 02:33:24 +03:00 
			
		
		
		
	* chore: extract benchmark tests * wip * enable pubsub tests * enable ring tests * stop tests with build redis from source * start all tests * mix of makefile and action * add sentinel configs * fix example test * stop debug on re * wip * enable gears for redis 7.2 * wip * enable sentinel, they are expected to fail * fix: linter configuration * chore: update re versions * return older redis enterprise version * add basic codeql * wip: increase timeout, focus only sentinel tests * sentinels with docker network host * enable all tests * fix flanky test * enable example tests * tidy docker compose * add debug output * stop shutingdown masters * don't test sentinel for re * skip unsuported addscores * Update README bump go version in CI * Update README.md Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * Update CONTRIBUTING.md add information about new test setup --------- Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
		
			
				
	
	
		
			450 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
			
		
		
	
	
			450 lines
		
	
	
		
			13 KiB
		
	
	
	
		
			Go
		
	
	
	
	
	
package redis_test
 | 
						|
 | 
						|
import (
 | 
						|
	"context"
 | 
						|
 | 
						|
	"github.com/redis/go-redis/v9"
 | 
						|
 | 
						|
	. "github.com/bsm/ginkgo/v2"
 | 
						|
	. "github.com/bsm/gomega"
 | 
						|
)
 | 
						|
 | 
						|
var TestUserName string = "goredis"
 | 
						|
var _ = Describe("ACL", func() {
 | 
						|
	var client *redis.Client
 | 
						|
	var ctx context.Context
 | 
						|
 | 
						|
	BeforeEach(func() {
 | 
						|
		ctx = context.Background()
 | 
						|
		opt := redisOptions()
 | 
						|
		client = redis.NewClient(opt)
 | 
						|
	})
 | 
						|
 | 
						|
	It("should ACL LOG", Label("NonRedisEnterprise"), func() {
 | 
						|
		Expect(client.ACLLogReset(ctx).Err()).NotTo(HaveOccurred())
 | 
						|
		err := client.Do(ctx, "acl", "setuser", "test", ">test", "on", "allkeys", "+get").Err()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
 | 
						|
		clientAcl := redis.NewClient(redisOptions())
 | 
						|
		clientAcl.Options().Username = "test"
 | 
						|
		clientAcl.Options().Password = "test"
 | 
						|
		clientAcl.Options().DB = 0
 | 
						|
		_ = clientAcl.Set(ctx, "mystring", "foo", 0).Err()
 | 
						|
		_ = clientAcl.HSet(ctx, "myhash", "foo", "bar").Err()
 | 
						|
		_ = clientAcl.SAdd(ctx, "myset", "foo", "bar").Err()
 | 
						|
 | 
						|
		logEntries, err := client.ACLLog(ctx, 10).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(len(logEntries)).To(Equal(4))
 | 
						|
 | 
						|
		for _, entry := range logEntries {
 | 
						|
			Expect(entry.Reason).To(Equal("command"))
 | 
						|
			Expect(entry.Context).To(Equal("toplevel"))
 | 
						|
			Expect(entry.Object).NotTo(BeEmpty())
 | 
						|
			Expect(entry.Username).To(Equal("test"))
 | 
						|
			Expect(entry.AgeSeconds).To(BeNumerically(">=", 0))
 | 
						|
			Expect(entry.ClientInfo).NotTo(BeNil())
 | 
						|
			Expect(entry.EntryID).To(BeNumerically(">=", 0))
 | 
						|
			Expect(entry.TimestampCreated).To(BeNumerically(">=", 0))
 | 
						|
			Expect(entry.TimestampLastUpdated).To(BeNumerically(">=", 0))
 | 
						|
		}
 | 
						|
 | 
						|
		limitedLogEntries, err := client.ACLLog(ctx, 2).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(len(limitedLogEntries)).To(Equal(2))
 | 
						|
 | 
						|
		// cleanup after creating the user
 | 
						|
		err = client.Do(ctx, "acl", "deluser", "test").Err()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("should ACL LOG RESET", Label("NonRedisEnterprise"), func() {
 | 
						|
		// Call ACL LOG RESET
 | 
						|
		resetCmd := client.ACLLogReset(ctx)
 | 
						|
		Expect(resetCmd.Err()).NotTo(HaveOccurred())
 | 
						|
		Expect(resetCmd.Val()).To(Equal("OK"))
 | 
						|
 | 
						|
		// Verify that the log is empty after the reset
 | 
						|
		logEntries, err := client.ACLLog(ctx, 10).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(len(logEntries)).To(Equal(0))
 | 
						|
	})
 | 
						|
 | 
						|
})
 | 
						|
var _ = Describe("ACL user commands", Label("NonRedisEnterprise"), func() {
 | 
						|
	var client *redis.Client
 | 
						|
	var ctx context.Context
 | 
						|
 | 
						|
	BeforeEach(func() {
 | 
						|
		ctx = context.Background()
 | 
						|
		opt := redisOptions()
 | 
						|
		client = redis.NewClient(opt)
 | 
						|
	})
 | 
						|
 | 
						|
	AfterEach(func() {
 | 
						|
		_, err := client.ACLDelUser(context.Background(), TestUserName).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(client.Close()).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("list only default user", func() {
 | 
						|
		res, err := client.ACLList(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(res).To(HaveLen(1))
 | 
						|
		Expect(res[0]).To(ContainSubstring("default"))
 | 
						|
	})
 | 
						|
 | 
						|
	It("setuser and deluser", func() {
 | 
						|
		res, err := client.ACLList(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(res).To(HaveLen(1))
 | 
						|
		Expect(res[0]).To(ContainSubstring("default"))
 | 
						|
 | 
						|
		add, err := client.ACLSetUser(ctx, TestUserName, "nopass", "on", "allkeys", "+set", "+get").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		resAfter, err := client.ACLList(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(resAfter).To(HaveLen(2))
 | 
						|
		Expect(resAfter[1]).To(ContainSubstring(TestUserName))
 | 
						|
 | 
						|
		deletedN, err := client.ACLDelUser(ctx, TestUserName).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(deletedN).To(BeNumerically("==", 1))
 | 
						|
 | 
						|
		resAfterDeletion, err := client.ACLList(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(resAfterDeletion).To(HaveLen(1))
 | 
						|
		Expect(resAfterDeletion[0]).To(BeEquivalentTo(res[0]))
 | 
						|
	})
 | 
						|
 | 
						|
	It("should acl dryrun", func() {
 | 
						|
		dryRun := client.ACLDryRun(ctx, "default", "get", "randomKey")
 | 
						|
		Expect(dryRun.Err()).NotTo(HaveOccurred())
 | 
						|
		Expect(dryRun.Val()).To(Equal("OK"))
 | 
						|
	})
 | 
						|
})
 | 
						|
 | 
						|
var _ = Describe("ACL permissions", Label("NonRedisEnterprise"), func() {
 | 
						|
	var client *redis.Client
 | 
						|
	var ctx context.Context
 | 
						|
 | 
						|
	BeforeEach(func() {
 | 
						|
		ctx = context.Background()
 | 
						|
		opt := redisOptions()
 | 
						|
		opt.UnstableResp3 = true
 | 
						|
		client = redis.NewClient(opt)
 | 
						|
	})
 | 
						|
 | 
						|
	AfterEach(func() {
 | 
						|
		_, err := client.ACLDelUser(context.Background(), TestUserName).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(client.Close()).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("reset permissions", func() {
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		connection := client.Conn()
 | 
						|
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		_, err = connection.Get(ctx, "anykey").Result()
 | 
						|
		Expect(err).To(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("add write permissions", func() {
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
			"~*",
 | 
						|
			"+SET",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		connection := client.Conn()
 | 
						|
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		// can write
 | 
						|
		v, err := connection.Set(ctx, "anykey", "anyvalue", 0).Result()
 | 
						|
		Expect(err).ToNot(HaveOccurred())
 | 
						|
		Expect(v).To(Equal("OK"))
 | 
						|
 | 
						|
		// but can't read
 | 
						|
		value, err := connection.Get(ctx, "anykey").Result()
 | 
						|
		Expect(err).To(HaveOccurred())
 | 
						|
		Expect(value).To(BeEmpty())
 | 
						|
	})
 | 
						|
 | 
						|
	It("add read permissions", func() {
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
			"~*",
 | 
						|
			"+GET",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		connection := client.Conn()
 | 
						|
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		// can read
 | 
						|
		value, err := connection.Get(ctx, "anykey").Result()
 | 
						|
		Expect(err).ToNot(HaveOccurred())
 | 
						|
		Expect(value).To(Equal("anyvalue"))
 | 
						|
 | 
						|
		// but can't delete
 | 
						|
		del, err := connection.Del(ctx, "anykey").Result()
 | 
						|
		Expect(err).To(HaveOccurred())
 | 
						|
		Expect(del).ToNot(Equal(1))
 | 
						|
	})
 | 
						|
 | 
						|
	It("add del permissions", func() {
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
			"~*",
 | 
						|
			"+DEL",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		connection := client.Conn()
 | 
						|
		authed, err := connection.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		// can read
 | 
						|
		del, err := connection.Del(ctx, "anykey").Result()
 | 
						|
		Expect(err).ToNot(HaveOccurred())
 | 
						|
		Expect(del).To(BeEquivalentTo(1))
 | 
						|
	})
 | 
						|
 | 
						|
	It("set permissions for module commands", func() {
 | 
						|
		SkipBeforeRedisVersion(8, "permissions for modules are supported for Redis Version >=8")
 | 
						|
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
 | 
						|
		val, err := client.FTCreate(ctx, "txt", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "txt", FieldType: redis.SearchFieldTypeText}).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(val).To(BeEquivalentTo("OK"))
 | 
						|
		WaitForIndexing(client, "txt")
 | 
						|
		client.HSet(ctx, "doc1", "txt", "foo baz")
 | 
						|
		client.HSet(ctx, "doc2", "txt", "foo bar")
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
			"~*",
 | 
						|
			"+FT.SEARCH",
 | 
						|
			"-FT.DROPINDEX",
 | 
						|
			"+json.set",
 | 
						|
			"+json.get",
 | 
						|
			"-json.clear",
 | 
						|
			"+bf.reserve",
 | 
						|
			"-bf.info",
 | 
						|
			"+cf.reserve",
 | 
						|
			"+cms.initbydim",
 | 
						|
			"+topk.reserve",
 | 
						|
			"+tdigest.create",
 | 
						|
			"+ts.create",
 | 
						|
			"-ts.info",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		c := client.Conn()
 | 
						|
		authed, err := c.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		// has perm for search
 | 
						|
		Expect(c.FTSearch(ctx, "txt", "foo ~bar").Err()).NotTo(HaveOccurred())
 | 
						|
 | 
						|
		// no perm for dropindex
 | 
						|
		err = c.FTDropIndex(ctx, "txt").Err()
 | 
						|
		Expect(err).ToNot(BeEmpty())
 | 
						|
		Expect(err.Error()).To(ContainSubstring("NOPERM"))
 | 
						|
 | 
						|
		// json set and get have perm
 | 
						|
		Expect(c.JSONSet(ctx, "foo", "$", "\"bar\"").Err()).NotTo(HaveOccurred())
 | 
						|
		Expect(c.JSONGet(ctx, "foo", "$").Val()).To(BeEquivalentTo("[\"bar\"]"))
 | 
						|
 | 
						|
		// no perm for json clear
 | 
						|
		err = c.JSONClear(ctx, "foo", "$").Err()
 | 
						|
		Expect(err).ToNot(BeEmpty())
 | 
						|
		Expect(err.Error()).To(ContainSubstring("NOPERM"))
 | 
						|
 | 
						|
		// perm for reserve
 | 
						|
		Expect(c.BFReserve(ctx, "bloom", 0.01, 100).Err()).NotTo(HaveOccurred())
 | 
						|
 | 
						|
		// no perm for info
 | 
						|
		err = c.BFInfo(ctx, "bloom").Err()
 | 
						|
		Expect(err).ToNot(BeEmpty())
 | 
						|
		Expect(err.Error()).To(ContainSubstring("NOPERM"))
 | 
						|
 | 
						|
		// perm for cf.reserve
 | 
						|
		Expect(c.CFReserve(ctx, "cfres", 100).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for cms.initbydim
 | 
						|
		Expect(c.CMSInitByDim(ctx, "cmsdim", 100, 5).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for topk.reserve
 | 
						|
		Expect(c.TopKReserve(ctx, "topk", 10).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for tdigest.create
 | 
						|
		Expect(c.TDigestCreate(ctx, "tdc").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for ts.create
 | 
						|
		Expect(c.TSCreate(ctx, "tsts").Err()).NotTo(HaveOccurred())
 | 
						|
		// noperm for ts.info
 | 
						|
		err = c.TSInfo(ctx, "tsts").Err()
 | 
						|
		Expect(err).ToNot(BeEmpty())
 | 
						|
		Expect(err.Error()).To(ContainSubstring("NOPERM"))
 | 
						|
 | 
						|
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("set permissions for module categories", func() {
 | 
						|
		SkipBeforeRedisVersion(8, "permissions for modules are supported for Redis Version >=8")
 | 
						|
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
 | 
						|
		val, err := client.FTCreate(ctx, "txt", &redis.FTCreateOptions{}, &redis.FieldSchema{FieldName: "txt", FieldType: redis.SearchFieldTypeText}).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(val).To(BeEquivalentTo("OK"))
 | 
						|
		WaitForIndexing(client, "txt")
 | 
						|
		client.HSet(ctx, "doc1", "txt", "foo baz")
 | 
						|
		client.HSet(ctx, "doc2", "txt", "foo bar")
 | 
						|
		add, err := client.ACLSetUser(ctx,
 | 
						|
			TestUserName,
 | 
						|
			"reset",
 | 
						|
			"nopass",
 | 
						|
			"on",
 | 
						|
			"~*",
 | 
						|
			"+@search",
 | 
						|
			"+@json",
 | 
						|
			"+@bloom",
 | 
						|
			"+@cuckoo",
 | 
						|
			"+@topk",
 | 
						|
			"+@cms",
 | 
						|
			"+@timeseries",
 | 
						|
			"+@tdigest",
 | 
						|
		).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(add).To(Equal("OK"))
 | 
						|
 | 
						|
		c := client.Conn()
 | 
						|
		authed, err := c.AuthACL(ctx, TestUserName, "").Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(authed).To(Equal("OK"))
 | 
						|
 | 
						|
		// has perm for search
 | 
						|
		Expect(c.FTSearch(ctx, "txt", "foo ~bar").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for dropindex
 | 
						|
		Expect(c.FTDropIndex(ctx, "txt").Err()).NotTo(HaveOccurred())
 | 
						|
		// json set and get have perm
 | 
						|
		Expect(c.JSONSet(ctx, "foo", "$", "\"bar\"").Err()).NotTo(HaveOccurred())
 | 
						|
		Expect(c.JSONGet(ctx, "foo", "$").Val()).To(BeEquivalentTo("[\"bar\"]"))
 | 
						|
		// perm for json clear
 | 
						|
		Expect(c.JSONClear(ctx, "foo", "$").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for reserve
 | 
						|
		Expect(c.BFReserve(ctx, "bloom", 0.01, 100).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for info
 | 
						|
		Expect(c.BFInfo(ctx, "bloom").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for cf.reserve
 | 
						|
		Expect(c.CFReserve(ctx, "cfres", 100).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for cms.initbydim
 | 
						|
		Expect(c.CMSInitByDim(ctx, "cmsdim", 100, 5).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for topk.reserve
 | 
						|
		Expect(c.TopKReserve(ctx, "topk", 10).Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for tdigest.create
 | 
						|
		Expect(c.TDigestCreate(ctx, "tdc").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for ts.create
 | 
						|
		Expect(c.TSCreate(ctx, "tsts").Err()).NotTo(HaveOccurred())
 | 
						|
		// perm for ts.info
 | 
						|
		Expect(c.TSInfo(ctx, "tsts").Err()).NotTo(HaveOccurred())
 | 
						|
 | 
						|
		Expect(client.FlushDB(ctx).Err()).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
})
 | 
						|
 | 
						|
var _ = Describe("ACL Categories", func() {
 | 
						|
	var client *redis.Client
 | 
						|
	var ctx context.Context
 | 
						|
 | 
						|
	BeforeEach(func() {
 | 
						|
		ctx = context.Background()
 | 
						|
		opt := redisOptions()
 | 
						|
		client = redis.NewClient(opt)
 | 
						|
	})
 | 
						|
 | 
						|
	AfterEach(func() {
 | 
						|
		Expect(client.Close()).NotTo(HaveOccurred())
 | 
						|
	})
 | 
						|
 | 
						|
	It("lists acl categories and subcategories", func() {
 | 
						|
		res, err := client.ACLCat(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(len(res)).To(BeNumerically(">", 20))
 | 
						|
		Expect(res).To(ContainElements(
 | 
						|
			"read",
 | 
						|
			"write",
 | 
						|
			"keyspace",
 | 
						|
			"dangerous",
 | 
						|
			"slow",
 | 
						|
			"set",
 | 
						|
			"sortedset",
 | 
						|
			"list",
 | 
						|
			"hash",
 | 
						|
		))
 | 
						|
 | 
						|
		res, err = client.ACLCatArgs(ctx, &redis.ACLCatArgs{Category: "read"}).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(res).To(ContainElement("get"))
 | 
						|
	})
 | 
						|
 | 
						|
	It("lists acl categories and subcategories with Modules", func() {
 | 
						|
		SkipBeforeRedisVersion(8, "modules are included in acl for redis version >= 8")
 | 
						|
		aclTestCase := map[string]string{
 | 
						|
			"search":     "FT.CREATE",
 | 
						|
			"bloom":      "bf.add",
 | 
						|
			"json":       "json.get",
 | 
						|
			"cuckoo":     "cf.insert",
 | 
						|
			"cms":        "cms.query",
 | 
						|
			"topk":       "topk.list",
 | 
						|
			"tdigest":    "tdigest.rank",
 | 
						|
			"timeseries": "ts.range",
 | 
						|
		}
 | 
						|
		var cats []interface{}
 | 
						|
 | 
						|
		for cat, subitem := range aclTestCase {
 | 
						|
			cats = append(cats, cat)
 | 
						|
 | 
						|
			res, err := client.ACLCatArgs(ctx, &redis.ACLCatArgs{
 | 
						|
				Category: cat,
 | 
						|
			}).Result()
 | 
						|
			Expect(err).NotTo(HaveOccurred())
 | 
						|
			Expect(res).To(ContainElement(subitem))
 | 
						|
		}
 | 
						|
 | 
						|
		res, err := client.ACLCat(ctx).Result()
 | 
						|
		Expect(err).NotTo(HaveOccurred())
 | 
						|
		Expect(res).To(ContainElements(cats...))
 | 
						|
	})
 | 
						|
})
 |