Beispiel #1
0
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")
	}
}
Beispiel #2
0
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)
	}
}
Beispiel #3
0
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)
	}
}
Beispiel #4
0
// Create generates a new dynamic client for a given machine. If machine client
// already exists, this function is no-op.
func (c *Clients) Create(id machine.ID, dynAddr client.DynamicAddrFunc) error {
	c.mu.Lock()
	defer c.mu.Unlock()

	if _, ok := c.m[id]; ok {
		return nil
	}

	dc, err := client.NewDynamic(client.DynamicOpts{
		AddrFunc:        dynAddr,
		Builder:         c.builder,
		DynAddrInterval: c.dynAddrInterval,
		PingInterval:    c.pingInterval,
		Log:             c.log.New(string(id)),
	})
	if err != nil {
		return err
	}

	c.m[id] = dc

	return nil
}