...

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

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

     1  package redis_test
     2  
     3  import (
     4  	"context"
     5  	"encoding/json"
     6  	"time"
     7  
     8  	. "github.com/bsm/ginkgo/v2"
     9  	. "github.com/bsm/gomega"
    10  
    11  	"github.com/redis/go-redis/v9"
    12  )
    13  
    14  type JSONGetTestStruct struct {
    15  	Hello string `json:"hello"`
    16  }
    17  
    18  var _ = Describe("JSON Commands", Label("json"), func() {
    19  	ctx := context.TODO()
    20  	var client *redis.Client
    21  
    22  	setupRedisClient := func(protocolVersion int) *redis.Client {
    23  		return redis.NewClient(&redis.Options{
    24  			Addr:          "localhost:6379",
    25  			DB:            0,
    26  			Protocol:      protocolVersion,
    27  			UnstableResp3: true,
    28  		})
    29  	}
    30  
    31  	AfterEach(func() {
    32  		if client != nil {
    33  			client.FlushDB(ctx)
    34  			client.Close()
    35  		}
    36  	})
    37  
    38  	protocols := []int{2, 3}
    39  	for _, protocol := range protocols {
    40  		BeforeEach(func() {
    41  			client = setupRedisClient(protocol)
    42  			Expect(client.FlushAll(ctx).Err()).NotTo(HaveOccurred())
    43  		})
    44  
    45  		Describe("arrays", Label("arrays"), func() {
    46  			It("should JSONArrAppend", Label("json.arrappend", "json"), func() {
    47  				cmd1 := client.JSONSet(ctx, "append2", "$", `{"a": [10], "b": {"a": [12, 13]}}`)
    48  				Expect(cmd1.Err()).NotTo(HaveOccurred())
    49  				Expect(cmd1.Val()).To(Equal("OK"))
    50  
    51  				cmd2 := client.JSONArrAppend(ctx, "append2", "$..a", 10)
    52  				Expect(cmd2.Err()).NotTo(HaveOccurred())
    53  				Expect(cmd2.Val()).To(Equal([]int64{2, 3}))
    54  			})
    55  
    56  			It("should JSONArrIndex and JSONArrIndexWithArgs", Label("json.arrindex", "json"), func() {
    57  				cmd1, err := client.JSONSet(ctx, "index1", "$", `{"a": [10], "b": {"a": [12, 10]}}`).Result()
    58  				Expect(err).NotTo(HaveOccurred())
    59  				Expect(cmd1).To(Equal("OK"))
    60  
    61  				cmd2, err := client.JSONArrIndex(ctx, "index1", "$.b.a", 10).Result()
    62  				Expect(err).NotTo(HaveOccurred())
    63  				Expect(cmd2).To(Equal([]int64{1}))
    64  
    65  				cmd3, err := client.JSONSet(ctx, "index2", "$", `[0,1,2,3,4]`).Result()
    66  				Expect(err).NotTo(HaveOccurred())
    67  				Expect(cmd3).To(Equal("OK"))
    68  
    69  				res, err := client.JSONArrIndex(ctx, "index2", "$", 1).Result()
    70  				Expect(err).NotTo(HaveOccurred())
    71  				Expect(res[0]).To(Equal(int64(1)))
    72  
    73  				res, err = client.JSONArrIndex(ctx, "index2", "$", 1, 2).Result()
    74  				Expect(err).NotTo(HaveOccurred())
    75  				Expect(res[0]).To(Equal(int64(-1)))
    76  
    77  				res, err = client.JSONArrIndex(ctx, "index2", "$", 4).Result()
    78  				Expect(err).NotTo(HaveOccurred())
    79  				Expect(res[0]).To(Equal(int64(4)))
    80  
    81  				res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{}, 4).Result()
    82  				Expect(err).NotTo(HaveOccurred())
    83  				Expect(res[0]).To(Equal(int64(4)))
    84  
    85  				stop := 5000
    86  				res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result()
    87  				Expect(err).NotTo(HaveOccurred())
    88  				Expect(res[0]).To(Equal(int64(4)))
    89  
    90  				stop = -1
    91  				res, err = client.JSONArrIndexWithArgs(ctx, "index2", "$", &redis.JSONArrIndexArgs{Stop: &stop}, 4).Result()
    92  				Expect(err).NotTo(HaveOccurred())
    93  				Expect(res[0]).To(Equal(int64(-1)))
    94  			})
    95  
    96  			It("should JSONArrIndex and JSONArrIndexWithArgs with $", Label("json.arrindex", "json"), func() {
    97  				doc := `{
    98  					"store": {
    99  						"book": [
   100  							{
   101  								"category": "reference",
   102  								"author": "Nigel Rees",
   103  								"title": "Sayings of the Century",
   104  								"price": 8.95,
   105  								"size": [10, 20, 30, 40]
   106  							},
   107  							{
   108  								"category": "fiction",
   109  								"author": "Evelyn Waugh",
   110  								"title": "Sword of Honour",
   111  								"price": 12.99,
   112  								"size": [50, 60, 70, 80]
   113  							},
   114  							{
   115  								"category": "fiction",
   116  								"author": "Herman Melville",
   117  								"title": "Moby Dick",
   118  								"isbn": "0-553-21311-3",
   119  								"price": 8.99,
   120  								"size": [5, 10, 20, 30]
   121  							},
   122  							{
   123  								"category": "fiction",
   124  								"author": "J. R. R. Tolkien",
   125  								"title": "The Lord of the Rings",
   126  								"isbn": "0-395-19395-8",
   127  								"price": 22.99,
   128  								"size": [5, 6, 7, 8]
   129  							}
   130  						],
   131  						"bicycle": {"color": "red", "price": 19.95}
   132  					}
   133  				}`
   134  				res, err := client.JSONSet(ctx, "doc1", "$", doc).Result()
   135  				Expect(err).NotTo(HaveOccurred())
   136  				Expect(res).To(Equal("OK"))
   137  
   138  				resGet, err := client.JSONGet(ctx, "doc1", "$.store.book[?(@.price<10)].size").Result()
   139  				Expect(err).NotTo(HaveOccurred())
   140  				Expect(resGet).To(Equal("[[10,20,30,40],[5,10,20,30]]"))
   141  
   142  				resArr, err := client.JSONArrIndex(ctx, "doc1", "$.store.book[?(@.price<10)].size", 20).Result()
   143  				Expect(err).NotTo(HaveOccurred())
   144  				Expect(resArr).To(Equal([]int64{1, 2}))
   145  
   146  				_, err = client.JSONGet(ctx, "this-key-does-not-exist", "$").Result()
   147  				Expect(err).To(HaveOccurred())
   148  				Expect(err).To(BeIdenticalTo(redis.Nil))
   149  			})
   150  
   151  			It("should JSONArrInsert", Label("json.arrinsert", "json"), func() {
   152  				cmd1 := client.JSONSet(ctx, "insert2", "$", `[100, 200, 300, 200]`)
   153  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   154  				Expect(cmd1.Val()).To(Equal("OK"))
   155  
   156  				cmd2 := client.JSONArrInsert(ctx, "insert2", "$", -1, 1, 2)
   157  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   158  				Expect(cmd2.Val()).To(Equal([]int64{6}))
   159  
   160  				cmd3 := client.JSONGet(ctx, "insert2")
   161  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   162  				// RESP2 vs RESP3
   163  				Expect(cmd3.Val()).To(Or(
   164  					Equal(`[100,200,300,1,2,200]`),
   165  					Equal(`[[100,200,300,1,2,200]]`)))
   166  			})
   167  
   168  			It("should JSONArrLen", Label("json.arrlen", "json"), func() {
   169  				cmd1 := client.JSONSet(ctx, "length2", "$", `{"a": [10], "b": {"a": [12, 10, 20, 12, 90, 10]}}`)
   170  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   171  				Expect(cmd1.Val()).To(Equal("OK"))
   172  
   173  				cmd2 := client.JSONArrLen(ctx, "length2", "$..a")
   174  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   175  				Expect(cmd2.Val()).To(Equal([]int64{1, 6}))
   176  			})
   177  
   178  			It("should JSONArrPop", Label("json.arrpop"), func() {
   179  				cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`)
   180  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   181  				Expect(cmd1.Val()).To(Equal("OK"))
   182  
   183  				cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2)
   184  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   185  				Expect(cmd2.Val()).To(Equal([]string{"300"}))
   186  
   187  				cmd3 := client.JSONGet(ctx, "pop4", "$")
   188  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   189  				Expect(cmd3.Val()).To(Equal("[[100,200,200]]"))
   190  			})
   191  
   192  			It("should JSONArrTrim", Label("json.arrtrim", "json"), func() {
   193  				cmd1, err := client.JSONSet(ctx, "trim1", "$", `[0,1,2,3,4]`).Result()
   194  				Expect(err).NotTo(HaveOccurred())
   195  				Expect(cmd1).To(Equal("OK"))
   196  
   197  				stop := 3
   198  				cmd2, err := client.JSONArrTrimWithArgs(ctx, "trim1", "$", &redis.JSONArrTrimArgs{Start: 1, Stop: &stop}).Result()
   199  				Expect(err).NotTo(HaveOccurred())
   200  				Expect(cmd2).To(Equal([]int64{3}))
   201  
   202  				res, err := client.JSONGet(ctx, "trim1", "$").Result()
   203  				Expect(err).NotTo(HaveOccurred())
   204  				Expect(res).To(Equal(`[[1,2,3]]`))
   205  
   206  				cmd3, err := client.JSONSet(ctx, "trim2", "$", `[0,1,2,3,4]`).Result()
   207  				Expect(err).NotTo(HaveOccurred())
   208  				Expect(cmd3).To(Equal("OK"))
   209  
   210  				stop = 3
   211  				cmd4, err := client.JSONArrTrimWithArgs(ctx, "trim2", "$", &redis.JSONArrTrimArgs{Start: -1, Stop: &stop}).Result()
   212  				Expect(err).NotTo(HaveOccurred())
   213  				Expect(cmd4).To(Equal([]int64{0}))
   214  
   215  				cmd5, err := client.JSONSet(ctx, "trim3", "$", `[0,1,2,3,4]`).Result()
   216  				Expect(err).NotTo(HaveOccurred())
   217  				Expect(cmd5).To(Equal("OK"))
   218  
   219  				stop = 99
   220  				cmd6, err := client.JSONArrTrimWithArgs(ctx, "trim3", "$", &redis.JSONArrTrimArgs{Start: 3, Stop: &stop}).Result()
   221  				Expect(err).NotTo(HaveOccurred())
   222  				Expect(cmd6).To(Equal([]int64{2}))
   223  
   224  				cmd7, err := client.JSONSet(ctx, "trim4", "$", `[0,1,2,3,4]`).Result()
   225  				Expect(err).NotTo(HaveOccurred())
   226  				Expect(cmd7).To(Equal("OK"))
   227  
   228  				stop = 1
   229  				cmd8, err := client.JSONArrTrimWithArgs(ctx, "trim4", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result()
   230  				Expect(err).NotTo(HaveOccurred())
   231  				Expect(cmd8).To(Equal([]int64{0}))
   232  
   233  				cmd9, err := client.JSONSet(ctx, "trim5", "$", `[0,1,2,3,4]`).Result()
   234  				Expect(err).NotTo(HaveOccurred())
   235  				Expect(cmd9).To(Equal("OK"))
   236  
   237  				stop = 11
   238  				cmd10, err := client.JSONArrTrimWithArgs(ctx, "trim5", "$", &redis.JSONArrTrimArgs{Start: 9, Stop: &stop}).Result()
   239  				Expect(err).NotTo(HaveOccurred())
   240  				Expect(cmd10).To(Equal([]int64{0}))
   241  			})
   242  
   243  			It("should JSONArrPop", Label("json.arrpop", "json"), func() {
   244  				cmd1 := client.JSONSet(ctx, "pop4", "$", `[100, 200, 300, 200]`)
   245  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   246  				Expect(cmd1.Val()).To(Equal("OK"))
   247  
   248  				cmd2 := client.JSONArrPop(ctx, "pop4", "$", 2)
   249  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   250  				Expect(cmd2.Val()).To(Equal([]string{"300"}))
   251  
   252  				cmd3 := client.JSONGet(ctx, "pop4", "$")
   253  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   254  				Expect(cmd3.Val()).To(Equal("[[100,200,200]]"))
   255  			})
   256  		})
   257  
   258  		Describe("get/set", Label("getset"), func() {
   259  			It("should JSONSet", Label("json.set", "json"), func() {
   260  				cmd := client.JSONSet(ctx, "set1", "$", `{"a": 1, "b": 2, "hello": "world"}`)
   261  				Expect(cmd.Err()).NotTo(HaveOccurred())
   262  				Expect(cmd.Val()).To(Equal("OK"))
   263  			})
   264  
   265  			It("should JSONGet", Label("json.get", "json", "NonRedisEnterprise"), func() {
   266  				res, err := client.JSONSet(ctx, "get3", "$", `{"a": 1, "b": 2}`).Result()
   267  				Expect(err).NotTo(HaveOccurred())
   268  				Expect(res).To(Equal("OK"))
   269  
   270  				res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-"}).Result()
   271  				Expect(err).NotTo(HaveOccurred())
   272  				Expect(res).To(Equal(`{-"a":1,-"b":2}`))
   273  
   274  				res, err = client.JSONGetWithArgs(ctx, "get3", &redis.JSONGetArgs{Indent: "-", Newline: `~`, Space: `!`}).Result()
   275  				Expect(err).NotTo(HaveOccurred())
   276  				Expect(res).To(Equal(`{~-"a":!1,~-"b":!2~}`))
   277  			})
   278  
   279  			It("should JSONMerge", Label("json.merge", "json"), func() {
   280  				res, err := client.JSONSet(ctx, "merge1", "$", `{"a": 1, "b": 2}`).Result()
   281  				Expect(err).NotTo(HaveOccurred())
   282  				Expect(res).To(Equal("OK"))
   283  
   284  				res, err = client.JSONMerge(ctx, "merge1", "$", `{"b": 3, "c": 4}`).Result()
   285  				Expect(err).NotTo(HaveOccurred())
   286  				Expect(res).To(Equal("OK"))
   287  
   288  				res, err = client.JSONGet(ctx, "merge1", "$").Result()
   289  				Expect(err).NotTo(HaveOccurred())
   290  				Expect(res).To(Equal(`[{"a":1,"b":3,"c":4}]`))
   291  			})
   292  
   293  			It("should JSONMSet", Label("json.mset", "json", "NonRedisEnterprise"), func() {
   294  				doc1 := redis.JSONSetArgs{Key: "mset1", Path: "$", Value: `{"a": 1}`}
   295  				doc2 := redis.JSONSetArgs{Key: "mset2", Path: "$", Value: 2}
   296  				docs := []redis.JSONSetArgs{doc1, doc2}
   297  
   298  				mSetResult, err := client.JSONMSetArgs(ctx, docs).Result()
   299  				Expect(err).NotTo(HaveOccurred())
   300  				Expect(mSetResult).To(Equal("OK"))
   301  
   302  				res, err := client.JSONMGet(ctx, "$", "mset1").Result()
   303  				Expect(err).NotTo(HaveOccurred())
   304  				Expect(res).To(Equal([]interface{}{`[{"a":1}]`}))
   305  
   306  				res, err = client.JSONMGet(ctx, "$", "mset1", "mset2").Result()
   307  				Expect(err).NotTo(HaveOccurred())
   308  				Expect(res).To(Equal([]interface{}{`[{"a":1}]`, "[2]"}))
   309  
   310  				_, err = client.JSONMSet(ctx, "mset1", "$.a", 2, "mset3", "$", `[1]`).Result()
   311  				Expect(err).NotTo(HaveOccurred())
   312  			})
   313  
   314  			It("should JSONMGet", Label("json.mget", "json", "NonRedisEnterprise"), func() {
   315  				cmd1 := client.JSONSet(ctx, "mget2a", "$", `{"a": ["aa", "ab", "ac", "ad"], "b": {"a": ["ba", "bb", "bc", "bd"]}}`)
   316  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   317  				Expect(cmd1.Val()).To(Equal("OK"))
   318  				cmd2 := client.JSONSet(ctx, "mget2b", "$", `{"a": [100, 200, 300, 200], "b": {"a": [100, 200, 300, 200]}}`)
   319  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   320  				Expect(cmd2.Val()).To(Equal("OK"))
   321  
   322  				cmd3 := client.JSONMGet(ctx, "$..a", "mget2a", "mget2b")
   323  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   324  				Expect(cmd3.Val()).To(HaveLen(2))
   325  				Expect(cmd3.Val()[0]).To(Equal(`[["aa","ab","ac","ad"],["ba","bb","bc","bd"]]`))
   326  				Expect(cmd3.Val()[1]).To(Equal(`[[100,200,300,200],[100,200,300,200]]`))
   327  			})
   328  
   329  			It("should JSONMget with $", Label("json.mget", "json", "NonRedisEnterprise"), func() {
   330  				res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "b": 2, "nested": {"a": 3}, "c": "", "nested2": {"a": ""}}`).Result()
   331  				Expect(err).NotTo(HaveOccurred())
   332  				Expect(res).To(Equal("OK"))
   333  
   334  				res, err = client.JSONSet(ctx, "doc2", "$", `{"a": 4, "b": 5, "nested": {"a": 6}, "c": "", "nested2": {"a": [""]}}`).Result()
   335  				Expect(err).NotTo(HaveOccurred())
   336  				Expect(res).To(Equal("OK"))
   337  
   338  				iRes, err := client.JSONMGet(ctx, "$..a", "doc1").Result()
   339  				Expect(err).NotTo(HaveOccurred())
   340  				Expect(iRes).To(Equal([]interface{}{`[1,3,""]`}))
   341  
   342  				iRes, err = client.JSONMGet(ctx, "$..a", "doc1", "doc2").Result()
   343  				Expect(err).NotTo(HaveOccurred())
   344  				Expect(iRes).To(Equal([]interface{}{`[1,3,""]`, `[4,6,[""]]`}))
   345  
   346  				iRes, err = client.JSONMGet(ctx, "$..a", "non_existing_doc", "non_existing_doc1").Result()
   347  				Expect(err).NotTo(HaveOccurred())
   348  				Expect(iRes).To(Equal([]interface{}{nil, nil}))
   349  			})
   350  		})
   351  
   352  		Describe("Misc", Label("misc"), func() {
   353  			It("should JSONClear", Label("json.clear", "json"), func() {
   354  				cmd1 := client.JSONSet(ctx, "clear1", "$", `[1]`)
   355  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   356  				Expect(cmd1.Val()).To(Equal("OK"))
   357  
   358  				cmd2 := client.JSONClear(ctx, "clear1", "$")
   359  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   360  				Expect(cmd2.Val()).To(Equal(int64(1)))
   361  
   362  				cmd3 := client.JSONGet(ctx, "clear1", "$")
   363  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   364  				Expect(cmd3.Val()).To(Equal(`[[]]`))
   365  			})
   366  
   367  			It("should JSONClear with $", Label("json.clear", "json"), func() {
   368  				doc := `{
   369  					"nested1": {"a": {"foo": 10, "bar": 20}},
   370  					"a": ["foo"],
   371  					"nested2": {"a": "claro"},
   372  					"nested3": {"a": {"baz": 50}}
   373  				}`
   374  				res, err := client.JSONSet(ctx, "doc1", "$", doc).Result()
   375  				Expect(err).NotTo(HaveOccurred())
   376  				Expect(res).To(Equal("OK"))
   377  
   378  				iRes, err := client.JSONClear(ctx, "doc1", "$..a").Result()
   379  				Expect(err).NotTo(HaveOccurred())
   380  				Expect(iRes).To(Equal(int64(3)))
   381  
   382  				resGet, err := client.JSONGet(ctx, "doc1", `$`).Result()
   383  				Expect(err).NotTo(HaveOccurred())
   384  				Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":[],"nested2":{"a":"claro"},"nested3":{"a":{}}}]`))
   385  
   386  				res, err = client.JSONSet(ctx, "doc1", "$", doc).Result()
   387  				Expect(err).NotTo(HaveOccurred())
   388  				Expect(res).To(Equal("OK"))
   389  
   390  				iRes, err = client.JSONClear(ctx, "doc1", "$.nested1.a").Result()
   391  				Expect(err).NotTo(HaveOccurred())
   392  				Expect(iRes).To(Equal(int64(1)))
   393  
   394  				resGet, err = client.JSONGet(ctx, "doc1", `$`).Result()
   395  				Expect(err).NotTo(HaveOccurred())
   396  				Expect(resGet).To(Equal(`[{"nested1":{"a":{}},"a":["foo"],"nested2":{"a":"claro"},"nested3":{"a":{"baz":50}}}]`))
   397  			})
   398  
   399  			It("should JSONDel", Label("json.del", "json"), func() {
   400  				cmd1 := client.JSONSet(ctx, "del1", "$", `[1]`)
   401  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   402  				Expect(cmd1.Val()).To(Equal("OK"))
   403  
   404  				cmd2 := client.JSONDel(ctx, "del1", "$")
   405  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   406  				Expect(cmd2.Val()).To(Equal(int64(1)))
   407  
   408  				cmd3 := client.JSONGet(ctx, "del1", "$")
   409  				Expect(cmd3.Err()).To(Equal(redis.Nil))
   410  				Expect(cmd3.Val()).To(Equal(""))
   411  			})
   412  
   413  			It("should JSONDel with $", Label("json.del", "json"), func() {
   414  				res, err := client.JSONSet(ctx, "del1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result()
   415  				Expect(err).NotTo(HaveOccurred())
   416  				Expect(res).To(Equal("OK"))
   417  
   418  				iRes, err := client.JSONDel(ctx, "del1", "$..a").Result()
   419  				Expect(err).NotTo(HaveOccurred())
   420  				Expect(iRes).To(Equal(int64(2)))
   421  
   422  				resGet, err := client.JSONGet(ctx, "del1", "$").Result()
   423  				Expect(err).NotTo(HaveOccurred())
   424  				Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`))
   425  
   426  				res, err = client.JSONSet(ctx, "del2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result()
   427  				Expect(err).NotTo(HaveOccurred())
   428  				Expect(res).To(Equal("OK"))
   429  
   430  				iRes, err = client.JSONDel(ctx, "del2", "$..a").Result()
   431  				Expect(err).NotTo(HaveOccurred())
   432  				Expect(iRes).To(Equal(int64(1)))
   433  
   434  				resGet, err = client.JSONGet(ctx, "del2", "$").Result()
   435  				Expect(err).NotTo(HaveOccurred())
   436  				Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`))
   437  
   438  				doc := `[
   439  					{
   440  						"ciao": ["non ancora"],
   441  						"nested": [
   442  							{"ciao": [1, "a"]},
   443  							{"ciao": [2, "a"]},
   444  							{"ciaoc": [3, "non", "ciao"]},
   445  							{"ciao": [4, "a"]},
   446  							{"e": [5, "non", "ciao"]}
   447  						]
   448  					}
   449  				]`
   450  				res, err = client.JSONSet(ctx, "del3", "$", doc).Result()
   451  				Expect(err).NotTo(HaveOccurred())
   452  				Expect(res).To(Equal("OK"))
   453  
   454  				iRes, err = client.JSONDel(ctx, "del3", `$.[0]["nested"]..ciao`).Result()
   455  				Expect(err).NotTo(HaveOccurred())
   456  				Expect(iRes).To(Equal(int64(3)))
   457  
   458  				resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]`
   459  				resGet, err = client.JSONGet(ctx, "del3", "$").Result()
   460  				Expect(err).NotTo(HaveOccurred())
   461  				Expect(resGet).To(Equal(resVal))
   462  			})
   463  
   464  			It("should JSONForget", Label("json.forget", "json"), func() {
   465  				cmd1 := client.JSONSet(ctx, "forget3", "$", `{"a": [1,2,3], "b": {"a": [1,2,3], "b": "annie"}}`)
   466  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   467  				Expect(cmd1.Val()).To(Equal("OK"))
   468  
   469  				cmd2 := client.JSONForget(ctx, "forget3", "$..a")
   470  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   471  				Expect(cmd2.Val()).To(Equal(int64(2)))
   472  
   473  				cmd3 := client.JSONGet(ctx, "forget3", "$")
   474  				Expect(cmd3.Err()).NotTo(HaveOccurred())
   475  				Expect(cmd3.Val()).To(Equal(`[{"b":{"b":"annie"}}]`))
   476  			})
   477  
   478  			It("should JSONForget with $", Label("json.forget", "json"), func() {
   479  				res, err := client.JSONSet(ctx, "doc1", "$", `{"a": 1, "nested": {"a": 2, "b": 3}}`).Result()
   480  				Expect(err).NotTo(HaveOccurred())
   481  				Expect(res).To(Equal("OK"))
   482  
   483  				iRes, err := client.JSONForget(ctx, "doc1", "$..a").Result()
   484  				Expect(err).NotTo(HaveOccurred())
   485  				Expect(iRes).To(Equal(int64(2)))
   486  
   487  				resGet, err := client.JSONGet(ctx, "doc1", "$").Result()
   488  				Expect(err).NotTo(HaveOccurred())
   489  				Expect(resGet).To(Equal(`[{"nested":{"b":3}}]`))
   490  
   491  				res, err = client.JSONSet(ctx, "doc2", "$", `{"a": {"a": 2, "b": 3}, "b": ["a", "b"], "nested": {"b": [true, "a", "b"]}}`).Result()
   492  				Expect(err).NotTo(HaveOccurred())
   493  				Expect(res).To(Equal("OK"))
   494  
   495  				iRes, err = client.JSONForget(ctx, "doc2", "$..a").Result()
   496  				Expect(err).NotTo(HaveOccurred())
   497  				Expect(iRes).To(Equal(int64(1)))
   498  
   499  				resGet, err = client.JSONGet(ctx, "doc2", "$").Result()
   500  				Expect(err).NotTo(HaveOccurred())
   501  				Expect(resGet).To(Equal(`[{"nested":{"b":[true,"a","b"]},"b":["a","b"]}]`))
   502  
   503  				doc := `[
   504  					{
   505  						"ciao": ["non ancora"],
   506  						"nested": [
   507  							{"ciao": [1, "a"]},
   508  							{"ciao": [2, "a"]},
   509  							{"ciaoc": [3, "non", "ciao"]},
   510  							{"ciao": [4, "a"]},
   511  							{"e": [5, "non", "ciao"]}
   512  						]
   513  					}
   514  				]`
   515  				res, err = client.JSONSet(ctx, "doc3", "$", doc).Result()
   516  				Expect(err).NotTo(HaveOccurred())
   517  				Expect(res).To(Equal("OK"))
   518  
   519  				iRes, err = client.JSONForget(ctx, "doc3", `$.[0]["nested"]..ciao`).Result()
   520  				Expect(err).NotTo(HaveOccurred())
   521  				Expect(iRes).To(Equal(int64(3)))
   522  
   523  				resVal := `[[{"ciao":["non ancora"],"nested":[{},{},{"ciaoc":[3,"non","ciao"]},{},{"e":[5,"non","ciao"]}]}]]`
   524  				resGet, err = client.JSONGet(ctx, "doc3", "$").Result()
   525  				Expect(err).NotTo(HaveOccurred())
   526  				Expect(resGet).To(Equal(resVal))
   527  			})
   528  
   529  			It("should JSONNumIncrBy", Label("json.numincrby", "json"), func() {
   530  				cmd1 := client.JSONSet(ctx, "incr3", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`)
   531  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   532  				Expect(cmd1.Val()).To(Equal("OK"))
   533  
   534  				cmd2 := client.JSONNumIncrBy(ctx, "incr3", "$..a[1]", float64(1))
   535  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   536  				Expect(cmd2.Val()).To(Equal(`[3,0]`))
   537  			})
   538  
   539  			It("should JSONNumIncrBy with $", Label("json.numincrby", "json"), func() {
   540  				res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result()
   541  				Expect(err).NotTo(HaveOccurred())
   542  				Expect(res).To(Equal("OK"))
   543  
   544  				res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 2).Result()
   545  				Expect(err).NotTo(HaveOccurred())
   546  				Expect(res).To(Equal(`[7]`))
   547  
   548  				res, err = client.JSONNumIncrBy(ctx, "doc1", "$.b[1].a", 3.5).Result()
   549  				Expect(err).NotTo(HaveOccurred())
   550  				Expect(res).To(Equal(`[10.5]`))
   551  
   552  				res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "b", "b": [{"a": 2}, {"a": 5.0}, {"a": "c"}]}`).Result()
   553  				Expect(err).NotTo(HaveOccurred())
   554  				Expect(res).To(Equal("OK"))
   555  
   556  				res, err = client.JSONNumIncrBy(ctx, "doc2", "$.b[0].a", 3).Result()
   557  				Expect(err).NotTo(HaveOccurred())
   558  				Expect(res).To(Equal(`[5]`))
   559  			})
   560  
   561  			It("should JSONObjKeys", Label("json.objkeys", "json"), func() {
   562  				cmd1 := client.JSONSet(ctx, "objkeys1", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`)
   563  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   564  				Expect(cmd1.Val()).To(Equal("OK"))
   565  
   566  				cmd2 := client.JSONObjKeys(ctx, "objkeys1", "$..*")
   567  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   568  				Expect(cmd2.Val()).To(HaveLen(7))
   569  				Expect(cmd2.Val()).To(Equal([]interface{}{nil, []interface{}{"a"}, nil, nil, nil, nil, nil}))
   570  			})
   571  
   572  			It("should JSONObjKeys with $", Label("json.objkeys", "json"), func() {
   573  				doc := `{
   574  					"nested1": {"a": {"foo": 10, "bar": 20}},
   575  					"a": ["foo"],
   576  					"nested2": {"a": {"baz": 50}}
   577  				}`
   578  				cmd1, err := client.JSONSet(ctx, "objkeys1", "$", doc).Result()
   579  				Expect(err).NotTo(HaveOccurred())
   580  				Expect(cmd1).To(Equal("OK"))
   581  
   582  				cmd2, err := client.JSONObjKeys(ctx, "objkeys1", "$.nested1.a").Result()
   583  				Expect(err).NotTo(HaveOccurred())
   584  				Expect(cmd2).To(Equal([]interface{}{[]interface{}{"foo", "bar"}}))
   585  
   586  				cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".*.a").Result()
   587  				Expect(err).NotTo(HaveOccurred())
   588  				Expect(cmd2).To(Equal([]interface{}{"foo", "bar"}))
   589  
   590  				cmd2, err = client.JSONObjKeys(ctx, "objkeys1", ".nested2.a").Result()
   591  				Expect(err).NotTo(HaveOccurred())
   592  				Expect(cmd2).To(Equal([]interface{}{"baz"}))
   593  
   594  				_, err = client.JSONObjKeys(ctx, "non_existing_doc", "..a").Result()
   595  				Expect(err).To(HaveOccurred())
   596  			})
   597  
   598  			It("should JSONObjLen", Label("json.objlen", "json"), func() {
   599  				cmd1 := client.JSONSet(ctx, "objlen2", "$", `{"a": [1, 2], "b": {"a": [0, -1]}}`)
   600  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   601  				Expect(cmd1.Val()).To(Equal("OK"))
   602  
   603  				cmd2 := client.JSONObjLen(ctx, "objlen2", "$..*")
   604  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   605  				Expect(cmd2.Val()).To(HaveLen(7))
   606  				Expect(cmd2.Val()[0]).To(BeNil())
   607  				Expect(*cmd2.Val()[1]).To(Equal(int64(1)))
   608  			})
   609  
   610  			It("should JSONStrLen", Label("json.strlen", "json"), func() {
   611  				cmd1 := client.JSONSet(ctx, "strlen2", "$", `{"a": "alice", "b": "bob", "c": {"a": "alice", "b": "bob"}}`)
   612  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   613  				Expect(cmd1.Val()).To(Equal("OK"))
   614  
   615  				cmd2 := client.JSONStrLen(ctx, "strlen2", "$..*")
   616  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   617  				Expect(cmd2.Val()).To(HaveLen(5))
   618  				var tmp int64 = 20
   619  				Expect(cmd2.Val()[0]).To(BeAssignableToTypeOf(&tmp))
   620  				Expect(*cmd2.Val()[0]).To(Equal(int64(5)))
   621  				Expect(*cmd2.Val()[1]).To(Equal(int64(3)))
   622  				Expect(cmd2.Val()[2]).To(BeNil())
   623  				Expect(*cmd2.Val()[3]).To(Equal(int64(5)))
   624  				Expect(*cmd2.Val()[4]).To(Equal(int64(3)))
   625  			})
   626  
   627  			It("should JSONStrAppend", Label("json.strappend", "json"), func() {
   628  				cmd1, err := client.JSONSet(ctx, "strapp1", "$", `"foo"`).Result()
   629  				Expect(err).NotTo(HaveOccurred())
   630  				Expect(cmd1).To(Equal("OK"))
   631  				cmd2, err := client.JSONStrAppend(ctx, "strapp1", "$", `"bar"`).Result()
   632  				Expect(err).NotTo(HaveOccurred())
   633  				Expect(*cmd2[0]).To(Equal(int64(6)))
   634  				cmd3, err := client.JSONGet(ctx, "strapp1", "$").Result()
   635  				Expect(err).NotTo(HaveOccurred())
   636  				Expect(cmd3).To(Equal(`["foobar"]`))
   637  			})
   638  
   639  			It("should JSONStrAppend and JSONStrLen with $", Label("json.strappend", "json.strlen", "json"), func() {
   640  				res, err := client.JSONSet(ctx, "doc1", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result()
   641  				Expect(err).NotTo(HaveOccurred())
   642  				Expect(res).To(Equal("OK"))
   643  
   644  				intArrayResult, err := client.JSONStrAppend(ctx, "doc1", "$.nested1.a", `"baz"`).Result()
   645  				Expect(err).NotTo(HaveOccurred())
   646  				Expect(*intArrayResult[0]).To(Equal(int64(8)))
   647  
   648  				res, err = client.JSONSet(ctx, "doc2", "$", `{"a": "foo", "nested1": {"a": "hello"}, "nested2": {"a": 31}}`).Result()
   649  				Expect(err).NotTo(HaveOccurred())
   650  				Expect(res).To(Equal("OK"))
   651  
   652  				intResult, err := client.JSONStrLen(ctx, "doc2", "$.nested1.a").Result()
   653  				Expect(err).NotTo(HaveOccurred())
   654  				Expect(*intResult[0]).To(Equal(int64(5)))
   655  			})
   656  
   657  			It("should JSONToggle", Label("json.toggle", "json"), func() {
   658  				cmd1 := client.JSONSet(ctx, "toggle1", "$", `[true]`)
   659  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   660  				Expect(cmd1.Val()).To(Equal("OK"))
   661  
   662  				cmd2 := client.JSONToggle(ctx, "toggle1", "$[0]")
   663  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   664  				Expect(cmd2.Val()).To(HaveLen(1))
   665  				Expect(*cmd2.Val()[0]).To(Equal(int64(0)))
   666  			})
   667  
   668  			It("should JSONType", Label("json.type", "json"), func() {
   669  				cmd1 := client.JSONSet(ctx, "type1", "$", `[true]`)
   670  				Expect(cmd1.Err()).NotTo(HaveOccurred())
   671  				Expect(cmd1.Val()).To(Equal("OK"))
   672  
   673  				cmd2 := client.JSONType(ctx, "type1", "$[0]")
   674  				Expect(cmd2.Err()).NotTo(HaveOccurred())
   675  				Expect(cmd2.Val()).To(HaveLen(1))
   676  				// RESP2 v RESP3
   677  				Expect(cmd2.Val()[0]).To(Or(Equal([]interface{}{"boolean"}), Equal("boolean")))
   678  			})
   679  		})
   680  
   681  		Describe("JSON Nil Handling", func() {
   682  			It("should return redis.Nil for non-existent key", func() {
   683  				_, err := client.JSONGet(ctx, "non-existent-key", "$").Result()
   684  				Expect(err).To(Equal(redis.Nil))
   685  			})
   686  
   687  			It("should return empty array for non-existent path in existing key", func() {
   688  				err := client.JSONSet(ctx, "test-key", "$", `{"a": 1, "b": "hello"}`).Err()
   689  				Expect(err).NotTo(HaveOccurred())
   690  
   691  				// Non-existent path should return empty array, not error
   692  				val, err := client.JSONGet(ctx, "test-key", "$.nonexistent").Result()
   693  				Expect(err).NotTo(HaveOccurred())
   694  				Expect(val).To(Equal("[]"))
   695  			})
   696  
   697  			It("should distinguish empty array from non-existent path", func() {
   698  				err := client.JSONSet(ctx, "test-key", "$", `{"arr": [], "obj": {}}`).Err()
   699  				Expect(err).NotTo(HaveOccurred())
   700  
   701  				// Empty array should return the array
   702  				val, err := client.JSONGet(ctx, "test-key", "$.arr").Result()
   703  				Expect(err).NotTo(HaveOccurred())
   704  				Expect(val).To(Equal("[[]]"))
   705  
   706  				// Non-existent field should return empty array
   707  				val, err = client.JSONGet(ctx, "test-key", "$.missing").Result()
   708  				Expect(err).NotTo(HaveOccurred())
   709  				Expect(val).To(Equal("[]"))
   710  			})
   711  
   712  			It("should handle multiple paths with mixed results", func() {
   713  				err := client.JSONSet(ctx, "test-key", "$", `{"a": 1, "b": 2}`).Err()
   714  				Expect(err).NotTo(HaveOccurred())
   715  
   716  				// Path that exists
   717  				val, err := client.JSONGet(ctx, "test-key", "$.a").Result()
   718  				Expect(err).NotTo(HaveOccurred())
   719  				Expect(val).To(Equal("[1]"))
   720  
   721  				// Path that doesn't exist should return empty array
   722  				val, err = client.JSONGet(ctx, "test-key", "$.c").Result()
   723  				Expect(err).NotTo(HaveOccurred())
   724  				Expect(val).To(Equal("[]"))
   725  			})
   726  
   727  			AfterEach(func() {
   728  				// Clean up test keys
   729  				client.Del(ctx, "test-key", "non-existent-key")
   730  			})
   731  		})
   732  	}
   733  })
   734  
   735  var _ = Describe("Go-Redis Advanced JSON and RediSearch Tests", func() {
   736  	var client *redis.Client
   737  	var ctx = context.Background()
   738  
   739  	setupRedisClient := func(protocolVersion int) *redis.Client {
   740  		return redis.NewClient(&redis.Options{
   741  			Addr:          "localhost:6379",
   742  			DB:            0,
   743  			Protocol:      protocolVersion, // Setting RESP2 or RESP3 protocol
   744  			UnstableResp3: true,            // Enable RESP3 features
   745  		})
   746  	}
   747  
   748  	AfterEach(func() {
   749  		if client != nil {
   750  			client.FlushDB(ctx)
   751  			client.Close()
   752  		}
   753  	})
   754  
   755  	Context("when testing with RESP2 and RESP3", func() {
   756  		protocols := []int{2, 3}
   757  
   758  		for _, protocol := range protocols {
   759  			When("using protocol version", func() {
   760  				BeforeEach(func() {
   761  					client = setupRedisClient(protocol)
   762  				})
   763  
   764  				It("should perform complex JSON and RediSearch operations", func() {
   765  					jsonDoc := map[string]interface{}{
   766  						"person": map[string]interface{}{
   767  							"name":   "Alice",
   768  							"age":    30,
   769  							"status": true,
   770  							"address": map[string]interface{}{
   771  								"city":     "Wonderland",
   772  								"postcode": "12345",
   773  							},
   774  							"contacts": []map[string]interface{}{
   775  								{"type": "email", "value": "alice@example.com"},
   776  								{"type": "phone", "value": "+123456789"},
   777  								{"type": "fax", "value": "+987654321"},
   778  							},
   779  							"friends": []map[string]interface{}{
   780  								{"name": "Bob", "age": 35, "status": true},
   781  								{"name": "Charlie", "age": 28, "status": false},
   782  							},
   783  						},
   784  						"settings": map[string]interface{}{
   785  							"notifications": map[string]interface{}{
   786  								"email":  true,
   787  								"sms":    false,
   788  								"alerts": []string{"low battery", "door open"},
   789  							},
   790  							"theme": "dark",
   791  						},
   792  					}
   793  
   794  					setCmd := client.JSONSet(ctx, "person:1", ".", jsonDoc)
   795  					Expect(setCmd.Err()).NotTo(HaveOccurred(), "JSON.SET failed")
   796  
   797  					getCmdRaw := client.JSONGet(ctx, "person:1", ".")
   798  					rawJSON, err := getCmdRaw.Result()
   799  					Expect(err).NotTo(HaveOccurred(), "JSON.GET (raw) failed")
   800  					GinkgoWriter.Printf("Raw JSON: %s\n", rawJSON)
   801  
   802  					getCmdExpanded := client.JSONGet(ctx, "person:1", ".")
   803  					expandedJSON, err := getCmdExpanded.Expanded()
   804  					Expect(err).NotTo(HaveOccurred(), "JSON.GET (expanded) failed")
   805  					GinkgoWriter.Printf("Expanded JSON: %+v\n", expandedJSON)
   806  
   807  					Expect(rawJSON).To(MatchJSON(jsonMustMarshal(expandedJSON)))
   808  
   809  					arrAppendCmd := client.JSONArrAppend(ctx, "person:1", "$.person.contacts", `{"type": "social", "value": "@alice_wonder"}`)
   810  					Expect(arrAppendCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRAPPEND failed")
   811  					arrLenCmd := client.JSONArrLen(ctx, "person:1", "$.person.contacts")
   812  					arrLen, err := arrLenCmd.Result()
   813  					Expect(err).NotTo(HaveOccurred(), "JSON.ARRLEN failed")
   814  					Expect(arrLen).To(Equal([]int64{4}), "Array length mismatch after append")
   815  
   816  					arrInsertCmd := client.JSONArrInsert(ctx, "person:1", "$.person.friends", 1, `{"name": "Diana", "age": 25, "status": true}`)
   817  					Expect(arrInsertCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRINSERT failed")
   818  
   819  					start := 0
   820  					stop := 1
   821  					arrTrimCmd := client.JSONArrTrimWithArgs(ctx, "person:1", "$.person.friends", &redis.JSONArrTrimArgs{Start: start, Stop: &stop})
   822  					Expect(arrTrimCmd.Err()).NotTo(HaveOccurred(), "JSON.ARRTRIM failed")
   823  
   824  					mergeData := map[string]interface{}{
   825  						"status":    false,
   826  						"nickname":  "WonderAlice",
   827  						"lastLogin": time.Now().Format(time.RFC3339),
   828  					}
   829  					mergeCmd := client.JSONMerge(ctx, "person:1", "$.person", jsonMustMarshal(mergeData))
   830  					Expect(mergeCmd.Err()).NotTo(HaveOccurred(), "JSON.MERGE failed")
   831  
   832  					typeCmd := client.JSONType(ctx, "person:1", "$.person.nickname")
   833  					nicknameType, err := typeCmd.Result()
   834  					Expect(err).NotTo(HaveOccurred(), "JSON.TYPE failed")
   835  					Expect(nicknameType[0]).To(Equal([]interface{}{"string"}), "JSON.TYPE mismatch for nickname")
   836  
   837  					createIndexCmd := client.Do(ctx, "FT.CREATE", "person_idx", "ON", "JSON",
   838  						"PREFIX", "1", "person:", "SCHEMA",
   839  						"$.person.name", "AS", "name", "TEXT",
   840  						"$.person.age", "AS", "age", "NUMERIC",
   841  						"$.person.address.city", "AS", "city", "TEXT",
   842  						"$.person.contacts[*].value", "AS", "contact_value", "TEXT",
   843  					)
   844  					Expect(createIndexCmd.Err()).NotTo(HaveOccurred(), "FT.CREATE failed")
   845  
   846  					searchCmd := client.FTSearchWithArgs(ctx, "person_idx", "@contact_value:(alice\\@example\\.com alice_wonder)", &redis.FTSearchOptions{Return: []redis.FTSearchReturn{{FieldName: "$.person.name"}, {FieldName: "$.person.age"}, {FieldName: "$.person.address.city"}}})
   847  					searchResult, err := searchCmd.Result()
   848  					Expect(err).NotTo(HaveOccurred(), "FT.SEARCH failed")
   849  					GinkgoWriter.Printf("Advanced Search result: %+v\n", searchResult)
   850  
   851  					incrCmd := client.JSONNumIncrBy(ctx, "person:1", "$.person.age", 5)
   852  					incrResult, err := incrCmd.Result()
   853  					Expect(err).NotTo(HaveOccurred(), "JSON.NUMINCRBY failed")
   854  					Expect(incrResult).To(Equal("[35]"), "Age increment mismatch")
   855  
   856  					delCmd := client.JSONDel(ctx, "person:1", "$.settings.notifications.email")
   857  					Expect(delCmd.Err()).NotTo(HaveOccurred(), "JSON.DEL failed")
   858  
   859  					typeCmd = client.JSONType(ctx, "person:1", "$.settings.notifications.email")
   860  					typeResult, err := typeCmd.Result()
   861  					Expect(err).ToNot(HaveOccurred())
   862  					Expect(typeResult[0]).To(BeEmpty(), "Expected JSON.TYPE to be empty for deleted field")
   863  				})
   864  			})
   865  		}
   866  	})
   867  })
   868  
   869  // Helper function to marshal data into JSON for comparisons
   870  func jsonMustMarshal(v interface{}) string {
   871  	bytes, err := json.Marshal(v)
   872  	Expect(err).NotTo(HaveOccurred())
   873  	return string(bytes)
   874  }
   875  

View as plain text