-
Notifications
You must be signed in to change notification settings - Fork 4.5k
/
Copy pathconfig_selector_test.go
156 lines (137 loc) · 4.15 KB
/
config_selector_test.go
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
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
/*
*
* Copyright 2020 gRPC authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package resolver
import (
"testing"
"time"
"github.com/google/go-cmp/cmp"
"google.golang.org/grpc/internal/grpctest"
"google.golang.org/grpc/internal/serviceconfig"
)
type s struct {
grpctest.Tester
}
func Test(t *testing.T) {
grpctest.RunSubTests(t, s{})
}
type fakeConfigSelector struct {
selectConfig func(RPCInfo) (*RPCConfig, error)
}
func (f *fakeConfigSelector) SelectConfig(r RPCInfo) (*RPCConfig, error) {
return f.selectConfig(r)
}
func (s) TestSafeConfigSelector(t *testing.T) {
testRPCInfo := RPCInfo{Method: "test method"}
retChan1 := make(chan *RPCConfig)
retChan2 := make(chan *RPCConfig)
defer close(retChan1)
defer close(retChan2)
one := 1
two := 2
resp1 := &RPCConfig{MethodConfig: serviceconfig.MethodConfig{MaxReqSize: &one}}
resp2 := &RPCConfig{MethodConfig: serviceconfig.MethodConfig{MaxReqSize: &two}}
cs1Called := make(chan struct{}, 1)
cs2Called := make(chan struct{}, 1)
cs1 := &fakeConfigSelector{
selectConfig: func(r RPCInfo) (*RPCConfig, error) {
cs1Called <- struct{}{}
if diff := cmp.Diff(r, testRPCInfo); diff != "" {
t.Errorf("SelectConfig(%v) called; want %v\n Diffs:\n%s", r, testRPCInfo, diff)
}
return <-retChan1, nil
},
}
cs2 := &fakeConfigSelector{
selectConfig: func(r RPCInfo) (*RPCConfig, error) {
cs2Called <- struct{}{}
if diff := cmp.Diff(r, testRPCInfo); diff != "" {
t.Errorf("SelectConfig(%v) called; want %v\n Diffs:\n%s", r, testRPCInfo, diff)
}
return <-retChan2, nil
},
}
scs := &SafeConfigSelector{}
scs.UpdateConfigSelector(cs1)
cs1Returned := make(chan struct{})
go func() {
got, err := scs.SelectConfig(testRPCInfo) // blocks until send to retChan1
if err != nil || got != resp1 {
t.Errorf("SelectConfig(%v) = %v, %v; want %v, nil", testRPCInfo, got, err, resp1)
}
close(cs1Returned)
}()
// cs1 is blocked but should be called
select {
case <-time.After(500 * time.Millisecond):
t.Fatalf("timed out waiting for cs1 to be called")
case <-cs1Called:
}
// swap in cs2 now that cs1 is called
csSwapped := make(chan struct{})
go func() {
// wait awhile first to ensure cs1 could be called below.
time.Sleep(50 * time.Millisecond)
scs.UpdateConfigSelector(cs2) // Blocks until cs1 done
close(csSwapped)
}()
// Allow cs1 to return and cs2 to eventually be swapped in.
retChan1 <- resp1
cs1Done := false // set when cs2 is first called
for dl := time.Now().Add(150 * time.Millisecond); !time.Now().After(dl); {
gotConfigChan := make(chan *RPCConfig)
go func() {
cfg, _ := scs.SelectConfig(testRPCInfo)
gotConfigChan <- cfg
}()
select {
case <-time.After(500 * time.Millisecond):
t.Fatalf("timed out waiting for cs1 or cs2 to be called")
case <-cs1Called:
// Initially, before swapping to cs2, cs1 should be called
retChan1 <- resp1
go func() { <-gotConfigChan }()
if cs1Done {
t.Fatalf("cs1 called after cs2")
}
case <-cs2Called:
// Success! the new config selector is being called
if !cs1Done {
select {
case <-csSwapped:
case <-time.After(50 * time.Millisecond):
t.Fatalf("timed out waiting for UpdateConfigSelector to return")
}
select {
case <-cs1Returned:
case <-time.After(50 * time.Millisecond):
t.Fatalf("timed out waiting for cs1 to return")
}
cs1Done = true
}
retChan2 <- resp2
got := <-gotConfigChan
if diff := cmp.Diff(got, resp2); diff != "" {
t.Fatalf("SelectConfig(%v) = %v; want %v\n Diffs:\n%s", testRPCInfo, got, resp2, diff)
}
}
time.Sleep(10 * time.Millisecond)
}
if !cs1Done {
t.Fatalf("timed out waiting for cs2 to be called")
}
}