Beispiel #1
0
func fightN(f1, f2 Factory, n int) []MatchResult {
	aiA := &aiAdapter{factory: f1, games: make(map[string]gameState)}
	aiB := &aiAdapter{factory: f2, games: make(map[string]gameState)}

	a1, a2 := net.Pipe()
	b1, b2 := net.Pipe()

	ca1, ca2 := rpc.StreamTransport(a1), rpc.StreamTransport(a2)
	cb1, cb2 := rpc.StreamTransport(b1), rpc.StreamTransport(b2)

	// Server-side
	srvA := botapi.Ai_ServerToClient(aiA)
	srvB := botapi.Ai_ServerToClient(aiB)
	serverConnA := rpc.NewConn(ca1, rpc.MainInterface(srvA.Client))
	serverConnB := rpc.NewConn(cb1, rpc.MainInterface(srvB.Client))
	defer serverConnA.Wait()
	defer serverConnB.Wait()

	// Client-side
	ctx := context.Background()

	clientConnA := rpc.NewConn(ca2)
	clientConnB := rpc.NewConn(cb2)
	defer clientConnA.Close()
	defer clientConnB.Close()

	clientA := localAI{botapi.Ai{Client: clientConnA.Bootstrap(ctx)}}
	clientB := localAI{botapi.Ai{Client: clientConnB.Bootstrap(ctx)}}

	matchRes := make([]MatchResult, n)
	// Run the game
	for i := 0; i < n; i++ {
		b := engine.EmptyBoard(engine.DefaultConfig)
		b.InitBoard(engine.DefaultConfig)

		for !b.IsFinished() {
			turnCtx, _ := context.WithTimeout(ctx, 30*time.Second)
			resA, _ := clientA.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P1Faction)
			resB, _ := clientB.takeTurn(turnCtx, strconv.Itoa(i), b, engine.P2Faction)
			b.Update(resA, resB)
		}
		matchRes[i] = MatchResult{
			P1Score: b.BotCount(1),
			P2Score: b.BotCount(2),
		}
	}
	return matchRes
}
Beispiel #2
0
func TestCancel(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	c := rpc.NewConn(p)
	notify := make(chan struct{})
	hanger := testcapnp.Hanger_ServerToClient(Hanger{notify: notify})
	d := rpc.NewConn(q, rpc.MainInterface(hanger.Client))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.Hanger{Client: c.Bootstrap(ctx)}

	subctx, subcancel := context.WithCancel(ctx)
	promise := client.Hang(subctx, func(r testcapnp.Hanger_hang_Params) error { return nil })
	<-notify
	subcancel()
	_, err := promise.Struct()
	<-notify // test will deadlock if cancel not delivered

	if err != context.Canceled {
		t.Errorf("promise.Get() error: %v; want %v", err, context.Canceled)
	}
}
func TestRelease(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	c := rpc.NewConn(p)
	hf := new(HandleFactory)
	d := rpc.NewConn(q, rpc.MainInterface(testcapnp.HandleFactory_ServerToClient(hf).Client))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.HandleFactory{Client: c.Bootstrap(ctx)}
	r, err := client.NewHandle(ctx, nil).Struct()
	if err != nil {
		t.Fatal("NewHandle:", err)
	}
	handle := r.Handle()
	if n := hf.numHandles(); n != 1 {
		t.Fatalf("numHandles = %d; want 1", n)
	}

	if err := handle.Client.Close(); err != nil {
		t.Error("handle.Client.Close():", err)
	}
	flushConn(ctx, c)

	if n := hf.numHandles(); n != 0 {
		t.Errorf("numHandles = %d; want 0", n)
	}
}
Beispiel #4
0
func TestIssue3(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	log := testLogger{t}
	c := rpc.NewConn(p, rpc.ConnLog(log))
	echoSrv := testcapnp.Echoer_ServerToClient(new(SideEffectEchoer))
	d := rpc.NewConn(q, rpc.MainInterface(echoSrv.Client), rpc.ConnLog(log))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.Echoer{Client: c.Bootstrap(ctx)}
	localCap := testcapnp.CallOrder_ServerToClient(new(CallOrder))
	echo := client.Echo(ctx, func(p testcapnp.Echoer_echo_Params) error {
		return p.SetCap(localCap)
	})

	// This should not deadlock.
	_, err := echo.Struct()
	if err != nil {
		t.Error("Echo error:", err)
	}
}
func TestPromisedCapability(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	c := rpc.NewConn(p)
	delay := make(chan struct{})
	echoSrv := testcapnp.Echoer_ServerToClient(&DelayEchoer{delay: delay})
	d := rpc.NewConn(q, rpc.MainInterface(echoSrv.Client))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.Echoer{Client: c.Bootstrap(ctx)}

	echo := client.Echo(ctx, func(p testcapnp.Echoer_echo_Params) error {
		return p.SetCap(testcapnp.CallOrder{Client: client.Client})
	})
	pipeline := echo.Cap()
	call0 := callseq(ctx, pipeline.Client, 0)
	call1 := callseq(ctx, pipeline.Client, 1)
	close(delay)

	check := func(promise testcapnp.CallOrder_getCallSequence_Results_Promise, n uint32) {
		r, err := promise.Struct()
		if err != nil {
			t.Errorf("call%d error: %v", n, err)
		}
		if r.N() != n {
			t.Errorf("call%d = %d; want %d", n, r.N(), n)
		}
	}
	check(call0, 0)
	check(call1, 1)
}
Beispiel #6
0
func TestMainInterface(t *testing.T) {
	main := mockClient()
	conn, p := newTestConn(t, rpc.MainInterface(main))
	defer conn.Close()
	defer p.Close()

	bootstrapRoundtrip(t, p)
}
Beispiel #7
0
func server(c net.Conn) error {
	// Create a new locally implemented HashFactory.
	main := hashes.HashFactory_ServerToClient(hashFactory{})
	// Listen for calls, using the HashFactory as the bootstrap interface.
	conn := rpc.NewConn(rpc.StreamTransport(c), rpc.MainInterface(main.Client))
	// Wait for connection to abort.
	err := conn.Wait()
	return err
}
func TestEmbargo(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	log := testLogger{t}
	c := rpc.NewConn(p, rpc.ConnLog(log))
	echoSrv := testcapnp.Echoer_ServerToClient(new(Echoer))
	d := rpc.NewConn(q, rpc.MainInterface(echoSrv.Client), rpc.ConnLog(log))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.Echoer{Client: c.Bootstrap(ctx)}
	localCap := testcapnp.CallOrder_ServerToClient(new(CallOrder))

	earlyCall := callseq(ctx, client.Client, 0)
	echo := client.Echo(ctx, func(p testcapnp.Echoer_echo_Params) error {
		return p.SetCap(localCap)
	})
	pipeline := echo.Cap()
	call0 := callseq(ctx, pipeline.Client, 0)
	call1 := callseq(ctx, pipeline.Client, 1)
	_, err := earlyCall.Struct()
	if err != nil {
		t.Errorf("earlyCall error: %v", err)
	}
	call2 := callseq(ctx, pipeline.Client, 2)
	_, err = echo.Struct()
	if err != nil {
		t.Errorf("echo.Get() error: %v", err)
	}
	call3 := callseq(ctx, pipeline.Client, 3)
	call4 := callseq(ctx, pipeline.Client, 4)
	call5 := callseq(ctx, pipeline.Client, 5)

	check := func(promise testcapnp.CallOrder_getCallSequence_Results_Promise, n uint32) {
		r, err := promise.Struct()
		if err != nil {
			t.Errorf("call%d error: %v", n, err)
		}
		if r.N() != n {
			t.Errorf("call%d = %d; want %d", n, r.N(), n)
		}
	}
	check(call0, 0)
	check(call1, 1)
	check(call2, 2)
	check(call3, 3)
	check(call4, 4)
	check(call5, 5)
}
func Example() {
	// Create an in-memory transport.  In a real application, you would probably
	// use a net.TCPConn (for RPC) or an os.Pipe (for IPC).
	p1, p2 := net.Pipe()
	t1, t2 := rpc.StreamTransport(p1), rpc.StreamTransport(p2)

	// Server-side
	srv := testcapnp.Adder_ServerToClient(AdderServer{})
	serverConn := rpc.NewConn(t1, rpc.MainInterface(srv.Client))
	defer serverConn.Wait()

	// Client-side
	ctx := context.Background()
	clientConn := rpc.NewConn(t2)
	defer clientConn.Close()
	adderClient := testcapnp.Adder{Client: clientConn.Bootstrap(ctx)}
	// Every client call returns a promise.  You can make multiple calls
	// concurrently.
	call1 := adderClient.Add(ctx, func(p testcapnp.Adder_add_Params) error {
		p.SetA(5)
		p.SetB(2)
		return nil
	})
	call2 := adderClient.Add(ctx, func(p testcapnp.Adder_add_Params) error {
		p.SetA(10)
		p.SetB(20)
		return nil
	})
	// Calling Struct() on a promise waits until it returns.
	result1, err := call1.Struct()
	if err != nil {
		fmt.Println("Add #1 failed:", err)
		return
	}
	result2, err := call2.Struct()
	if err != nil {
		fmt.Println("Add #2 failed:", err)
		return
	}

	fmt.Println("Results:", result1.Result(), result2.Result())
	// Output:
	// Results: 7 30
}
Beispiel #10
0
func TestReleaseAlias(t *testing.T) {
	ctx, cancel := context.WithCancel(context.Background())
	defer cancel()
	p, q := pipetransport.New()
	if *logMessages {
		p = logtransport.New(nil, p)
	}
	c := rpc.NewConn(p)
	hf := singletonHandleFactory()
	d := rpc.NewConn(q, rpc.MainInterface(testcapnp.HandleFactory_ServerToClient(hf).Client))
	defer d.Wait()
	defer c.Close()
	client := testcapnp.HandleFactory{Client: c.Bootstrap(ctx)}
	r1, err := client.NewHandle(ctx, func(r testcapnp.HandleFactory_newHandle_Params) error { return nil }).Struct()
	if err != nil {
		t.Fatal("NewHandle #1:", err)
	}
	handle1 := r1.Handle()
	r2, err := client.NewHandle(ctx, func(r testcapnp.HandleFactory_newHandle_Params) error { return nil }).Struct()
	if err != nil {
		t.Fatal("NewHandle #2:", err)
	}
	handle2 := r2.Handle()
	if n := hf.numHandles(); n != 1 {
		t.Fatalf("after creation, numHandles = %d; want 1", n)
	}

	if err := handle1.Client.Close(); err != nil {
		t.Error("handle1.Client.Close():", err)
	}
	flushConn(ctx, c)
	if n := hf.numHandles(); n != 1 {
		t.Errorf("after handle1.Client.Close(), numHandles = %d; want 1", n)
	}
	if err := handle2.Client.Close(); err != nil {
		t.Error("handle2.Client.Close():", err)
	}
	flushConn(ctx, c)
	if n := hf.numHandles(); n != 0 {
		t.Errorf("after handle1.Close() and handle2.Close(), numHandles = %d; want 0", n)
	}
}
Beispiel #11
0
// handleConn runs in its own goroutine, started by listen.
func (e *aiEndpoint) handleConn(c net.Conn) {
	aic := &aiConnector{e: e}
	rc := rpc.NewConn(rpc.StreamTransport(c), rpc.MainInterface(botapi.AiConnector_ServerToClient(aic).Client))
	rc.Wait()
	aic.drop()
}
Beispiel #12
0
func TestReceiveCallOnExport(t *testing.T) {
	const questionID = 999
	called := false
	main := stubClient(func(ctx context.Context, params capnp.Struct) (capnp.Struct, error) {
		msg, s, err := capnp.NewMessage(capnp.SingleSegment(nil))
		if err != nil {
			return capnp.Struct{}, err
		}
		result, err := capnp.NewStruct(s, capnp.ObjectSize{})
		if err != nil {
			return capnp.Struct{}, err
		}
		called = true
		if err := msg.SetRoot(result); err != nil {
			return capnp.Struct{}, err
		}
		return result, nil
	})
	conn, p := newTestConn(t, rpc.MainInterface(main))
	defer conn.Close()
	defer p.Close()
	importID := sendBootstrapAndFinish(t, p)

	err := sendMessage(context.TODO(), p, func(msg rpccapnp.Message) error {
		call, err := msg.NewCall()
		if err != nil {
			return err
		}
		call.SetQuestionId(questionID)
		call.SetInterfaceId(interfaceID)
		call.SetMethodId(methodID)
		target, err := call.NewTarget()
		if err != nil {
			return err
		}
		target.SetImportedCap(importID)
		call.SetTarget(target)
		payload, err := call.NewParams()
		if err != nil {
			return err
		}
		content, err := capnp.NewStruct(msg.Segment(), capnp.ObjectSize{})
		if err != nil {
			return err
		}
		payload.SetContent(content)
		return nil
	})
	if err != nil {
		t.Fatal("Call message failed:", err)
	}
	retmsg, err := p.RecvMessage(context.TODO())
	if err != nil {
		t.Fatal("Read Call return failed:", err)
	}

	if !called {
		t.Error("interface not called")
	}
	if retmsg.Which() != rpccapnp.Message_Which_return {
		t.Fatalf("Return message is %v; want %v", retmsg.Which(), rpccapnp.Message_Which_return)
	}
	ret, err := retmsg.Return()
	if err != nil {
		t.Fatal("return error:", err)
	}
	if id := ret.AnswerId(); id != questionID {
		t.Errorf("Return.answerId = %d; want %d", id, questionID)
	}
	if ret.Which() == rpccapnp.Return_Which_results {
		// TODO(light)
	} else if ret.Which() == rpccapnp.Return_Which_exception {
		exc, _ := ret.Exception()
		reason, _ := exc.Reason()
		t.Error("Return.exception:", reason)
	} else {
		t.Errorf("Return.Which() = %v; want %v", ret.Which(), rpccapnp.Return_Which_results)
	}
}