func TestSupervisedWait(t *testing.T) { serv := &testutil.Server{} dc, err := client.NewDynamic(testutil.DynamicOpts(serv, testutil.NewBuilder(nil))) if err != nil { t.Fatalf("want err = nil; got %v", err) } defer dc.Close() dcf := func() (client.Client, error) { return dc.Client(), nil } // Server is off, so the timeout should be reached. const timeout = 50 * time.Millisecond spv := client.NewSupervised(dcf, timeout) startC, hitC := make(chan struct{}), make(chan time.Time) go func() { <-startC _, err = spv.CurrentUser() hitC <- time.Now() }() now := time.Now() close(startC) select { case called := <-hitC: if tret := called.Sub(now); tret < timeout { t.Fatalf("want return at least after %v; got %v", timeout, tret) } if err != client.ErrDisconnected { t.Fatalf("want err = %v; got %v", client.ErrDisconnected, err) } case <-time.After(time.Second): t.Fatalf("test timed out after 1s") } // Server starts to be responsive while Supervisor waits for it. spv = client.NewSupervised(dcf, 2*time.Second) startC, hitC = make(chan struct{}), make(chan time.Time) go func() { <-startC _, err = spv.CurrentUser() hitC <- time.Now() }() close(startC) serv.TurnOn() select { case <-hitC: if err == client.ErrDisconnected { t.Fatal("want err != client.ErrDisconnected") } case <-time.After(time.Second): t.Fatalf("test timed out after 1s") } }
func TestDynamicClientContext(t *testing.T) { var ( serv = &testutil.Server{} builder = testutil.NewBuilder(nil) ) dc, err := client.NewDynamic(testutil.DynamicOpts(serv, builder)) if err != nil { t.Fatalf("want err = nil; got %v", err) } defer dc.Close() ctx := dc.Client().Context() serv.TurnOn() if err := testutil.WaitForContextClose(ctx, time.Second); err != nil { t.Fatalf("want err = nil; got %v", err) } const ContextWorkers = 10 var g errgroup.Group for i := 0; i < ContextWorkers; i++ { g.Go(func() error { select { case <-dc.Client().Context().Done(): return errors.New("context closed unexpectedly") case <-time.After(50 * time.Millisecond): return nil } }) } // Machine is on so dynamic client should not close its context. if err := g.Wait(); err != nil { t.Fatalf("want err = nil; got %v", err) } ctx = dc.Client().Context() serv.TurnOff() for i := 0; i < ContextWorkers; i++ { g.Go(func() error { select { case <-ctx.Done(): return nil case <-time.After(time.Second): return errors.New("timed out") } }) } // Machine is off so its context channel should be closed by dynamic client. if err := g.Wait(); err != nil { t.Fatalf("want err = nil; got %v", err) } }
func TestDynamicClientOnOff(t *testing.T) { var ( serv = &testutil.Server{} builder = testutil.NewBuilder(nil) ) dc, err := client.NewDynamic(testutil.DynamicOpts(serv, builder)) if err != nil { t.Fatalf("want err = nil; got %v", err) } defer dc.Close() // Server is in unknown state. if status := dc.Status(); status.State != machine.StateUnknown { t.Fatalf("want state = %s; got %s", machine.StateUnknown, status.State) } // Server starts responding. ctx := dc.Client().Context() serv.TurnOn() if err := builder.WaitForBuild(time.Second); err != nil { t.Fatalf("want err = nil; got %v", err) } if n := builder.BuildsCount(); n != 1 { t.Fatalf("want builds count = 1; got %d", n) } if err := testutil.WaitForContextClose(ctx, time.Second); err != nil { t.Fatalf("want err = nil; got %v", err) } if status := dc.Status(); status.State != machine.StateOnline { t.Fatalf("want state = %s; got %s", machine.StateOnline, status.State) } // Stop server. ctx = dc.Client().Context() serv.TurnOff() if err := builder.WaitForBuild(time.Second); err != nil { t.Fatalf("want err = nil; got %v", err) } if n := builder.BuildsCount(); n != 2 { t.Fatalf("want builds count = 2; got %d", n) } if err := testutil.WaitForContextClose(ctx, time.Second); err != nil { t.Fatalf("want err = nil; got %v", err) } if status := dc.Status(); status.State != machine.StateOffline { t.Fatalf("want state = %s; got %s", machine.StateOffline, status.State) } }