-
Notifications
You must be signed in to change notification settings - Fork 2.4k
Expand file tree
/
Copy pathwait_test.go
More file actions
107 lines (99 loc) · 3.19 KB
/
Copy pathwait_test.go
File metadata and controls
107 lines (99 loc) · 3.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
package micro
import (
"context"
"errors"
"sync/atomic"
"testing"
"time"
"go-micro.dev/v6/registry"
)
type waitingRegistry struct {
registry.Registry
get func(string, ...registry.GetOption) ([]*registry.Service, error)
}
func (r waitingRegistry) GetService(name string, opts ...registry.GetOption) ([]*registry.Service, error) {
return r.get(name, opts...)
}
func TestWaitForServiceRetriesDiscoveryAndProbe(t *testing.T) {
var lookups, probes int
transient := errors.New("not ready")
reg := waitingRegistry{get: func(_ string, opts ...registry.GetOption) ([]*registry.Service, error) {
lookups++
var options registry.GetOptions
for _, opt := range opts {
opt(&options)
}
if options.Context == nil {
t.Error("missing lookup context")
}
if lookups == 1 {
return nil, transient
}
if lookups == 2 {
return []*registry.Service{{Nodes: []*registry.Node{{Address: ""}}}}, nil
}
return []*registry.Service{{Nodes: []*registry.Node{{Address: "localhost:1"}}}}, nil
}}
svc := NewService("caller", Registry(reg))
ctx, cancel := context.WithTimeout(context.Background(), time.Second)
defer cancel()
err := WaitForService(ctx, svc, "dependency", WaitBackoff(time.Millisecond, 2*time.Millisecond), WaitProbe(func(context.Context) error {
probes++
if probes == 1 {
return transient
}
return nil
}))
if err != nil || lookups != 4 || probes != 2 {
t.Fatalf("err=%v lookups=%d probes=%d", err, lookups, probes)
}
}
func TestWaitForServiceCancellation(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
entered, release := make(chan struct{}), make(chan struct{})
defer close(release)
var calls atomic.Int32
reg := waitingRegistry{get: func(string, ...registry.GetOption) ([]*registry.Service, error) {
calls.Add(1)
close(entered)
<-release
return nil, registry.ErrNotFound
}}
svc := NewService("caller", Registry(reg))
done := make(chan error, 1)
go func() { done <- WaitForService(ctx, svc, "dependency") }()
<-entered
cancel()
select {
case err := <-done:
if !errors.Is(err, context.Canceled) {
t.Fatal(err)
}
case <-time.After(time.Second):
t.Fatal("cancellation blocked behind registry")
}
if calls.Load() != 1 {
t.Fatal("unexpected extra lookup")
}
}
func TestWaitForServiceCanceledBeforeLookup(t *testing.T) {
ctx, cancel := context.WithCancel(context.Background())
cancel()
reg := waitingRegistry{get: func(string, ...registry.GetOption) ([]*registry.Service, error) {
t.Error("lookup after cancellation")
return nil, nil
}}
if err := WaitForService(ctx, NewService("caller", Registry(reg)), "dependency"); !errors.Is(err, context.Canceled) {
t.Fatal(err)
}
}
func TestWaitForServiceDeadlinePreservesDiscoveryError(t *testing.T) {
cause := errors.New("registry unavailable")
reg := waitingRegistry{get: func(string, ...registry.GetOption) ([]*registry.Service, error) { return nil, cause }}
ctx, cancel := context.WithTimeout(context.Background(), 20*time.Millisecond)
defer cancel()
err := WaitForService(ctx, NewService("caller", Registry(reg)), "dependency", WaitBackoff(time.Millisecond, time.Millisecond))
if !errors.Is(err, context.DeadlineExceeded) || !errors.Is(err, cause) {
t.Fatalf("lost error cause: %v", err)
}
}