The Go Programming Language

Source file src/pkg/netchan/netchan_test.go

     1	// Copyright 2010 The Go Authors. All rights reserved.
     2	// Use of this source code is governed by a BSD-style
     3	// license that can be found in the LICENSE file.
     4	
     5	package netchan
     6	
     7	import (
     8		"net"
     9		"strings"
    10		"testing"
    11		"time"
    12	)
    13	
    14	const count = 10     // number of items in most tests
    15	const closeCount = 5 // number of items when sender closes early
    16	
    17	const base = 23
    18	
    19	func exportSend(exp *Exporter, n int, t *testing.T, done chan bool) {
    20		ch := make(chan int)
    21		err := exp.Export("exportedSend", ch, Send)
    22		if err != nil {
    23			t.Fatal("exportSend:", err)
    24		}
    25		go func() {
    26			for i := 0; i < n; i++ {
    27				ch <- base + i
    28			}
    29			close(ch)
    30			if done != nil {
    31				done <- true
    32			}
    33		}()
    34	}
    35	
    36	func exportReceive(exp *Exporter, t *testing.T, expDone chan bool) {
    37		ch := make(chan int)
    38		err := exp.Export("exportedRecv", ch, Recv)
    39		expDone <- true
    40		if err != nil {
    41			t.Fatal("exportReceive:", err)
    42		}
    43		for i := 0; i < count; i++ {
    44			v, ok := <-ch
    45			if !ok {
    46				if i != closeCount {
    47					t.Errorf("exportReceive expected close at %d; got one at %d", closeCount, i)
    48				}
    49				break
    50			}
    51			if v != base+i {
    52				t.Errorf("export Receive: bad value: expected %d+%d=%d; got %d", base, i, base+i, v)
    53			}
    54		}
    55	}
    56	
    57	func importSend(imp *Importer, n int, t *testing.T, done chan bool) {
    58		ch := make(chan int)
    59		err := imp.ImportNValues("exportedRecv", ch, Send, 3, -1)
    60		if err != nil {
    61			t.Fatal("importSend:", err)
    62		}
    63		go func() {
    64			for i := 0; i < n; i++ {
    65				ch <- base + i
    66			}
    67			close(ch)
    68			if done != nil {
    69				done <- true
    70			}
    71		}()
    72	}
    73	
    74	func importReceive(imp *Importer, t *testing.T, done chan bool) {
    75		ch := make(chan int)
    76		err := imp.ImportNValues("exportedSend", ch, Recv, 3, count)
    77		if err != nil {
    78			t.Fatal("importReceive:", err)
    79		}
    80		for i := 0; i < count; i++ {
    81			v, ok := <-ch
    82			if !ok {
    83				if i != closeCount {
    84					t.Errorf("importReceive expected close at %d; got one at %d", closeCount, i)
    85				}
    86				break
    87			}
    88			if v != base+i {
    89				t.Errorf("importReceive: bad value: expected %d+%d=%d; got %+d", base, i, base+i, v)
    90			}
    91		}
    92		if done != nil {
    93			done <- true
    94		}
    95	}
    96	
    97	func TestExportSendImportReceive(t *testing.T) {
    98		exp, imp := pair(t)
    99		exportSend(exp, count, t, nil)
   100		importReceive(imp, t, nil)
   101	}
   102	
   103	func TestExportReceiveImportSend(t *testing.T) {
   104		exp, imp := pair(t)
   105		expDone := make(chan bool)
   106		done := make(chan bool)
   107		go func() {
   108			exportReceive(exp, t, expDone)
   109			done <- true
   110		}()
   111		<-expDone
   112		importSend(imp, count, t, nil)
   113		<-done
   114	}
   115	
   116	func TestClosingExportSendImportReceive(t *testing.T) {
   117		exp, imp := pair(t)
   118		exportSend(exp, closeCount, t, nil)
   119		importReceive(imp, t, nil)
   120	}
   121	
   122	func TestClosingImportSendExportReceive(t *testing.T) {
   123		exp, imp := pair(t)
   124		expDone := make(chan bool)
   125		done := make(chan bool)
   126		go func() {
   127			exportReceive(exp, t, expDone)
   128			done <- true
   129		}()
   130		<-expDone
   131		importSend(imp, closeCount, t, nil)
   132		<-done
   133	}
   134	
   135	func TestErrorForIllegalChannel(t *testing.T) {
   136		exp, imp := pair(t)
   137		// Now export a channel.
   138		ch := make(chan int, 1)
   139		err := exp.Export("aChannel", ch, Send)
   140		if err != nil {
   141			t.Fatal("export:", err)
   142		}
   143		ch <- 1234
   144		close(ch)
   145		// Now try to import a different channel.
   146		ch = make(chan int)
   147		err = imp.Import("notAChannel", ch, Recv, 1)
   148		if err != nil {
   149			t.Fatal("import:", err)
   150		}
   151		// Expect an error now.  Start a timeout.
   152		timeout := make(chan bool, 1) // buffered so closure will not hang around.
   153		go func() {
   154			time.Sleep(10e9) // very long, to give even really slow machines a chance.
   155			timeout <- true
   156		}()
   157		select {
   158		case err = <-imp.Errors():
   159			if strings.Index(err.String(), "no such channel") < 0 {
   160				t.Error("wrong error for nonexistent channel:", err)
   161			}
   162		case <-timeout:
   163			t.Error("import of nonexistent channel did not receive an error")
   164		}
   165	}
   166	
   167	// Not a great test but it does at least invoke Drain.
   168	func TestExportDrain(t *testing.T) {
   169		exp, imp := pair(t)
   170		done := make(chan bool)
   171		go func() {
   172			exportSend(exp, closeCount, t, nil)
   173			done <- true
   174		}()
   175		<-done
   176		go importReceive(imp, t, done)
   177		exp.Drain(0)
   178		<-done
   179	}
   180	
   181	// Not a great test but it does at least invoke Drain.
   182	func TestImportDrain(t *testing.T) {
   183		exp, imp := pair(t)
   184		expDone := make(chan bool)
   185		go exportReceive(exp, t, expDone)
   186		<-expDone
   187		importSend(imp, closeCount, t, nil)
   188		imp.Drain(0)
   189	}
   190	
   191	// Not a great test but it does at least invoke Sync.
   192	func TestExportSync(t *testing.T) {
   193		exp, imp := pair(t)
   194		done := make(chan bool)
   195		exportSend(exp, closeCount, t, nil)
   196		go importReceive(imp, t, done)
   197		exp.Sync(0)
   198		<-done
   199	}
   200	
   201	// Test hanging up the send side of an export.
   202	// TODO: test hanging up the receive side of an export.
   203	func TestExportHangup(t *testing.T) {
   204		exp, imp := pair(t)
   205		ech := make(chan int)
   206		err := exp.Export("exportedSend", ech, Send)
   207		if err != nil {
   208			t.Fatal("export:", err)
   209		}
   210		// Prepare to receive two values. We'll actually deliver only one.
   211		ich := make(chan int)
   212		err = imp.ImportNValues("exportedSend", ich, Recv, 1, 2)
   213		if err != nil {
   214			t.Fatal("import exportedSend:", err)
   215		}
   216		// Send one value, receive it.
   217		const Value = 1234
   218		ech <- Value
   219		v := <-ich
   220		if v != Value {
   221			t.Fatal("expected", Value, "got", v)
   222		}
   223		// Now hang up the channel.  Importer should see it close.
   224		exp.Hangup("exportedSend")
   225		v, ok := <-ich
   226		if ok {
   227			t.Fatal("expected channel to be closed; got value", v)
   228		}
   229	}
   230	
   231	// Test hanging up the send side of an import.
   232	// TODO: test hanging up the receive side of an import.
   233	func TestImportHangup(t *testing.T) {
   234		exp, imp := pair(t)
   235		ech := make(chan int)
   236		err := exp.Export("exportedRecv", ech, Recv)
   237		if err != nil {
   238			t.Fatal("export:", err)
   239		}
   240		// Prepare to Send two values. We'll actually deliver only one.
   241		ich := make(chan int)
   242		err = imp.ImportNValues("exportedRecv", ich, Send, 1, 2)
   243		if err != nil {
   244			t.Fatal("import exportedRecv:", err)
   245		}
   246		// Send one value, receive it.
   247		const Value = 1234
   248		ich <- Value
   249		v := <-ech
   250		if v != Value {
   251			t.Fatal("expected", Value, "got", v)
   252		}
   253		// Now hang up the channel.  Exporter should see it close.
   254		imp.Hangup("exportedRecv")
   255		v, ok := <-ech
   256		if ok {
   257			t.Fatal("expected channel to be closed; got value", v)
   258		}
   259	}
   260	
   261	// loop back exportedRecv to exportedSend,
   262	// but receive a value from ctlch before starting the loop.
   263	func exportLoopback(exp *Exporter, t *testing.T) {
   264		inch := make(chan int)
   265		if err := exp.Export("exportedRecv", inch, Recv); err != nil {
   266			t.Fatal("exportRecv")
   267		}
   268	
   269		outch := make(chan int)
   270		if err := exp.Export("exportedSend", outch, Send); err != nil {
   271			t.Fatal("exportSend")
   272		}
   273	
   274		ctlch := make(chan int)
   275		if err := exp.Export("exportedCtl", ctlch, Recv); err != nil {
   276			t.Fatal("exportRecv")
   277		}
   278	
   279		go func() {
   280			<-ctlch
   281			for i := 0; i < count; i++ {
   282				x := <-inch
   283				if x != base+i {
   284					t.Errorf("exportLoopback expected %d; got %d", i, x)
   285				}
   286				outch <- x
   287			}
   288		}()
   289	}
   290	
   291	// This test checks that channel operations can proceed
   292	// even when other concurrent operations are blocked.
   293	func TestIndependentSends(t *testing.T) {
   294		exp, imp := pair(t)
   295	
   296		exportLoopback(exp, t)
   297	
   298		importSend(imp, count, t, nil)
   299		done := make(chan bool)
   300		go importReceive(imp, t, done)
   301	
   302		// wait for export side to try to deliver some values.
   303		time.Sleep(0.25e9)
   304	
   305		ctlch := make(chan int)
   306		if err := imp.ImportNValues("exportedCtl", ctlch, Send, 1, 1); err != nil {
   307			t.Fatal("importSend:", err)
   308		}
   309		ctlch <- 0
   310	
   311		<-done
   312	}
   313	
   314	// This test cross-connects a pair of exporter/importer pairs.
   315	type value struct {
   316		I      int
   317		Source string
   318	}
   319	
   320	func TestCrossConnect(t *testing.T) {
   321		e1, i1 := pair(t)
   322		e2, i2 := pair(t)
   323	
   324		crossExport(e1, e2, t)
   325		crossImport(i1, i2, t)
   326	}
   327	
   328	// Export side of cross-traffic.
   329	func crossExport(e1, e2 *Exporter, t *testing.T) {
   330		s := make(chan value)
   331		err := e1.Export("exportedSend", s, Send)
   332		if err != nil {
   333			t.Fatal("exportSend:", err)
   334		}
   335	
   336		r := make(chan value)
   337		err = e2.Export("exportedReceive", r, Recv)
   338		if err != nil {
   339			t.Fatal("exportReceive:", err)
   340		}
   341	
   342		go crossLoop("export", s, r, t)
   343	}
   344	
   345	// Import side of cross-traffic.
   346	func crossImport(i1, i2 *Importer, t *testing.T) {
   347		s := make(chan value)
   348		err := i2.Import("exportedReceive", s, Send, 2)
   349		if err != nil {
   350			t.Fatal("import of exportedReceive:", err)
   351		}
   352	
   353		r := make(chan value)
   354		err = i1.Import("exportedSend", r, Recv, 2)
   355		if err != nil {
   356			t.Fatal("import of exported Send:", err)
   357		}
   358	
   359		crossLoop("import", s, r, t)
   360	}
   361	
   362	// Cross-traffic: send and receive 'count' numbers.
   363	func crossLoop(name string, s, r chan value, t *testing.T) {
   364		for si, ri := 0, 0; si < count && ri < count; {
   365			select {
   366			case s <- value{si, name}:
   367				si++
   368			case v := <-r:
   369				if v.I != ri {
   370					t.Errorf("loop: bad value: expected %d, hello; got %+v", ri, v)
   371				}
   372				ri++
   373			}
   374		}
   375	}
   376	
   377	const flowCount = 100
   378	
   379	// test flow control from exporter to importer.
   380	func TestExportFlowControl(t *testing.T) {
   381		exp, imp := pair(t)
   382	
   383		sendDone := make(chan bool, 1)
   384		exportSend(exp, flowCount, t, sendDone)
   385	
   386		ch := make(chan int)
   387		err := imp.ImportNValues("exportedSend", ch, Recv, 20, -1)
   388		if err != nil {
   389			t.Fatal("importReceive:", err)
   390		}
   391	
   392		testFlow(sendDone, ch, flowCount, t)
   393	}
   394	
   395	// test flow control from importer to exporter.
   396	func TestImportFlowControl(t *testing.T) {
   397		exp, imp := pair(t)
   398	
   399		ch := make(chan int)
   400		err := exp.Export("exportedRecv", ch, Recv)
   401		if err != nil {
   402			t.Fatal("importReceive:", err)
   403		}
   404	
   405		sendDone := make(chan bool, 1)
   406		importSend(imp, flowCount, t, sendDone)
   407		testFlow(sendDone, ch, flowCount, t)
   408	}
   409	
   410	func testFlow(sendDone chan bool, ch <-chan int, N int, t *testing.T) {
   411		go func() {
   412			time.Sleep(0.5e9)
   413			sendDone <- false
   414		}()
   415	
   416		if <-sendDone {
   417			t.Fatal("send did not block")
   418		}
   419		n := 0
   420		for i := range ch {
   421			t.Log("after blocking, got value ", i)
   422			n++
   423		}
   424		if n != N {
   425			t.Fatalf("expected %d values; got %d", N, n)
   426		}
   427	}
   428	
   429	func pair(t *testing.T) (*Exporter, *Importer) {
   430		c0, c1 := net.Pipe()
   431		exp := NewExporter()
   432		go exp.ServeConn(c0)
   433		imp := NewImporter(c1)
   434		return exp, imp
   435	}

release.r60.3. Except as noted, this content is licensed under a Creative Commons Attribution 3.0 License.