lib9p

Go 9P library.
Log | Files | Refs | LICENSE

client_test.go (21826B)


      1 package client
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"errors"
      7 	"io"
      8 	"math/rand"
      9 	"reflect"
     10 	"sync"
     11 	"testing"
     12 
     13 	"git.mtkn.jp/lib9p"
     14 )
     15 
     16 // TestClientCancel checks if the client goroutines cancel outstanding transactions
     17 // propperly when the Client is canceled.
     18 func TestClientCancel(t *testing.T) {
     19 	ctx, cancel := context.WithCancel(context.Background())
     20 	cr, _ := io.Pipe()
     21 	sr, cw := io.Pipe()
     22 	defer func() { cr.Close(); sr.Close() }()
     23 	c := NewClient(ctx, 1024, "", cr, cw)
     24 	wg := new(sync.WaitGroup)
     25 	wg.Add(10)
     26 	for i := 0; i < 10; i++ {
     27 		go func(i int) {
     28 			defer wg.Done()
     29 			c.Version(uint16(i), 1024, "9P2000")
     30 		}(i)
     31 	}
     32 	for i := 0; i < 5; i++ {
     33 		_, err := lib9p.RecvMsg(sr)
     34 		if err != nil {
     35 			t.Fatal(err)
     36 		}
     37 	}
     38 	cancel()
     39 	wg.Wait()
     40 }
     41 
     42 func TestDupTag(t *testing.T) {
     43 	ctx, cancel := context.WithCancel(context.Background())
     44 	c, r, _ := newClientForTest(ctx, 1024, "glenda")
     45 	defer cancel()
     46 	go c.Version(0, 1024, "9P2000")
     47 	_, err := lib9p.RecvMsg(r)
     48 	if err != nil {
     49 		t.Fatal(err)
     50 	}
     51 	_, _, err = c.Version(0, 1024, "9P2000")
     52 	if !errors.Is(err, lib9p.ErrDupTag) {
     53 		t.Error("duplicate tag error not reported: err:", err)
     54 	}
     55 }
     56 
     57 func newClientForTest(ctx context.Context, msize uint32, uname string) (*Client, io.Reader, io.Writer) {
     58 	c := &Client{
     59 		msize:     msize,
     60 		mSizeLock: new(sync.Mutex),
     61 		uname:     uname,
     62 		rPool:     newReqPool(),
     63 		wg:        new(sync.WaitGroup),
     64 	}
     65 	cr, sw := io.Pipe()
     66 	sr, cw := io.Pipe()
     67 	c.txc = c.runMultiplexer(ctx, cr, cw)
     68 	return c, sr, sw
     69 }
     70 
     71 func TestMux(t *testing.T) {
     72 	tests := []struct {
     73 		tmsg, rmsg lib9p.Msg
     74 	}{
     75 		{&lib9p.TVersion{}, &lib9p.RVersion{}},
     76 		{&lib9p.TCreate{}, &lib9p.RError{Ename: errors.New("e")}},
     77 	}
     78 
     79 	ctx, cancel := context.WithCancel(context.Background())
     80 	defer cancel()
     81 	c, r, w := newClientForTest(ctx, 1024, "glenda")
     82 	for i, test := range tests {
     83 		tag := uint16(rand.Uint32())
     84 		test.tmsg.SetTag(tag)
     85 		test.rmsg.SetTag(tag)
     86 		rq := newReq(test.tmsg)
     87 		c.txc <- rq
     88 		gottmsg, err := lib9p.RecvMsg(r)
     89 		if err != nil {
     90 			t.Error(err)
     91 			continue
     92 		}
     93 		if !reflect.DeepEqual(test.tmsg, gottmsg) {
     94 			t.Errorf("%d: mux modified tmsg:\n\twant: %v\n\tgot:  %v",
     95 				i, test.tmsg, gottmsg)
     96 			continue
     97 		}
     98 		rq0, ok := c.rPool.lookup(tag)
     99 		if !ok {
    100 			t.Errorf("%d: req not registered to the pool.", i)
    101 			continue
    102 		}
    103 		if rq != rq0 {
    104 			t.Errorf("%d: wrong req registered.", i)
    105 			continue
    106 		}
    107 		if err = lib9p.SendMsg(test.rmsg, w); err != nil {
    108 			t.Error(err)
    109 			continue
    110 		}
    111 		rq = <-rq.rxc
    112 		if !reflect.DeepEqual(test.rmsg, rq.rmsg) {
    113 			t.Errorf("%d: mux modified tmsg:\n\twant: %v\n\tgot:  %v",
    114 				i, test.tmsg, gottmsg)
    115 		}
    116 		_, ok = c.rPool.lookup(tag)
    117 		if ok {
    118 			t.Errorf("req not deleted from the pool.")
    119 			continue
    120 		}
    121 	}
    122 }
    123 
    124 func TestVersion(t *testing.T) {
    125 	tests := []struct {
    126 		name string
    127 		tmsg *lib9p.TVersion
    128 		rmsg lib9p.Msg
    129 	}{
    130 		{"0",
    131 			&lib9p.TVersion{Tag: lib9p.NOTAG, Msize: 1024, Version: "9P2000"},
    132 			&lib9p.RVersion{Tag: lib9p.NOTAG, Msize: 1024, Version: "9P2000"}},
    133 		{"1",
    134 			&lib9p.TVersion{Tag: lib9p.NOTAG, Msize: 1024, Version: "hoge"},
    135 			&lib9p.RVersion{Tag: lib9p.NOTAG, Msize: 1024, Version: "unknown"}},
    136 	}
    137 	for _, test := range tests {
    138 		func() {
    139 			ctx, cancel := context.WithCancel(context.Background())
    140 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    141 			defer cancel()
    142 			var (
    143 				gotmsize   uint32
    144 				gotversion string
    145 				goterr     error
    146 				done       = make(chan struct{})
    147 			)
    148 			go func() {
    149 				ifcall := test.tmsg
    150 				gotmsize, gotversion, goterr =
    151 					c.Version(ifcall.Tag, ifcall.Msize, ifcall.Version)
    152 				close(done)
    153 			}()
    154 			gottmsg, err := lib9p.RecvMsg(r)
    155 			if err != nil {
    156 				t.Error(err)
    157 			}
    158 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    159 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    160 					test.name, test.tmsg, gottmsg)
    161 				return
    162 			}
    163 			lib9p.SendMsg(test.rmsg, w)
    164 			<-done
    165 			switch ofcall := test.rmsg.(type) {
    166 			case *lib9p.RVersion:
    167 				if goterr != nil {
    168 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    169 					return
    170 				}
    171 				if ofcall.Msize != gotmsize || ofcall.Version != gotversion {
    172 					t.Errorf("%s: (mSize, verion) want: %d, %s, got: %d, %s",
    173 						test.name, ofcall.Msize, ofcall.Version,
    174 						gotmsize, gotversion)
    175 				}
    176 			case *lib9p.RError:
    177 				if goterr == nil {
    178 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    179 				}
    180 			default:
    181 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    182 			}
    183 		}()
    184 	}
    185 }
    186 
    187 func TestAuth(t *testing.T) {
    188 	tests := []struct {
    189 		name string
    190 		tmsg *lib9p.TAuth
    191 		rmsg lib9p.Msg
    192 	}{
    193 		{"0",
    194 			&lib9p.TAuth{Tag: 0, Afid: lib9p.NOFID, Uname: "glenda", Aname: ""},
    195 			&lib9p.RError{Tag: 0, Ename: errors.New("authentication not required.")}},
    196 		{"1",
    197 			&lib9p.TAuth{Tag: 0, Afid: 0, Uname: "glenda", Aname: ""},
    198 			&lib9p.RAuth{Tag: 0, Aqid: lib9p.Qid{Path: 1}}},
    199 	}
    200 	for _, test := range tests {
    201 		func() {
    202 			ctx, cancel := context.WithCancel(context.Background())
    203 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    204 			defer cancel()
    205 			var (
    206 				gotaqid lib9p.Qid
    207 				goterr  error
    208 				done    = make(chan struct{})
    209 			)
    210 			go func() {
    211 				ifcall := test.tmsg
    212 				gotaqid, goterr =
    213 					c.Auth(ifcall.Tag, ifcall.Afid, ifcall.Uname, ifcall.Aname)
    214 				close(done)
    215 			}()
    216 			gottmsg, err := lib9p.RecvMsg(r)
    217 			if err != nil {
    218 				t.Error(err)
    219 			}
    220 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    221 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    222 					test.name, test.tmsg, gottmsg)
    223 				return
    224 			}
    225 			lib9p.SendMsg(test.rmsg, w)
    226 			<-done
    227 			switch ofcall := test.rmsg.(type) {
    228 			case *lib9p.RAuth:
    229 				if goterr != nil {
    230 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    231 					return
    232 				}
    233 				if ofcall.Aqid != gotaqid {
    234 					t.Errorf("%s: (qid) want: %v, got: %v",
    235 						test.name, ofcall.Aqid, gotaqid)
    236 				}
    237 			case *lib9p.RError:
    238 				if goterr == nil {
    239 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    240 				}
    241 			default:
    242 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    243 			}
    244 		}()
    245 	}
    246 }
    247 
    248 func TestAttach(t *testing.T) {
    249 	tests := []struct {
    250 		name string
    251 		tmsg *lib9p.TAttach
    252 		rmsg lib9p.Msg
    253 	}{
    254 		{"0",
    255 			&lib9p.TAttach{Fid: 0, Afid: lib9p.NOFID, Uname: "glenda", Aname: ""},
    256 			&lib9p.RAttach{Qid: lib9p.Qid{Path: 2}}},
    257 		{"1",
    258 			&lib9p.TAttach{Fid: 0, Afid: lib9p.NOFID, Uname: "glenda", Aname: ""},
    259 			&lib9p.RError{Ename: errors.New("authentication required")}},
    260 	}
    261 	for _, test := range tests {
    262 		func() {
    263 			ctx, cancel := context.WithCancel(context.Background())
    264 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    265 			defer cancel()
    266 			var (
    267 				gotqid lib9p.Qid
    268 				goterr error
    269 				done   = make(chan struct{})
    270 			)
    271 			go func() {
    272 				ifcall := test.tmsg
    273 				gotqid, goterr =
    274 					c.Attach(ifcall.Tag, ifcall.Fid, ifcall.Afid, ifcall.Uname, ifcall.Aname)
    275 				close(done)
    276 			}()
    277 			gottmsg, err := lib9p.RecvMsg(r)
    278 			if err != nil {
    279 				t.Error(err)
    280 			}
    281 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    282 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    283 					test.name, test.tmsg, gottmsg)
    284 				return
    285 			}
    286 			lib9p.SendMsg(test.rmsg, w)
    287 			<-done
    288 			switch ofcall := test.rmsg.(type) {
    289 			case *lib9p.RAttach:
    290 				if goterr != nil {
    291 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    292 					return
    293 				}
    294 				if ofcall.Qid != gotqid {
    295 					t.Errorf("%s: (qid) want: %v, got: %v",
    296 						test.name, ofcall.Qid, gotqid)
    297 				}
    298 			case *lib9p.RError:
    299 				if goterr == nil {
    300 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    301 				}
    302 			default:
    303 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    304 			}
    305 		}()
    306 	}
    307 }
    308 
    309 func TestFlush(t *testing.T) {
    310 	tests := []struct {
    311 		name string
    312 		tmsg *lib9p.TFlush
    313 		rmsg lib9p.Msg
    314 	}{
    315 		{"0",
    316 			&lib9p.TFlush{Oldtag: 1},
    317 			&lib9p.RFlush{}},
    318 	}
    319 	for _, test := range tests {
    320 		func() {
    321 			ctx, cancel := context.WithCancel(context.Background())
    322 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    323 			defer cancel()
    324 			var (
    325 				goterr error
    326 				done   = make(chan struct{})
    327 			)
    328 			go func() {
    329 				ifcall := test.tmsg
    330 				goterr =
    331 					c.Flush(ifcall.Tag, ifcall.Oldtag)
    332 				close(done)
    333 			}()
    334 			gottmsg, err := lib9p.RecvMsg(r)
    335 			if err != nil {
    336 				t.Error(err)
    337 			}
    338 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    339 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    340 					test.name, test.tmsg, gottmsg)
    341 				return
    342 			}
    343 			lib9p.SendMsg(test.rmsg, w)
    344 			<-done
    345 			switch ofcall := test.rmsg.(type) {
    346 			case *lib9p.RFlush:
    347 				if goterr != nil {
    348 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    349 					return
    350 				}
    351 			case *lib9p.RError:
    352 				if goterr == nil {
    353 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    354 				}
    355 			default:
    356 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    357 			}
    358 		}()
    359 	}
    360 }
    361 
    362 func TestWalk(t *testing.T) {
    363 	tests := []struct {
    364 		name string
    365 		tmsg *lib9p.TWalk
    366 		rmsg lib9p.Msg
    367 	}{
    368 		{"0",
    369 			&lib9p.TWalk{Fid: 0, Newfid: 1, Wnames: []string{"a", "b", "c"}},
    370 			&lib9p.RWalk{Qids: []lib9p.Qid{lib9p.Qid{Path: 0}, lib9p.Qid{Path: 1}, lib9p.Qid{Path: 2}}}},
    371 		{"1",
    372 			&lib9p.TWalk{Fid: 0, Newfid: 2, Wnames: []string{"a", "b", "c"}},
    373 			&lib9p.RError{Ename: errors.New("not found")}},
    374 	}
    375 	for _, test := range tests {
    376 		func() {
    377 			ctx, cancel := context.WithCancel(context.Background())
    378 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    379 			defer cancel()
    380 			var (
    381 				gotqids []lib9p.Qid
    382 				goterr  error
    383 				done    = make(chan struct{})
    384 			)
    385 			go func() {
    386 				ifcall := test.tmsg
    387 				gotqids, goterr =
    388 					c.Walk(ifcall.Tag, ifcall.Fid, ifcall.Newfid, ifcall.Wnames)
    389 				close(done)
    390 			}()
    391 			gottmsg, err := lib9p.RecvMsg(r)
    392 			if err != nil {
    393 				t.Error(err)
    394 			}
    395 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    396 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    397 					test.name, test.tmsg, gottmsg)
    398 				return
    399 			}
    400 			lib9p.SendMsg(test.rmsg, w)
    401 			<-done
    402 			switch ofcall := test.rmsg.(type) {
    403 			case *lib9p.RWalk:
    404 				if goterr != nil {
    405 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    406 					return
    407 				}
    408 				if !reflect.DeepEqual(ofcall.Qids, gotqids) {
    409 					t.Errorf("%s: (qids) want: %v, got: %v",
    410 						test.name, ofcall.Qids, gotqids)
    411 				}
    412 			case *lib9p.RError:
    413 				if goterr == nil {
    414 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    415 				}
    416 			default:
    417 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    418 			}
    419 		}()
    420 	}
    421 }
    422 
    423 func TestOpen(t *testing.T) {
    424 	tests := []struct {
    425 		name string
    426 		tmsg *lib9p.TOpen
    427 		rmsg lib9p.Msg
    428 	}{
    429 		{"0",
    430 			&lib9p.TOpen{Fid: 0, Mode: lib9p.OREAD},
    431 			&lib9p.ROpen{Qid: lib9p.Qid{Path: 1}, Iounit: 1000}},
    432 		{"1",
    433 			&lib9p.TOpen{Fid: 0, Mode: lib9p.OWRITE},
    434 			&lib9p.RError{Ename: errors.New("permission denied")}},
    435 	}
    436 	for _, test := range tests {
    437 		func() {
    438 			ctx, cancel := context.WithCancel(context.Background())
    439 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    440 			defer cancel()
    441 			var (
    442 				gotqid    lib9p.Qid
    443 				gotiounit uint32
    444 				goterr    error
    445 				done      = make(chan struct{})
    446 			)
    447 			go func() {
    448 				ifcall := test.tmsg
    449 				gotqid, gotiounit, goterr =
    450 					c.Open(ifcall.Tag, ifcall.Fid, ifcall.Mode)
    451 				close(done)
    452 			}()
    453 			gottmsg, err := lib9p.RecvMsg(r)
    454 			if err != nil {
    455 				t.Error(err)
    456 			}
    457 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    458 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    459 					test.name, test.tmsg, gottmsg)
    460 				return
    461 			}
    462 			lib9p.SendMsg(test.rmsg, w)
    463 			<-done
    464 			switch ofcall := test.rmsg.(type) {
    465 			case *lib9p.ROpen:
    466 				if goterr != nil {
    467 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    468 					return
    469 				}
    470 				if ofcall.Qid != gotqid || ofcall.Iounit != gotiounit {
    471 					t.Errorf("%s: (qid, iounit) want: %v, %d, got: %v, %d",
    472 						test.name, ofcall.Qid, ofcall.Iounit, gotqid, gotiounit)
    473 				}
    474 			case *lib9p.RError:
    475 				if goterr == nil {
    476 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    477 				}
    478 			default:
    479 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    480 			}
    481 		}()
    482 	}
    483 }
    484 
    485 func TestCreate(t *testing.T) {
    486 	tests := []struct {
    487 		name string
    488 		tmsg *lib9p.TCreate
    489 		rmsg lib9p.Msg
    490 	}{
    491 		{"0",
    492 			&lib9p.TCreate{Fid: 0, Name: "file", Perm: 0666, Mode: lib9p.OREAD},
    493 			&lib9p.RCreate{Qid: lib9p.Qid{Path: 0}, Iounit: 1000}},
    494 		{"1",
    495 			&lib9p.TCreate{Fid: 0, Name: "file", Perm: 0777, Mode: lib9p.OWRITE},
    496 			&lib9p.RError{Ename: errors.New("permission denied")}},
    497 	}
    498 	for _, test := range tests {
    499 		func() {
    500 			ctx, cancel := context.WithCancel(context.Background())
    501 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    502 			defer cancel()
    503 			var (
    504 				gotqid    lib9p.Qid
    505 				gotiounit uint32
    506 				goterr    error
    507 				done      = make(chan struct{})
    508 			)
    509 			go func() {
    510 				ifcall := test.tmsg
    511 				gotqid, gotiounit, goterr =
    512 					c.Create(ifcall.Tag, ifcall.Fid, ifcall.Name, ifcall.Perm, ifcall.Mode)
    513 				close(done)
    514 			}()
    515 			gottmsg, err := lib9p.RecvMsg(r)
    516 			if err != nil {
    517 				t.Error(err)
    518 			}
    519 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    520 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    521 					test.name, test.tmsg, gottmsg)
    522 				return
    523 			}
    524 			lib9p.SendMsg(test.rmsg, w)
    525 			<-done
    526 			switch ofcall := test.rmsg.(type) {
    527 			case *lib9p.RCreate:
    528 				if goterr != nil {
    529 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    530 					return
    531 				}
    532 				if ofcall.Qid != gotqid || ofcall.Iounit != gotiounit {
    533 					t.Errorf("%s: (qid, iounit) want: %v, %d, got: %v, %d",
    534 						test.name, ofcall.Qid, ofcall.Iounit, gotqid, gotiounit)
    535 				}
    536 			case *lib9p.RError:
    537 				if goterr == nil {
    538 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    539 				}
    540 			default:
    541 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    542 			}
    543 		}()
    544 	}
    545 }
    546 
    547 func TestRead(t *testing.T) {
    548 	tests := []struct {
    549 		name string
    550 		tmsg *lib9p.TRead
    551 		rmsg lib9p.Msg
    552 	}{
    553 		{"0",
    554 			&lib9p.TRead{Fid: 0, Offset: 0, Count: 1000},
    555 			&lib9p.RRead{Count: 4, Data: []byte("hoge")}},
    556 		{"1",
    557 			&lib9p.TRead{Fid: 0, Offset: 0, Count: 1000},
    558 			&lib9p.RError{Ename: errors.New("not open")}},
    559 	}
    560 	for _, test := range tests {
    561 		func() {
    562 			ctx, cancel := context.WithCancel(context.Background())
    563 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    564 			defer cancel()
    565 			var (
    566 				gotdata []byte
    567 				goterr  error
    568 				done    = make(chan struct{})
    569 			)
    570 			go func() {
    571 				ifcall := test.tmsg
    572 				gotdata, goterr =
    573 					c.Read(ifcall.Tag, ifcall.Fid, ifcall.Offset, ifcall.Count)
    574 				close(done)
    575 			}()
    576 			gottmsg, err := lib9p.RecvMsg(r)
    577 			if err != nil {
    578 				t.Error(err)
    579 			}
    580 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    581 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    582 					test.name, test.tmsg, gottmsg)
    583 				return
    584 			}
    585 			lib9p.SendMsg(test.rmsg, w)
    586 			<-done
    587 			switch ofcall := test.rmsg.(type) {
    588 			case *lib9p.RRead:
    589 				if goterr != nil {
    590 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    591 					return
    592 				}
    593 				if !bytes.Equal(ofcall.Data, gotdata) {
    594 					t.Errorf("%s: (data) want: %v, got: %v",
    595 						test.name, ofcall.Data, gotdata)
    596 				}
    597 			case *lib9p.RError:
    598 				if goterr == nil {
    599 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    600 				}
    601 			default:
    602 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    603 			}
    604 		}()
    605 	}
    606 }
    607 
    608 func TestWrite(t *testing.T) {
    609 	tests := []struct {
    610 		name string
    611 		tmsg *lib9p.TWrite
    612 		rmsg lib9p.Msg
    613 	}{
    614 		{"0",
    615 			&lib9p.TWrite{Fid: 0, Offset: 0, Count: 4, Data: []byte("hoge")},
    616 			&lib9p.RWrite{Count: 4}},
    617 		{"1",
    618 			&lib9p.TWrite{Fid: 0, Offset: 0, Count: 4, Data: []byte("hoge")},
    619 			&lib9p.RError{Ename: errors.New("not open")}},
    620 	}
    621 	for _, test := range tests {
    622 		func() {
    623 			ctx, cancel := context.WithCancel(context.Background())
    624 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    625 			defer cancel()
    626 			var (
    627 				gotcount uint32
    628 				goterr   error
    629 				done     = make(chan struct{})
    630 			)
    631 			go func() {
    632 				ifcall := test.tmsg
    633 				gotcount, goterr =
    634 					c.Write(ifcall.Tag, ifcall.Fid, ifcall.Offset, ifcall.Count, ifcall.Data)
    635 				close(done)
    636 			}()
    637 			gottmsg, err := lib9p.RecvMsg(r)
    638 			if err != nil {
    639 				t.Error(err)
    640 			}
    641 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    642 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    643 					test.name, test.tmsg, gottmsg)
    644 				return
    645 			}
    646 			lib9p.SendMsg(test.rmsg, w)
    647 			<-done
    648 			switch ofcall := test.rmsg.(type) {
    649 			case *lib9p.RWrite:
    650 				if goterr != nil {
    651 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    652 					return
    653 				}
    654 				if ofcall.Count != gotcount {
    655 					t.Errorf("%s: (count) want: %v, got: %v",
    656 						test.name, ofcall.Count, gotcount)
    657 				}
    658 			case *lib9p.RError:
    659 				if goterr == nil {
    660 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    661 				}
    662 			default:
    663 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    664 			}
    665 		}()
    666 	}
    667 }
    668 
    669 func TestClunk(t *testing.T) {
    670 	tests := []struct {
    671 		name string
    672 		tmsg *lib9p.TClunk
    673 		rmsg lib9p.Msg
    674 	}{
    675 		{"0",
    676 			&lib9p.TClunk{Fid: 0},
    677 			&lib9p.RClunk{}},
    678 		{"1",
    679 			&lib9p.TClunk{Fid: 0},
    680 			&lib9p.RError{Ename: errors.New("unknown fid")}},
    681 	}
    682 	for _, test := range tests {
    683 		func() {
    684 			ctx, cancel := context.WithCancel(context.Background())
    685 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    686 			defer cancel()
    687 			var (
    688 				goterr error
    689 				done   = make(chan struct{})
    690 			)
    691 			go func() {
    692 				ifcall := test.tmsg
    693 				goterr =
    694 					c.Clunk(ifcall.Tag, ifcall.Fid)
    695 				close(done)
    696 			}()
    697 			gottmsg, err := lib9p.RecvMsg(r)
    698 			if err != nil {
    699 				t.Error(err)
    700 			}
    701 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    702 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    703 					test.name, test.tmsg, gottmsg)
    704 				return
    705 			}
    706 			lib9p.SendMsg(test.rmsg, w)
    707 			<-done
    708 			switch ofcall := test.rmsg.(type) {
    709 			case *lib9p.RClunk:
    710 				if goterr != nil {
    711 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    712 					return
    713 				}
    714 			case *lib9p.RError:
    715 				if goterr == nil {
    716 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    717 				}
    718 			default:
    719 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    720 			}
    721 		}()
    722 	}
    723 }
    724 
    725 func TestRemove(t *testing.T) {
    726 	tests := []struct {
    727 		name string
    728 		tmsg *lib9p.TRemove
    729 		rmsg lib9p.Msg
    730 	}{
    731 		{"0",
    732 			&lib9p.TRemove{Fid: 0},
    733 			&lib9p.RRemove{}},
    734 		{"1",
    735 			&lib9p.TRemove{Fid: 0},
    736 			&lib9p.RError{Ename: errors.New("unknown fid")}},
    737 	}
    738 	for _, test := range tests {
    739 		func() {
    740 			ctx, cancel := context.WithCancel(context.Background())
    741 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    742 			defer cancel()
    743 			var (
    744 				goterr error
    745 				done   = make(chan struct{})
    746 			)
    747 			go func() {
    748 				ifcall := test.tmsg
    749 				goterr =
    750 					c.Remove(ifcall.Tag, ifcall.Fid)
    751 				close(done)
    752 			}()
    753 			gottmsg, err := lib9p.RecvMsg(r)
    754 			if err != nil {
    755 				t.Error(err)
    756 			}
    757 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    758 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    759 					test.name, test.tmsg, gottmsg)
    760 				return
    761 			}
    762 			lib9p.SendMsg(test.rmsg, w)
    763 			<-done
    764 			switch ofcall := test.rmsg.(type) {
    765 			case *lib9p.RRemove:
    766 				if goterr != nil {
    767 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    768 					return
    769 				}
    770 			case *lib9p.RError:
    771 				if goterr == nil {
    772 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    773 				}
    774 			default:
    775 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    776 			}
    777 		}()
    778 	}
    779 }
    780 
    781 func TestStat(t *testing.T) {
    782 	tests := []struct {
    783 		name string
    784 		tmsg *lib9p.TStat
    785 		rmsg lib9p.Msg
    786 	}{
    787 		{"0",
    788 			&lib9p.TStat{Fid: 0},
    789 			&lib9p.RStat{Stat: &lib9p.Stat{Name: "file"}}},
    790 	}
    791 	for _, test := range tests {
    792 		func() {
    793 			ctx, cancel := context.WithCancel(context.Background())
    794 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    795 			defer cancel()
    796 			var (
    797 				gotstat *lib9p.Stat
    798 				goterr  error
    799 				done    = make(chan struct{})
    800 			)
    801 			go func() {
    802 				ifcall := test.tmsg
    803 				gotstat, goterr =
    804 					c.Stat(ifcall.Tag, ifcall.Fid)
    805 				close(done)
    806 			}()
    807 			gottmsg, err := lib9p.RecvMsg(r)
    808 			if err != nil {
    809 				t.Error(err)
    810 			}
    811 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    812 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    813 					test.name, test.tmsg, gottmsg)
    814 				return
    815 			}
    816 			lib9p.SendMsg(test.rmsg, w)
    817 			<-done
    818 			switch ofcall := test.rmsg.(type) {
    819 			case *lib9p.RStat:
    820 				if goterr != nil {
    821 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    822 					return
    823 				}
    824 				if !reflect.DeepEqual(ofcall.Stat, gotstat) {
    825 					t.Errorf("%s: (stat) want: %v, got: %v",
    826 						test.name, ofcall.Stat, gotstat)
    827 				}
    828 			case *lib9p.RError:
    829 				if goterr == nil {
    830 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    831 				}
    832 			default:
    833 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    834 			}
    835 		}()
    836 	}
    837 }
    838 
    839 func TestWstat(t *testing.T) {
    840 	tests := []struct {
    841 		name string
    842 		tmsg *lib9p.TWstat
    843 		rmsg lib9p.Msg
    844 	}{
    845 		{"0",
    846 			&lib9p.TWstat{Fid: 0, Stat: &lib9p.Stat{Name: "file", Gid: "ken"}},
    847 			&lib9p.RWstat{}},
    848 		{"1",
    849 			&lib9p.TWstat{Fid: 0, Stat: &lib9p.Stat{Name: "file", Uid: "ken"}},
    850 			&lib9p.RError{Ename: errors.New("permission denied.")}},
    851 	}
    852 	for _, test := range tests {
    853 		func() {
    854 			ctx, cancel := context.WithCancel(context.Background())
    855 			c, r, w := newClientForTest(ctx, 1024, "glenda")
    856 			defer cancel()
    857 			var (
    858 				goterr error
    859 				done   = make(chan struct{})
    860 			)
    861 			go func() {
    862 				ifcall := test.tmsg
    863 				goterr =
    864 					c.Wstat(ifcall.Tag, ifcall.Fid, ifcall.Stat)
    865 				close(done)
    866 			}()
    867 			gottmsg, err := lib9p.RecvMsg(r)
    868 			if err != nil {
    869 				t.Error(err)
    870 			}
    871 			if !reflect.DeepEqual(test.tmsg, gottmsg) {
    872 				t.Errorf("%s: tmsg modified:\n\twant: %v\n\tgot:  %v",
    873 					test.name, test.tmsg, gottmsg)
    874 				return
    875 			}
    876 			lib9p.SendMsg(test.rmsg, w)
    877 			<-done
    878 			switch ofcall := test.rmsg.(type) {
    879 			case *lib9p.RWstat:
    880 				if goterr != nil {
    881 					t.Errorf("%s: unexpected error: %v", test.name, goterr)
    882 					return
    883 				}
    884 			case *lib9p.RError:
    885 				if goterr == nil {
    886 					t.Errorf("%s: error expected: %v", test.name, ofcall)
    887 				}
    888 			default:
    889 				t.Errorf("%s: unexpected message: %v", test.name, ofcall)
    890 			}
    891 		}()
    892 	}
    893 }