Skip to content

Commit 0c45a77

Browse files
authored
Merge branch 'master' into redis#3139-add-encoding-BinaryUnmarshaler-scan
2 parents b976e28 + efe0f65 commit 0c45a77

7 files changed

+374
-6
lines changed

.github/workflows/build.yml

+44-1
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,47 @@ jobs:
4242
uses: codecov/codecov-action@v5
4343
with:
4444
files: coverage.txt
45-
token: ${{ secrets.CODECOV_TOKEN }}
45+
token: ${{ secrets.CODECOV_TOKEN }}
46+
47+
test-redis-ce:
48+
name: test-redis-ce
49+
runs-on: ubuntu-latest
50+
strategy:
51+
fail-fast: false
52+
matrix:
53+
redis_version:
54+
- "8.0-M01"
55+
- "7.4.1"
56+
- "7.2.6"
57+
- "6.2.16"
58+
go-version:
59+
- "1.19.x"
60+
- "1.20.x"
61+
- "1.21.x"
62+
63+
steps:
64+
- name: Set up ${{ matrix.go-version }}
65+
uses: actions/setup-go@v5
66+
with:
67+
go-version: ${{ matrix.go-version }}
68+
69+
- name: Checkout code
70+
uses: actions/checkout@v4
71+
72+
# Set up Docker Compose environment
73+
- name: Set up Docker Compose environment
74+
run: |
75+
docker compose --profile all up -d
76+
77+
- name: Run tests
78+
env:
79+
USE_CONTAINERIZED_REDIS: "true"
80+
RE_CLUSTER: "true"
81+
run: |
82+
go test \
83+
--ginkgo.skip-file="ring_test.go" \
84+
--ginkgo.skip-file="sentinel_test.go" \
85+
--ginkgo.skip-file="osscluster_test.go" \
86+
--ginkgo.skip-file="pubsub_test.go" \
87+
--ginkgo.skip-file="gears_commands_test.go" \
88+
--ginkgo.label-filter='!NonRedisEnterprise'

.github/workflows/test-redis-enterprise.yml

+1
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,7 @@ jobs:
4747
- name: Test
4848
env:
4949
RE_CLUSTER: "1"
50+
USE_CONTAINERIZED_REDIS: "1"
5051
run: |
5152
go test \
5253
--ginkgo.skip-file="ring_test.go" \

docker-compose.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
---
2+
3+
services:
4+
5+
redis-stanalone:
6+
image: redislabs/client-libs-test:8.0-M02
7+
container_name: redis-standalone
8+
environment:
9+
- REDIS_CLUSTER=no
10+
- PORT=6379
11+
- TLS_PORT=6666
12+
13+
ports:
14+
- 6379:6379
15+
- 6380:6379
16+
- 6666:6666 # TLS port
17+
volumes:
18+
- "./dockers/redis-standalone:/redis/work"
19+
profiles:
20+
- standalone
21+
- all

doctests/cmds_hash_test.go

+111-3
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ package example_commands_test
55
import (
66
"context"
77
"fmt"
8+
"sort"
89

910
"github.com/redis/go-redis/v9"
1011
)
@@ -74,8 +75,20 @@ func ExampleClient_hset() {
7475
panic(err)
7576
}
7677

77-
fmt.Println(res6)
78-
// >>> map[field1:Hello field2:Hi field3:World]
78+
keys := make([]string, 0, len(res6))
79+
80+
for key, _ := range res6 {
81+
keys = append(keys, key)
82+
}
83+
84+
sort.Strings(keys)
85+
86+
for _, key := range keys {
87+
fmt.Printf("Key: %v, value: %v\n", key, res6[key])
88+
}
89+
// >>> Key: field1, value: Hello
90+
// >>> Key: field2, value: Hi
91+
// >>> Key: field3, value: World
7992
// STEP_END
8093

8194
// Output:
@@ -84,7 +97,9 @@ func ExampleClient_hset() {
8497
// 2
8598
// Hi
8699
// World
87-
// map[field1:Hello field2:Hi field3:World]
100+
// Key: field1, value: Hello
101+
// Key: field2, value: Hi
102+
// Key: field3, value: World
88103
}
89104

90105
func ExampleClient_hget() {
@@ -131,3 +146,96 @@ func ExampleClient_hget() {
131146
// foo
132147
// redis: nil
133148
}
149+
150+
func ExampleClient_hgetall() {
151+
ctx := context.Background()
152+
153+
rdb := redis.NewClient(&redis.Options{
154+
Addr: "localhost:6379",
155+
Password: "", // no password
156+
DB: 0, // use default DB
157+
})
158+
159+
// REMOVE_START
160+
rdb.Del(ctx, "myhash")
161+
// REMOVE_END
162+
163+
// STEP_START hgetall
164+
hGetAllResult1, err := rdb.HSet(ctx, "myhash",
165+
"field1", "Hello",
166+
"field2", "World",
167+
).Result()
168+
169+
if err != nil {
170+
panic(err)
171+
}
172+
173+
fmt.Println(hGetAllResult1) // >>> 2
174+
175+
hGetAllResult2, err := rdb.HGetAll(ctx, "myhash").Result()
176+
177+
if err != nil {
178+
panic(err)
179+
}
180+
181+
keys := make([]string, 0, len(hGetAllResult2))
182+
183+
for key, _ := range hGetAllResult2 {
184+
keys = append(keys, key)
185+
}
186+
187+
sort.Strings(keys)
188+
189+
for _, key := range keys {
190+
fmt.Printf("Key: %v, value: %v\n", key, hGetAllResult2[key])
191+
}
192+
// >>> Key: field1, value: Hello
193+
// >>> Key: field2, value: World
194+
// STEP_END
195+
196+
// Output:
197+
// 2
198+
// Key: field1, value: Hello
199+
// Key: field2, value: World
200+
}
201+
202+
func ExampleClient_hvals() {
203+
ctx := context.Background()
204+
205+
rdb := redis.NewClient(&redis.Options{
206+
Addr: "localhost:6379",
207+
Password: "", // no password docs
208+
DB: 0, // use default DB
209+
})
210+
211+
// REMOVE_START
212+
rdb.Del(ctx, "myhash")
213+
// REMOVE_END
214+
215+
// STEP_START hvals
216+
hValsResult1, err := rdb.HSet(ctx, "myhash",
217+
"field1", "Hello",
218+
"field2", "World",
219+
).Result()
220+
221+
if err != nil {
222+
panic(err)
223+
}
224+
225+
fmt.Println(hValsResult1) // >>> 2
226+
227+
hValsResult2, err := rdb.HVals(ctx, "myhash").Result()
228+
229+
if err != nil {
230+
panic(err)
231+
}
232+
233+
sort.Strings(hValsResult2)
234+
235+
fmt.Println(hValsResult2) // >>> [Hello World]
236+
// STEP_END
237+
238+
// Output:
239+
// 2
240+
// [Hello World]
241+
}

doctests/pipe_trans_example_test.go

+180
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,180 @@
1+
// EXAMPLE: pipe_trans_tutorial
2+
// HIDE_START
3+
package example_commands_test
4+
5+
import (
6+
"context"
7+
"fmt"
8+
9+
"github.com/redis/go-redis/v9"
10+
)
11+
12+
// HIDE_END
13+
14+
func ExampleClient_transactions() {
15+
ctx := context.Background()
16+
17+
rdb := redis.NewClient(&redis.Options{
18+
Addr: "localhost:6379",
19+
Password: "", // no password docs
20+
DB: 0, // use default DB
21+
})
22+
// REMOVE_START
23+
for i := 0; i < 5; i++ {
24+
rdb.Del(ctx, fmt.Sprintf("seat:%d", i))
25+
}
26+
27+
rdb.Del(ctx, "counter:1", "counter:2", "counter:3", "shellpath")
28+
// REMOVE_END
29+
30+
// STEP_START basic_pipe
31+
pipe := rdb.Pipeline()
32+
33+
for i := 0; i < 5; i++ {
34+
pipe.Set(ctx, fmt.Sprintf("seat:%v", i), fmt.Sprintf("#%v", i), 0)
35+
}
36+
37+
cmds, err := pipe.Exec(ctx)
38+
39+
if err != nil {
40+
panic(err)
41+
}
42+
43+
for _, c := range cmds {
44+
fmt.Printf("%v;", c.(*redis.StatusCmd).Val())
45+
}
46+
47+
fmt.Println("")
48+
// >>> OK;OK;OK;OK;OK;
49+
50+
pipe = rdb.Pipeline()
51+
52+
get0Result := pipe.Get(ctx, "seat:0")
53+
get3Result := pipe.Get(ctx, "seat:3")
54+
get4Result := pipe.Get(ctx, "seat:4")
55+
56+
cmds, err = pipe.Exec(ctx)
57+
58+
// The results are available only after the pipeline
59+
// has finished executing.
60+
fmt.Println(get0Result.Val()) // >>> #0
61+
fmt.Println(get3Result.Val()) // >>> #3
62+
fmt.Println(get4Result.Val()) // >>> #4
63+
// STEP_END
64+
65+
// STEP_START basic_pipe_pipelined
66+
var pd0Result *redis.StatusCmd
67+
var pd3Result *redis.StatusCmd
68+
var pd4Result *redis.StatusCmd
69+
70+
cmds, err = rdb.Pipelined(ctx, func(pipe redis.Pipeliner) error {
71+
pd0Result = (*redis.StatusCmd)(pipe.Get(ctx, "seat:0"))
72+
pd3Result = (*redis.StatusCmd)(pipe.Get(ctx, "seat:3"))
73+
pd4Result = (*redis.StatusCmd)(pipe.Get(ctx, "seat:4"))
74+
return nil
75+
})
76+
77+
if err != nil {
78+
panic(err)
79+
}
80+
81+
// The results are available only after the pipeline
82+
// has finished executing.
83+
fmt.Println(pd0Result.Val()) // >>> #0
84+
fmt.Println(pd3Result.Val()) // >>> #3
85+
fmt.Println(pd4Result.Val()) // >>> #4
86+
// STEP_END
87+
88+
// STEP_START basic_trans
89+
trans := rdb.TxPipeline()
90+
91+
trans.IncrBy(ctx, "counter:1", 1)
92+
trans.IncrBy(ctx, "counter:2", 2)
93+
trans.IncrBy(ctx, "counter:3", 3)
94+
95+
cmds, err = trans.Exec(ctx)
96+
97+
for _, c := range cmds {
98+
fmt.Println(c.(*redis.IntCmd).Val())
99+
}
100+
// >>> 1
101+
// >>> 2
102+
// >>> 3
103+
// STEP_END
104+
105+
// STEP_START basic_trans_txpipelined
106+
var tx1Result *redis.IntCmd
107+
var tx2Result *redis.IntCmd
108+
var tx3Result *redis.IntCmd
109+
110+
cmds, err = rdb.TxPipelined(ctx, func(trans redis.Pipeliner) error {
111+
tx1Result = trans.IncrBy(ctx, "counter:1", 1)
112+
tx2Result = trans.IncrBy(ctx, "counter:2", 2)
113+
tx3Result = trans.IncrBy(ctx, "counter:3", 3)
114+
return nil
115+
})
116+
117+
if err != nil {
118+
panic(err)
119+
}
120+
121+
fmt.Println(tx1Result.Val()) // >>> 2
122+
fmt.Println(tx2Result.Val()) // >>> 4
123+
fmt.Println(tx3Result.Val()) // >>> 6
124+
// STEP_END
125+
126+
// STEP_START trans_watch
127+
// Set initial value of `shellpath`.
128+
rdb.Set(ctx, "shellpath", "/usr/syscmds/", 0)
129+
130+
const maxRetries = 1000
131+
132+
// Retry if the key has been changed.
133+
for i := 0; i < maxRetries; i++ {
134+
err := rdb.Watch(ctx,
135+
func(tx *redis.Tx) error {
136+
currentPath, err := rdb.Get(ctx, "shellpath").Result()
137+
newPath := currentPath + ":/usr/mycmds/"
138+
139+
_, err = tx.TxPipelined(ctx, func(pipe redis.Pipeliner) error {
140+
pipe.Set(ctx, "shellpath", newPath, 0)
141+
return nil
142+
})
143+
144+
return err
145+
},
146+
"shellpath",
147+
)
148+
149+
if err == nil {
150+
// Success.
151+
break
152+
} else if err == redis.TxFailedErr {
153+
// Optimistic lock lost. Retry the transaction.
154+
continue
155+
} else {
156+
// Panic for any other error.
157+
panic(err)
158+
}
159+
}
160+
161+
fmt.Println(rdb.Get(ctx, "shellpath").Val())
162+
// >>> /usr/syscmds/:/usr/mycmds/
163+
// STEP_END
164+
165+
// Output:
166+
// OK;OK;OK;OK;OK;
167+
// #0
168+
// #3
169+
// #4
170+
// #0
171+
// #3
172+
// #4
173+
// 1
174+
// 2
175+
// 3
176+
// 2
177+
// 4
178+
// 6
179+
// /usr/syscmds/:/usr/mycmds/
180+
}

0 commit comments

Comments
 (0)