lib9p

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

server2_test.go (6934B)


      1 package lib9p
      2 
      3 import (
      4 	"bytes"
      5 	"context"
      6 	"errors"
      7 	"io"
      8 	"os"
      9 	"reflect"
     10 	"sync"
     11 	"testing"
     12 )
     13 
     14 // TestRunListener tests if the listener goroutine receives 9P messages
     15 // and send them through the server's listenChan channel.
     16 // It also checks whether the listener goroutine returns by canceling
     17 // ctx, by checking if the server's listenChan is closed.
     18 func TestRunListener(t *testing.T) {
     19 	tFile, err := os.Open("testdata/test_Tmsg.dat")
     20 	if err != nil {
     21 		t.Fatalf("open file: %v", err)
     22 	}
     23 	defer tFile.Close()
     24 	tFile2, err := os.Open("testdata/test_Tmsg.dat")
     25 	if err != nil {
     26 		t.Fatalf("open file: %v", err)
     27 	}
     28 	defer tFile2.Close()
     29 	c := &Conn{
     30 		s: &Server{chatty9P: false},
     31 		r: tFile,
     32 	}
     33 	oldReqPoolAdd := reqPoolAdd
     34 	defer func() { reqPoolAdd = oldReqPoolAdd }()
     35 	reqPoolAdd = func(*reqPool, uint16) (*request, error) { return &request{}, nil }
     36 	ctx, cancel := context.WithCancel(context.Background())
     37 	defer cancel()
     38 	c.runListener(ctx, newReqPool())
     39 	for {
     40 		want, err := RecvMsg(tFile2)
     41 		if err == io.EOF {
     42 			break
     43 		} else if err != nil {
     44 			t.Fatalf("recvmsg: %v", err)
     45 		}
     46 		r := <-c.listenChan
     47 		if r.listenErr != nil {
     48 			t.Fatalf("listenErr: %v", r.listenErr)
     49 		}
     50 		got := r.ifcall
     51 		if !reflect.DeepEqual(want, got) {
     52 			t.Errorf("listener modified message:\n\twant: %v\n\tgot: %v",
     53 				want, got)
     54 		}
     55 	}
     56 }
     57 
     58 // TestRunSpeaker tests if the speaker goroutine receives 9P messages
     59 // and send them through the server's speakChan channel.
     60 func TestRunResponder(t *testing.T) {
     61 	rFile, err := os.Open("testdata/test_Rmsg.dat")
     62 	if err != nil {
     63 		t.Fatalf("open file: %v", err)
     64 	}
     65 	defer rFile.Close()
     66 	r, w := io.Pipe()
     67 	c := &Conn{s: &Server{chatty9P: false}, w: w}
     68 	rp := newReqPool()
     69 	ctx, cancel := context.WithCancel(context.Background())
     70 	defer cancel()
     71 	c.runResponder(ctx, rp)
     72 	for {
     73 		want, err := readMsg(rFile)
     74 		if err == io.EOF {
     75 			break
     76 		} else if err != nil {
     77 			t.Fatalf("readmsg: %v", err)
     78 		}
     79 		msg, err := unmarshal(want)
     80 		if err != nil {
     81 			t.Fatalf("unmarshal %v", err)
     82 		}
     83 		c.respChan <- &request{
     84 			tag:    msg.GetTag(),
     85 			ofcall: msg,
     86 		}
     87 		got := make([]byte, len(want))
     88 		_, err = io.ReadFull(r, got)
     89 		if err != nil {
     90 			t.Fatalf("readfull: %v", err)
     91 		}
     92 		if !bytes.Equal(want, got) {
     93 			t.Errorf("responder modified message:\n\twant: %v\n\tgot: %v",
     94 				want, got)
     95 		}
     96 	}
     97 }
     98 
     99 func TestGetReq(t *testing.T) {
    100 	tFile, err := os.Open("testdata/test_Tmsg.dat")
    101 	if err != nil {
    102 		t.Fatalf("open file: %v", err)
    103 	}
    104 	defer tFile.Close()
    105 	tFile2, err := os.Open("testdata/test_Tmsg.dat")
    106 	if err != nil {
    107 		t.Fatalf("open file: %v", err)
    108 	}
    109 	defer tFile2.Close()
    110 	rp := newReqPool()
    111 	for {
    112 		got := getReq(tFile, rp, false)
    113 		if got.listenErr == io.EOF {
    114 			break
    115 		} else if got.listenErr != nil {
    116 			t.Fatalf("getReq: %v", got.listenErr)
    117 		}
    118 		wantMsg, err := RecvMsg(tFile2)
    119 		if err != nil {
    120 			t.Fatalf("recvmsg: %v", err)
    121 		}
    122 		if got.tag != wantMsg.GetTag() {
    123 			t.Errorf("r.tag: want: %v, got: %v", wantMsg.GetTag(), got.tag)
    124 		}
    125 		if !reflect.DeepEqual(got.ifcall, wantMsg) {
    126 			t.Errorf("r.ifcall:\n\twant: %v,\n\tgot:  %v", wantMsg, got.ifcall)
    127 		}
    128 		got2, ok := rp.lookup(wantMsg.GetTag())
    129 		if !ok {
    130 			t.Errorf("request not registered to the pool")
    131 		}
    132 		if got != got2 {
    133 			t.Errorf("wrong message in pool:\n\twant: %p,\n\tgot:  %p", got, got2)
    134 		}
    135 		rp.delete(wantMsg.GetTag())
    136 	}
    137 }
    138 
    139 func TestSVersion(t *testing.T) {
    140 	tests := []struct {
    141 		input *request
    142 		want  *request
    143 	}{
    144 		{&request{ifcall: &TVersion{Msize: 1024, Version: "9P2000"}},
    145 			&request{ofcall: &RVersion{Msize: 1024, Version: "9P2000"}}},
    146 		{&request{ifcall: &TVersion{Msize: 564, Version: "9P2000"}},
    147 			&request{ofcall: &RVersion{Msize: 564, Version: "9P2000"}}},
    148 		{&request{ifcall: &TVersion{Msize: 8 * 1024, Version: "9P2000"}},
    149 			&request{ofcall: &RVersion{Msize: 1024, Version: "9P2000"}}},
    150 		{&request{ifcall: &TVersion{Msize: 1024, Version: "unko"}},
    151 			&request{ofcall: &RVersion{Msize: 1024, Version: "unknown"}}},
    152 	}
    153 	tc := make(chan *request)
    154 	rc := make(chan *request)
    155 	c := &Conn{msize: 1024, mSizeLock: new(sync.Mutex), respChan: rc}
    156 	ctx, cancel := context.WithCancel(context.Background())
    157 	defer cancel()
    158 	go sVersion(ctx, c, tc)
    159 	for _, test := range tests {
    160 		oldMsize := c.msize
    161 		tc <- test.input
    162 		ifcall := test.input.ifcall.(*TVersion)
    163 		wantmsg := test.want.ofcall.(*RVersion)
    164 		gotmsg := (<-rc).ofcall.(*RVersion)
    165 		if !reflect.DeepEqual(wantmsg, gotmsg) {
    166 			t.Errorf("want: %v,\n\tgot:  %v", wantmsg, gotmsg)
    167 		}
    168 		if ifcall.Msize < oldMsize && c.msize != ifcall.Msize {
    169 			t.Errorf("msize not changed")
    170 		}
    171 		if ifcall.Msize >= oldMsize && c.msize != oldMsize {
    172 			t.Errorf("msize changed unexpectedly")
    173 		}
    174 		c.msize = oldMsize
    175 	}
    176 }
    177 
    178 func TestSAuth(t *testing.T) {
    179 	tests := []struct {
    180 		input    *request
    181 		want     *request
    182 		authFunc func(context.Context, *request)
    183 	}{
    184 		{&request{ifcall: &TAuth{Afid: NOFID, Uname: "kenji", Aname: ""}},
    185 			&request{ofcall: &RError{Ename: errors.New("authentication not required")}}, nil},
    186 		{&request{ifcall: &TAuth{Afid: NOFID, Uname: "kenji", Aname: ""}},
    187 			&request{ofcall: &RError{Ename: errors.New("NOFID can't be used for afid")}},
    188 			func(ctx context.Context, r *request) {}},
    189 		{&request{ifcall: &TAuth{Afid: 0, Uname: "kenji", Aname: ""}},
    190 			&request{ofcall: &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}},
    191 			func(ctx context.Context, r *request) {
    192 				r.ofcall = &RAuth{Tag: 0, Aqid: Qid{0, 1, 2}}
    193 			}},
    194 	}
    195 	for _, test := range tests {
    196 		func() {
    197 			tc := make(chan *request)
    198 			rc := make(chan *request)
    199 			defer close(tc)
    200 			defer close(rc)
    201 			s := &Server{Auth: test.authFunc}
    202 			c := &Conn{s: s, respChan: rc, fPool: newFidPool()}
    203 			ctx, cancel := context.WithCancel(context.Background())
    204 			defer cancel()
    205 			go sAuth(ctx, c, tc)
    206 			tc <- test.input
    207 			ofcall := (<-rc).ofcall
    208 			switch wantmsg := test.want.ofcall.(type) {
    209 			case *RAuth:
    210 				gotmsg, ok := ofcall.(*RAuth)
    211 				if !ok {
    212 					t.Errorf("unexpected message: %v", ofcall)
    213 					return
    214 				}
    215 				if !reflect.DeepEqual(wantmsg, gotmsg) {
    216 					t.Errorf("want: %v,\n\tgot:  %v", wantmsg, gotmsg)
    217 					return
    218 				}
    219 			case *RError:
    220 				_, ok := ofcall.(*RError)
    221 				if !ok {
    222 					t.Errorf("unexpected message: %v", ofcall)
    223 					return
    224 				}
    225 			default:
    226 				t.Fatalf("unexpected message: %v", wantmsg)
    227 			}
    228 		}()
    229 	}
    230 }
    231 
    232 func TestSFlush(t *testing.T) {
    233 	rp := newReqPool()
    234 	tests := []struct {
    235 		input *request
    236 	}{
    237 		{&request{ifcall: &TFlush{},
    238 			oldreq: &request{pool: rp, done: make(chan struct{})}}},
    239 	}
    240 	tc := make(chan *request)
    241 	rc := make(chan *request)
    242 	c := &Conn{msize: 1024, mSizeLock: new(sync.Mutex), respChan: rc}
    243 	ctx, cancel := context.WithCancel(context.Background())
    244 	defer cancel()
    245 	go sFlush(ctx, c, tc)
    246 	for _, test := range tests {
    247 		tc <- test.input
    248 		if gotmsg, ok := (<-rc).ofcall.(*RFlush); !ok {
    249 			t.Errorf("unexpected message: %v", gotmsg)
    250 		}
    251 		if _, ok := <-test.input.oldreq.done; ok {
    252 			t.Errorf("done channel not closed")
    253 		}
    254 	}
    255 }