1 package main
2
3 import (
4 "context"
5 "fmt"
6 apb "golang.conradwood.net/apis/auth"
7 "golang.conradwood.net/apis/common"
8 ge "golang.conradwood.net/apis/getestservice"
9 "golang.conradwood.net/go-easyops/auth"
10 "golang.conradwood.net/go-easyops/authremote"
11 "golang.conradwood.net/go-easyops/cmdline"
12 gcm "golang.conradwood.net/go-easyops/common"
13 pctx "golang.conradwood.net/go-easyops/ctx"
14
15 "flag"
16 "golang.conradwood.net/go-easyops/server"
17 "golang.conradwood.net/go-easyops/utils"
18 "google.golang.org/grpc"
19 "io"
20 "os"
21 "sync"
22 "time"
23 )
24
25 var (
26 run_sleep_tests = flag.Bool("run_sleep_tests", true, "extra tests to test if timeouts and cancels propagate accurately, they take a while...")
27 runlock sync.Mutex
28 didrun = false
29 )
30
31 func start_server() {
32 sd := server.NewServerDef()
33 sd.SetPort(3005)
34 sd.SetOnStartupCallback(run_tests)
35 sd.SetRegister(server.Register(
36 func(g *grpc.Server) error {
37 ge.RegisterCtxTestServer(g, &geServer{})
38 return nil
39 },
40 ))
41 err := server.ServerStartup(sd)
42 utils.Bail("Unable to start server", err)
43 }
44
45 type geServer struct{}
46
47 func (g *geServer) Sleep(ctx context.Context, req *ge.SleepRequest) (*common.Void, error) {
48 t := time.Duration(req.Seconds) * time.Second
49 fmt.Printf("Sleeping for %0.2f seconds\n", t.Seconds())
50 time.Sleep(t)
51 if ctx.Err() != nil {
52 return nil, ctx.Err()
53 }
54 return &common.Void{}, nil
55 }
56
57 func (g *geServer) TestFork(ctx context.Context, req *ge.RequiredContext) (*common.Void, error) {
58 err := AssertRequiredContext(ctx, req)
59 if err != nil {
60 return nil, err
61 }
62
63 nctx, err := auth.ForkContext(ctx)
64 if err != nil {
65 return nil, err
66 }
67 err = AssertEqualContexts(ctx, nctx)
68 if err != nil {
69 return nil, err
70 }
71
72 return &common.Void{}, nil
73 }
74 func (g *geServer) TestUnary(ctx context.Context, req *ge.RequiredContext) (*common.Void, error) {
75 err := AssertRequiredContext(ctx, req)
76 if err != nil {
77 return nil, err
78 }
79 return &common.Void{}, nil
80
81 }
82 func (g *geServer) TestStream(req *ge.RequiredContext, srv ge.CtxTest_TestStreamServer) error {
83 ctx := srv.Context()
84 err := AssertRequiredContext(ctx, req)
85 if err != nil {
86 return err
87 }
88
89 _, err = g.TestDeSer(ctx, req)
90 return err
91 }
92 func (g *geServer) TestDeSer(ctx context.Context, req *ge.RequiredContext) (*ge.SerialisedContext, error) {
93 err := AssertRequiredContext(ctx, req)
94 if err != nil {
95 return nil, err
96 }
97 fmt.Printf("TestDeSer: required (and received) context calling service: %s\n", auth.UserIDString(auth.GetService(ctx)))
98 m := map[string]string{"foo": "bar"}
99 ictx := authremote.DerivedContextWithRouting(ctx, m, true)
100 err = AssertRequiredContext(ictx, req)
101 if err != nil {
102 return nil, fmt.Errorf("broken derived context (%s)", err)
103 }
104
105 err = AssertEqualContexts(ctx, ictx)
106 if err != nil {
107 return nil, err
108 }
109
110
111 b, err := auth.SerialiseContext(ctx)
112 if err != nil {
113 return nil, err
114 }
115
116 s, err := auth.SerialiseContextToString(ctx)
117 if err != nil {
118 return nil, err
119 }
120
121 ictx, err = auth.RecreateContextWithTimeout(time.Duration(10)*time.Second, b)
122 if err != nil {
123 return nil, err
124 }
125 err = AssertRequiredContext(ictx, req)
126 if err != nil {
127 return nil, err
128 }
129
130 err = AssertEqualContexts(ctx, ictx)
131 if err != nil {
132 return nil, err
133 }
134
135 sctx, err := auth.RecreateContextWithTimeout(time.Duration(10)*time.Second, []byte(s))
136 if err != nil {
137 return nil, err
138 }
139 err = AssertRequiredContext(sctx, req)
140 if err != nil {
141 return nil, err
142 }
143
144 err = AssertEqualContexts(ctx, sctx)
145 if err != nil {
146 return nil, err
147 }
148
149 if cmdline.ContextWithBuilder() {
150 ictx, err = pctx.DeserialiseContextFromString(s)
151 if err != nil {
152 return nil, err
153 }
154
155 err = AssertEqualContexts(ctx, ictx)
156 if err != nil {
157 return nil, err
158 }
159
160 if !pctx.IsSerialisedByBuilder(b) {
161 return nil, fmt.Errorf("ctx does not recognise its own (byte) serialised context")
162 }
163 if !pctx.IsSerialisedByBuilder([]byte(s)) {
164 return nil, fmt.Errorf("ctx does not recognise its own (byte) serialised context")
165 }
166 _, err = pctx.DeserialiseContext(b)
167 if err != nil {
168 return nil, err
169 }
170 }
171
172 res := &ge.SerialisedContext{
173 Data: b,
174 SData: s,
175 User: auth.GetSignedUser(ctx),
176 Service: auth.GetSignedService(ctx),
177 }
178 return res, nil
179 }
180 func run_tests() {
181 runlock.Lock()
182 if didrun == true {
183 runlock.Unlock()
184 return
185 }
186 didrun = true
187 runlock.Unlock()
188
189 svc := authremote.GetLocalServiceAccount()
190 ctx := authremote.Context()
191 if ctx == nil {
192 panic("no context")
193 }
194 if svc != nil && auth.GetSignedService(ctx) == nil {
195 panic("missing service")
196 }
197 ctx = authremote.DerivedContextWithRouting(ctx, make(map[string]string), true)
198 if ctx == nil {
199 panic("no context")
200 }
201 if svc != nil && auth.GetSignedService(ctx) == nil {
202 panic("missing service")
203 }
204
205 cmdline.SetDatacenter(false)
206 run_all_tests()
207 cmdline.SetDatacenter(true)
208 run_all_tests()
209 if *run_sleep_tests {
210 sleepTests()
211 }
212 fmt.Printf("Done\n")
213 PrintResult()
214 os.Exit(0)
215
216 }
217 func run_all_tests() {
218 fmt.Printf("Running tests...\n")
219
220 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
221 t := NewTest("simple unary test")
222 ctx := authremote.Context()
223 _, err := ge.GetCtxTestClient().TestUnary(ctx, CreateContextObject(ctx))
224 t.Error(err)
225 t.Done()
226
227 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
228 t = NewTest("simple unary test")
229 ctx = authremote.Context()
230 _, err = ge.GetCtxTestClient().TestUnary(ctx, CreateContextObject(ctx))
231 t.Error(err)
232 t.Done()
233
234 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
235 t = NewTest("stream test")
236 ctx = authremote.Context()
237 srv, err := ge.GetCtxTestClient().TestStream(ctx, CreateContextObject(ctx))
238 t.Error(err)
239 t.Error(checkSrv(srv))
240 t.Done()
241
242 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
243 t = NewTest("stream test")
244 ctx = authremote.Context()
245 srv, err = ge.GetCtxTestClient().TestStream(ctx, CreateContextObject(ctx))
246 t.Error(err)
247 t.Error(checkSrv(srv))
248 t.Done()
249
250 checkStream("CallUnaryFromStream", func(ctx context.Context) (recv, error) {
251 return ge.GetCtxTestClient().CallUnaryFromStream(ctx, CreateContextObject(ctx))
252 })
253
254 checkStream("CallStreamFromStream", func(ctx context.Context) (recv, error) {
255 return ge.GetCtxTestClient().CallStreamFromStream(ctx, CreateContextObject(ctx))
256 })
257 checkUnary("CallStreamFromUnary", func(ctx context.Context) error {
258 _, err := ge.GetCtxTestClient().CallStreamFromUnary(ctx, CreateContextObject(ctx))
259 return err
260 })
261 checkUnary("CallUnaryFromUnary", func(ctx context.Context) error {
262 _, err := ge.GetCtxTestClient().CallUnaryFromUnary(ctx, CreateContextObject(ctx))
263 return err
264 })
265
266 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
267 t = NewTest("fork test")
268 ctx = authremote.Context()
269 _, err = ge.GetCtxTestClient().TestFork(ctx, CreateContextObject(ctx))
270 t.Error(err)
271 t.Done()
272
273 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
274 t = NewTest("fork test")
275 ctx = authremote.Context()
276 _, err = ge.GetCtxTestClient().TestFork(ctx, CreateContextObject(ctx))
277 t.Error(err)
278 t.Done()
279
280 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
281 t = NewTest("(de)serialise")
282 ctx = authremote.Context()
283 _, err = ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
284 t.Error(err)
285 t.Done()
286
287 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
288 t = NewTest("(de)serialise")
289 ctx = authremote.Context()
290 dctx, err := ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
291 t.Error(err)
292 t.Done()
293
294 if dctx != nil {
295 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
296 t = NewTest("use serialised context to access service")
297 if !pctx.IsSerialisedByBuilder(dctx.Data) {
298 t.Error(fmt.Errorf("ctx failed to recognise it as a context"))
299 }
300 ctx, err = pctx.DeserialiseContext(dctx.Data)
301 t.Error(err)
302 }
303 dctx, err = ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
304 t.Error(err)
305 if dctx == nil || (!CompareUsers(dctx.User, auth.GetSignedUser(ctx))) {
306 t.Error(fmt.Errorf("No user in service with serialised context"))
307 }
308 t.Done()
309
310 if dctx != nil {
311 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
312 t = NewTest("use serialised context to access service")
313 if !pctx.IsSerialisedByBuilder(dctx.Data) {
314 t.Error(fmt.Errorf("ctx failed to recognise it as a context"))
315 }
316 ctx, err = pctx.DeserialiseContext(dctx.Data)
317 t.Error(err)
318 }
319 dctx, err = ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
320 t.Error(err)
321 if dctx == nil || (!CompareUsers(dctx.User, auth.GetSignedUser(ctx))) {
322 t.Error(fmt.Errorf("No user in service with serialised context"))
323 }
324 t.Done()
325
326 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
327 t = NewTest("serialise old, deserialise new")
328 ctx = authremote.Context()
329 r, err := ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
330 t.Error(err)
331 if err == nil {
332 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
333 nctx, err := auth.RecreateContextWithTimeout(time.Duration(10)*time.Second, r.Data)
334 t.Error(err)
335 if err != nil {
336 err = AssertEqualContexts(ctx, nctx)
337 t.Error(err)
338 }
339 }
340 t.Done()
341
342
343 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
344 t = NewTest("old context, call new service")
345 ctx = authremote.Context()
346 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
347
348 _, err = ge.GetCtxTestClient().TestDeSer(ctx, CreateContextObject(ctx))
349 t.Error(err)
350 t.Done()
351
352 }
353
354 func AssertEqualContexts(ctx1, ctx2 context.Context) error {
355 su1 := auth.GetSignedUser(ctx1)
356 su2 := auth.GetSignedUser(ctx2)
357 if !CompareUsers(su1, su2) {
358 u1 := gcm.VerifySignedUser(su1)
359 u2 := gcm.VerifySignedUser(su2)
360 return fmt.Errorf("u1 (%s) != u2 (%s)", auth.UserIDString(u1), auth.UserIDString(u2))
361 }
362
363 return nil
364 }
365
366 func CompareUsers(su1, su2 *apb.SignedUser) bool {
367 u1 := gcm.VerifySignedUser(su1)
368 u2 := gcm.VerifySignedUser(su2)
369 if u1 == nil && u2 == nil {
370 return true
371 }
372 if u1 == nil && u2 != nil {
373 return false
374 }
375 if u1 != nil && u2 == nil {
376 return false
377 }
378
379 if u1.ID != u2.ID {
380 return false
381 }
382 return true
383 }
384
385 type recv interface {
386 Recv() (*common.Void, error)
387 }
388
389 func checkSrv(r recv) error {
390 for {
391 _, err := r.Recv()
392 if err == io.EOF {
393 return nil
394 }
395 if err != nil {
396 return err
397 }
398 }
399 }
400
401 func checkStream(name string, f func(ctx context.Context) (recv, error)) {
402 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
403 t := NewTest("stream-bouncer %s (new ctx)", name)
404 ctx := authremote.Context()
405 srv, err := f(ctx)
406 t.Error(err)
407 t.Error(checkSrv(srv))
408 t.Done()
409
410 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
411 t = NewTest("stream-bouncer %s (old ctx)", name)
412 ctx = authremote.Context()
413 srv, err = f(ctx)
414 t.Error(err)
415 t.Error(checkSrv(srv))
416 t.Done()
417
418 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
419 ctx = authremote.Context()
420 t = NewTest("stream-bouncer %s (new/old ctx)", name)
421 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
422 srv, err = f(ctx)
423 t.Error(err)
424 t.Error(checkSrv(srv))
425 t.Done()
426
427 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
428 ctx = authremote.Context()
429 t = NewTest("stream-bouncer %s (old/new ctx)", name)
430 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
431 srv, err = f(ctx)
432 t.Error(err)
433 t.Error(checkSrv(srv))
434 t.Done()
435
436 }
437 func checkUnary(name string, f func(ctx context.Context) error) {
438 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
439 t := NewTest("unary-bouncer with_cb %s (new ctx)", name)
440 ctx := authremote.Context()
441 err := f(ctx)
442 t.Error(err)
443 t.Done()
444
445 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
446 t = NewTest("unary-bouncer wo_cb %s (old ctx)", name)
447 ctx = authremote.Context()
448 err = f(ctx)
449 t.Error(err)
450 t.Done()
451
452 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
453 t = NewTest("unary-bouncer %s cb_tf (new/old ctx)", name)
454 ctx = authremote.Context()
455 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
456 err = f(ctx)
457 t.Error(err)
458 t.Done()
459
460 cmdline.SetContextBuilderVersion(OLD_CONTEXT_VERSION)
461 t = NewTest("unary-bouncer %s cb_ft test (old/new ctx)", name)
462 ctx = authremote.Context()
463 cmdline.SetContextBuilderVersion(NEW_CONTEXT_VERSION)
464 err = f(ctx)
465 t.Error(err)
466 t.Done()
467
468 }
469
470 func CreateContextObject(ctx context.Context) *ge.RequiredContext {
471 res := &ge.RequiredContext{
472 User: auth.GetSignedUser(ctx),
473 Service: auth.GetSignedService(ctx),
474 }
475 return res
476 }
477 func AssertRequiredContext(ctx context.Context, rc *ge.RequiredContext) error {
478 if ctx == nil {
479 return fmt.Errorf("no context to assert")
480 }
481 u := auth.GetSignedUser(ctx)
482 s := auth.GetSignedService(ctx)
483 err := AssertSameUser("user", rc.User, u)
484 if err != nil {
485 fmt.Println("Mismatched context:" + pctx.Context2String(ctx))
486 return err
487 }
488 if rc.Service != nil {
489 err = AssertSameUser("service", rc.Service, s)
490 if err != nil {
491 fmt.Println("Mismatched context:" + pctx.Context2String(ctx))
492 return err
493 }
494 }
495 return nil
496 }
497 func AssertSameUser(s string, u1, u2 *apb.SignedUser) error {
498 if !CompareUsers(u1, u2) {
499 uu1 := gcm.VerifySignedUser(u1)
500 uu2 := gcm.VerifySignedUser(u2)
501 utils.PrintStack("%s Mismatch: expected=%s, actual=%s", s, auth.UserIDString(uu1), auth.UserIDString(uu2))
502 return fmt.Errorf("%s Mismatch: expected=%s, actual=%s", s, auth.UserIDString(uu1), auth.UserIDString(uu2))
503 }
504 return nil
505 }
506
View as plain text