func (ts *TestSystem) runtest(timeoutms int) {
	lspnet.SetWriteDropPercent(ts.DropPercent)
	if ts.Description != "" {
		fmt.Printf("Testing: %s\n", ts.Description)
	}
	go ts.runserver()
	for i := 0; i < ts.NClients; i++ {
		go ts.runclient(i)
	}
	go ts.runtimeout(timeoutms)
	for i := 0; i < ts.NClients; i++ {
		v := <-ts.CChan
		if v < 0 {
			ts.RunFlag = false
			ts.Tester.Logf("Test timed out after %f secs\n",
				float64(timeoutms)/1000.0)
			ts.Tester.FailNow()
		}
	}
	ts.RunFlag = false
	lsplog.Vlogf(0, "Passed: %d clients, %d messages/client, %.2f maxsleep, %.2f drop rate\n",
		ts.NClients, ts.NMessages,
		float64(ts.MaxSleepMilliseconds)/1000.0,
		float64(ts.DropPercent)/100.0)
	lsplog.SetVerbose(DefaultVerbosity)
	lspnet.SetWriteDropPercent(0)
}
func main() {
	var ihelp *bool = flag.Bool("h", false, "Print help information")
	var iport *int = flag.Int("p", 6666, "Port number")
	var iverb *int = flag.Int("v", 4, "Verbosity (0-6)")
	var idrop *int = flag.Int("r", 0, "Network packet drop percentage")
	var elim *int = flag.Int("k", 5, "Epoch limit")
	var ems *int = flag.Int("d", 2000, "Epoch duration (millisecconds)")
	flag.Parse()
	if *ihelp {
		flag.Usage()
		os.Exit(0)
	}
	var port int = *iport
	if flag.NArg() > 0 {
		nread, _ := fmt.Sscanf(flag.Arg(0), "%d", &port)
		if nread != 1 {
			flag.Usage()
			os.Exit(0)
		}
	}
	params := &lsp.LspParams{*elim, *ems}

	lsplog.SetVerbose(*iverb)
	lspnet.SetWriteDropPercent(*idrop)
	fmt.Printf("Establishing server on port %d\n", port)
	srv, err := lsp.NewLspServer(port, params)
	if err != nil {
		fmt.Printf("... failed.  Error message %s\n", err.Error())
	} else {
		runserver(srv)
	}
}
func TestBasic2(t *testing.T) {
	lsplog.SetVerbose(2)
	ts := NewTestSystem(t, 1, params(5, 2000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("Long client/server interaction")
	ts.SetNMessages(50)
	ts.runtest(1000)
}
func TestBasic3(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 2, params(5, 2000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("Two client/one server interaction")
	ts.SetNMessages(50)
	ts.runtest(1000)
}
func TestBasic4(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 10, params(5, 2000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("10 clients, long interaction")
	ts.SetNMessages(50)
	ts.runtest(2000)
}
func TestBasic6(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 2, params(5, 2000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("2 clients, test wraparound of sequence numnbers")
	ts.SetNMessages(550)
	ts.runtest(2000)
}
func TestSendReceive2(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 4, params(5, 5000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("No epochs.  Multiple clients")
	ts.SetNMessages(6)
	ts.runtest(5000)
}
func TestRobust3(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 4, params(20, 50))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("Four clients.  Some packet dropping")
	ts.SetDropPercent(20)
	ts.SetNMessages(8)
	ts.runtest(15000)
}
func TestSendReceive3(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 4, params(5, 10000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("No epochs.  Random delays inserted")
	ts.SetNMessages(6)
	ts.SetMaxSleepMilliseconds(100)
	ts.runtest(10000)
}
func TestBasic5(t *testing.T) {
	lsplog.SetVerbose(DefaultVerbosity)
	ts := NewTestSystem(t, 4, params(5, 2000))
	if ts == nil {
		t.FailNow()
	}
	ts.SetDescription("Random delays by clients & server")
	ts.SetNMessages(10)
	ts.SetMaxSleepMilliseconds(100)
	ts.runtest(15000)
}
func main() {
	var ihelp *bool = flag.Bool("h", false, "Show help information")
	var iport *int = flag.Int("p", 6666, "Port number")
	var ihost *string = flag.String("H", "localhost", "Host address")
	var iverb *int = flag.Int("v", 4, "Verbosity (0-6)")
	var irdrop *int = flag.Int("r", 0, "Network read packet drop percentage")
	var iwdrop *int = flag.Int("w", 0, "Network write packet drop percentage")
	var elim *int = flag.Int("k", 5, "Epoch limit")
	var ems *int = flag.Int("d", 2000, "Epoch duration (millisecconds)")
	flag.Parse()
	if *ihelp {
		flag.Usage()
		os.Exit(0)
	}
	if flag.NArg() > 0 {
		// Look for host:port on command line
		ok := true
		fields := strings.Split(flag.Arg(0), ":")
		ok = ok && len(fields) == 2
		if ok {
			*ihost = fields[0]
			n, err := fmt.Sscanf(fields[1], "%d", iport)
			ok = ok && n == 1 && err == nil
		}
		if !ok {
			flag.Usage()
			os.Exit(0)
		}
	}
	params := &lsp.LspParams{*elim, *ems}

	lsplog.SetVerbose(*iverb)
	lspnet.SetReadDropPercent(*irdrop)
	lspnet.SetWriteDropPercent(*iwdrop)
	hostport := fmt.Sprintf("%s:%v", *ihost, *iport)
	fmt.Printf("Connecting to server at %s\n", hostport)
	cli, err := lsp.NewLspClient(hostport, params)
	if err != nil {
		fmt.Printf("... failed.  Error message %s\n", err.Error())
	}
	if lsplog.CheckReport(1, err) {
		return
	}
	runclient(cli)
}
// Test components
func NewSynchTestSystem(t *testing.T, nclients int, nmessages int, mode int, maxepochs int, params *LspParams) {
	fmt.Printf("Testing: Mode %s, %d clients\n", SynchModeName[mode], nclients)
	ts := new(SynchTestSystem)
	ts.Mode = mode
	ts.Params = params
	ts.C2MChan = make(chan bool)
	ts.S2MChan = make(chan bool)
	ts.N2MChan = make(chan bool)
	ts.TChan = make(chan int)
	ts.M2CChan = make(chan bool)
	ts.M2SChan = make(chan bool)
	ts.M2NChan = make(chan bool)
	ts.Nclients = nclients
	ts.Nmessages = nmessages
	ts.Clients = make([]*LspClient, nclients)
	ts.ClientMap = make(map[uint16]int, nclients)
	ts.Data = make([][]int, nclients)
	ts.Rgen = *rand.New(rand.NewSource(time.Now().Unix()))
	for i := 0; i < nclients; i++ {
		ts.Data[i] = genData(nmessages, ts.Rgen)
	}
	ts.Nclients = nclients
	ts.Port = synchrandport(ts.Rgen)
	ts.RunFlag = true
	ts.Tester = t
	go ts.RunNetwork()
	go ts.RunServer()
	// Set up clients
	for i := 0; i < nclients; i++ {
		go ts.RunClient(i)
	}
	go ts.RunTimeout(float64(maxepochs))
	ts.Master()
	ts.RunFlag = false
	lsplog.SetVerbose(SynchDefaultVerbosity)
	lspnet.SetWriteDropPercent(0)
}
func TestServerToClient2(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 3, 10, doservertoclient, 12, synchparams(5, 500))
}
func TestStopServerConns2(t *testing.T) {
	lsplog.SetVerbose(1)
	NewAuxTestSystem(t, 3, doserverstopconns, 5, auxparams(2, 500))
}
func TestStopClient2(t *testing.T) {
	lsplog.SetVerbose(1)
	NewAuxTestSystem(t, 3, doclientstop, 15, auxparams(5, 500))
}
func NewAuxTestSystem(t *testing.T, nclients int, mode int, maxepochs int,
	params *LspParams) {
	fmt.Printf("Testing: Mode %s, %d clients\n", ModeName[mode], nclients)
	ts := new(AuxTestSystem)
	ts.Mode = mode
	ts.Params = params
	ts.ClientChan = make(chan bool)
	ts.ServerChan = make(chan bool)
	ts.TimeChan = make(chan bool)
	ts.Clients = make([]*LspClient, nclients)
	ts.Nclients = nclients
	ts.Nmessages = 10
	ts.Rgen = *rand.New(rand.NewSource(time.Now().Unix()))
	ts.Port = randport(ts.Rgen)
	ts.RunFlag = true
	ts.Tester = t
	go ts.BuildServer()
	for i := 0; i < nclients; i++ {
		go ts.BuildClient(i)
	}
	go ts.runtimeout(float64(maxepochs))

	switch ts.Mode {
	case doclientstop:
		// Wait for server or timer to complete
		select {
		case sok := <-ts.ServerChan:
			if !sok {
				ts.Tester.Logf("Server error\n")
				ts.Tester.FailNow()
			}
		case <-ts.TimeChan:
			ts.Tester.Logf("Test timed out waiting for server\n")
			ts.Tester.FailNow()
		}
		lsplog.Vlogf(0, "Server completed\n")
		// Wait for the clients
		for i := 0; i < nclients; i++ {
			select {
			case c*k := <-ts.ClientChan:
				if !c*k {
					ts.Tester.Logf("Client error\n")
					ts.Tester.FailNow()
				}
			case <-ts.TimeChan:
				ts.Tester.Logf("Test timed out waiting for client\n")
				ts.Tester.FailNow()
			}
		}
		lsplog.Vlogf(0, "Clients completed\n")
	default: // Includes stopserver
		// Wait for the clients
		for i := 0; i < nclients; i++ {
			select {
			case c*k := <-ts.ClientChan:
				if !c*k {
					ts.Tester.Logf("Client error\n")
					ts.Tester.FailNow()
				}
			case <-ts.TimeChan:
				ts.Tester.Logf("Test timed out waiting for client\n")
				ts.Tester.FailNow()
			}
		}
		// Wait for server or timer to complete
		select {
		case sok := <-ts.ServerChan:
			if !sok {
				ts.Tester.Logf("Server error\n")
				ts.Tester.FailNow()
			}
		case <-ts.TimeChan:
			ts.Tester.Logf("Test timed out waiting for server\n")
			ts.Tester.FailNow()
		}
	}
	lsplog.SetVerbose(AuxDefaultVerbosity)
}
func TestRoundTrip2(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 3, 10, doroundtrip, 12, synchparams(5, 500))
}
func TestClientToServer3(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 5, 500, doclienttoserver, 20, synchparams(5, 2000))
}
func TestClientToServer2(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 3, 10, doclienttoserver, 12, synchparams(5, 500))
}
func TestStopServerConns1(t *testing.T) {
	lsplog.SetVerbose(1)
	NewAuxTestSystem(t, 1, doserverstopconns, 10, auxparams(5, 500))
}
func TestServerFastClose3(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 5, 500, doserverfastclose, 20, synchparams(5, 2000))
}
func TestServerFastClose2(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 3, 10, doserverfastclose, 12, synchparams(5, 500))
}
func TestRoundTrip3(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 5, 500, doroundtrip, 20, synchparams(5, 2000))
}
func TestServerToClient3(t *testing.T) {
	lsplog.SetVerbose(3)
	NewSynchTestSystem(t, 5, 500, doservertoclient, 20, synchparams(5, 2000))
}
func TestSlowStart2(t *testing.T) {
	lsplog.SetVerbose(1)
	NewAuxTestSystem(t, 3, doslowstart, 5, auxparams(5, 500))
}