protocol_test.go 15 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. // Copyright 2009 The Ninep 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. package protocol
  5. import (
  6. "bytes"
  7. "fmt"
  8. "net"
  9. "os"
  10. "reflect"
  11. "testing"
  12. )
  13. var (
  14. removedFID2 bool
  15. )
  16. func print(f string, args ...interface{}) {
  17. fmt.Fprintf(os.Stderr, f+"\n", args...)
  18. }
  19. func newEcho() *echo {
  20. return &echo{
  21. qids: make(map[FID]QID),
  22. }
  23. }
  24. // Two files, dotu was true.
  25. var testunpackbytes = []byte{
  26. 79, 0, 0, 0, 0, 0, 0, 0, 0, 228, 193, 233, 248, 44, 145, 3, 0, 0, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 47, 117, 180, 83, 102, 3, 0, 0, 0, 0, 0, 0, 6, 0, 112, 97, 115, 115, 119, 100, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 0, 0, 232, 3, 0, 0, 232, 3, 0, 0, 255, 255, 255, 255, 78, 0, 0, 0, 0, 0, 0, 0, 0, 123, 171, 233, 248, 42, 145, 3, 0, 0, 0, 0, 0, 164, 1, 0, 0, 0, 0, 0, 0, 41, 117, 180, 83, 195, 0, 0, 0, 0, 0, 0, 0, 5, 0, 104, 111, 115, 116, 115, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 4, 0, 110, 111, 110, 101, 0, 0, 232, 3, 0, 0, 232, 3, 0, 0, 255, 255, 255, 255,
  27. }
  28. /*
  29. func testUnpackDir(t *testing.T) {
  30. b := testunpackbytes
  31. for len(b) > 0 {
  32. var err error
  33. if _, b, _, err = UnpackDir(b, true); err != nil {
  34. t.Fatalf("Unpackdir: %v", err)
  35. }
  36. }
  37. }
  38. */
  39. func TestEncode(t *testing.T) {
  40. // The traces used in this array came from running 9p servers and clients.
  41. // Except for flush, which we made up.
  42. // TODO: put the replies in, then the decode testing when we get decode done.
  43. var tests = []struct {
  44. n string
  45. b []byte
  46. f func(b *bytes.Buffer)
  47. }{
  48. {
  49. "TVersion test with 8192 byte msize and 9P2000",
  50. []byte{19, 0, 0, 0, 100, 0x55, 0xaa, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48},
  51. func(b *bytes.Buffer) { MarshalTversionPkt(b, Tag(0xaa55), 8192, "9P2000") },
  52. },
  53. {
  54. "RVersion test with 8192 byte msize and 9P2000",
  55. []byte{19, 0, 0, 0, 101, 0xaa, 0x55, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48},
  56. func(b *bytes.Buffer) { MarshalRversionPkt(b, Tag(0x55aa), 8192, "9P2000") },
  57. },
  58. /*
  59. {
  60. "Twalk tag 0 fid 0 newfid 1 to null",
  61. []byte{23, 0, 0, 0, 110, 0xaa, 0x55, 0, 0, 0, 0, 1, 0, 0, 0, 1, 0, 4, 0, 110, 117, 108, 108},
  62. func(b *bytes.Buffer) { MarshalTwalkPkt(b, Tag(0x55aa), 0, 1, []string{"null",}) },
  63. },
  64. {
  65. "Flush test with tag 1 and oldtag 2",
  66. []byte{9, 0, 0, 0, 108, 1, 0, 2, 0},
  67. []interface{}{Tflush, Tag(1), Tag(2)},
  68. },
  69. {
  70. "Auth test with tag 0, fid 0,uname rminnich",
  71. []byte{21, 0, 0, 0, 102, 0, 0, 0, 0, 0, 0, 8, 0, 114, 109, 105, 110, 110, 105, 99, 104},
  72. []interface{}{Tauth, Tag(0), FID(0), "rminnich"},
  73. },
  74. {
  75. "Attach test with tag 0, fid 0, afid -1, uname rminnich",
  76. []byte{28, 0, 0, 0, 104, 0, 0, 0, 0, 0, 0, 255, 255, 255, 255, 8, 0, 114, 109, 105, 110, 110, 105, 99, 104, 1, 0, 47},
  77. []interface{}{Tattach, Tag(0), FID(0), NOFID, "rminnich", "/"},
  78. },
  79. {
  80. "Tauth with an rerror of no user required",
  81. //Tauth tag 1 afid 45 uname 'rminnich' nuname 4294967295 aname ''
  82. []byte{23,0,0,0,102,1,0,45,0,0,0,8,0,114,109,105,110,110,105,99,104,0,0},
  83. []interface{}{Tauth, Tag(1), FID(45), "rminnich", ""},
  84. // [39 0 0 0 107 1 0 30 0 110 111 32 97 117 116 104 101 110 116 105 99 97 116 105 111 110 32 114 101 113 117 105 114 101 100 58 32 50 50]
  85. //Rerror tag 1 ename 'no authentication required: 22' ecode 0
  86. },
  87. {
  88. "Tattach from Harvey to ninep: Tattach tag 1 fid 48 afid 4294967295 uname 'rminnich' nuname 4294967295 aname ''",
  89. []byte{27,0,0,0,104,1,0,48,0,0,0,255,255,255,255,8,0,114,109,105,110,110,105,99,104,0,0},
  90. []interface{}{Tattach, Tag(1), FID(48), NOFID, "rminnich", ""},
  91. // 20 0 0 0 105 1 0 128 99 207 44 145 115 221 96 0 0 0 0 0]
  92. // Rattach tag 1 aqid (60dd73 912ccf63 'd')
  93. },
  94. {
  95. "Topen tag 0 fid 1 mode 2",
  96. []byte{12, 0, 0, 0, 112, 0, 0, 1, 0, 0, 0, 2},
  97. []interface{}{Topen, Tag(0), FID(1), Mode(2)},
  98. },
  99. {
  100. "Tread tag 0 fid 1 offset 0 count 8192",
  101. []byte{23, 0, 0, 0, 116, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 32, 0, 0},
  102. []interface{}{Tread, Tag(0), FID(1), Offset(0), Count(8192)},
  103. },
  104. {
  105. "Tstat tag 1 fid 49",
  106. []byte{11, 0, 0, 0, 124, 1, 0, 49, 0, 0, 0},
  107. // Rstat
  108. //
  109. //[84,0,0,0,125,1,0,75,0,73,0,0,0,0,0,0,0,128,99,207,44,145,115,221,96,0,0,0,0,0,253,1,0,128,109,185,47,86,196,66,41,86,0,16,0,0,0,0,0,0,6,0,104,97,114,118,101,121,8,0,114,109,105,110,110,105,99,104,8,0,114,109,105,110,110,105,99,104,4,0,110,111,110,101]
  110. //Rstat tag 1 st ('harvey' 'rminnich' 'rminnich' 'none' q (60dd73 912ccf63 'd') m d775 at 1445968237 mt 1445544644 l 4096 t 0 d 0 ext )
  111. []interface{}{Tstat, Tag(1), FID(49)},
  112. },
  113. {
  114. "Twrite tag 3 fid 139 offset 0 count 3",
  115. []byte{26, 0, 0, 0, 118, 3, 0, 139, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 104, 105, 10},
  116. // rwrite []byte{11,0,0,0,119,3,0,3,0,0,0}
  117. []interface{}{Twrite, Tag(3), FID(139), Offset(0), Count(3), []byte("hi\n")},
  118. },
  119. {
  120. "Tclunk tag 1 fid 49",
  121. []byte{11, 0, 0, 0, 120, 1, 0, 49, 0, 0, 0},
  122. // rclunk 7 0 0 0 121 1 0]
  123. []interface{}{Tclunk, Tag(1), FID(49)},
  124. },
  125. {
  126. "Tremove tag 1 fid 49",
  127. []byte{11, 0, 0, 0, 122, 1, 0, 49, 0, 0, 0},
  128. // rclunk 7 0 0 0 121 1 0]
  129. []interface{}{Tremove, Tag(1), FID(49)},
  130. },
  131. {
  132. "Twstat tag 3 fid 49 ",
  133. //Twstat tag 3 fid 49 st ('' '' '' '' q (ffffffffffffffff ffffffff 'daAltL') m daAltDSPL777 at 4294967295 mt 1445968327 l 18446744073709551615 t 65535 d 4294967295 ext )
  134. []byte{62, 0, 0, 0, 126, 3, 0, 49, 0, 0, 0, 49, 0, 47, 0, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 199, 185, 47, 86, 255, 255, 255, 255, 255, 255, 255, 255, 0, 0, 0, 0, 0, 0, 0, 0},
  135. // Rwstat [11 0 0 0 120 3 0 49 0 0 0]
  136. []interface{}{Twstat, Tag(3), FID(49), &Dir{ /* TODO: remove this size
  137. Size: 47,
  138. Type: math.MaxUint16,
  139. Dev: math.MaxUint32,
  140. Qid: Qid{Type: math.MaxUint8, Version: math.MaxUint32, Path: math.MaxUint64},
  141. Mode: math.MaxUint32,
  142. Atime: 4294967295,
  143. Mtime: 1445968327,
  144. Length: 18446744073709551615,
  145. Name: "",
  146. Uid: "",
  147. Gid: "",
  148. Muid: "",
  149. },
  150. },
  151. },
  152. {
  153. "Tcreate tag 3 fid 74 name 'y' perm 666 mode 0",
  154. []byte{19,0,0,0,114,3,0,74,0,0,0,1,0,121,182,1,0,0,0},
  155. []interface{}{Tcreate, Tag(3), FID(74), "y", Perm(0666), Mode(0)},
  156. /// rcreate [24 0 0 0 115 3 0 0 226 200 71 172 45 166 98 0 0 0 0 0 0 0 0 0]
  157. // Rcreate tag 3 qid (62a62d ac47c8e2 '') iounit 0
  158. },*/
  159. }
  160. for _, v := range tests {
  161. var b bytes.Buffer
  162. v.f(&b)
  163. if !reflect.DeepEqual(v.b, b.Bytes()) {
  164. t.Errorf("Mismatch on %v: Got\n%v[%v], want\n%v[%v]", v.n, b.Bytes(), len(b.Bytes()), v.b, len(v.b))
  165. }
  166. }
  167. }
  168. /*
  169. func testDecode(t *testing.T) {
  170. var tests = []struct {
  171. n string
  172. b []byte
  173. f func(b *bytes.Buffer) error
  174. }{
  175. {
  176. "TVersion test with 8192 byte msize and 9P2000",
  177. []byte{19, 0, 0, 0, 100, 255, 255, 0, 32, 0, 0, 6, 0, 57, 80, 50, 48, 48, 48},
  178. func (b *bytes.Buffer){ MarshalTversionPkt(b, NOTAG, 8192, "9P2000")},
  179. },
  180. for _, v := range tests {
  181. var b bytes.Buffer
  182. v.f(&b)
  183. if !reflect.DeepEqual(v.b, b.Bytes()) {
  184. t.Errorf("Mismatch on %v: Got %v[%v], want %v[%v]", v.n, b.Bytes(), len(b.Bytes()), v.b, len(v.b))
  185. }
  186. }
  187. }
  188. */
  189. func TestTags(t *testing.T) {
  190. c, err := NewClient()
  191. if err != nil {
  192. t.Fatalf("%v", err)
  193. }
  194. _ = c.GetTag()
  195. if len(c.Tags) != NumTags-1 {
  196. t.Errorf("Got one tag, len(tags) is %d, want %d", len(c.Tags), NumTags-1)
  197. }
  198. }
  199. type echo struct {
  200. qids map[FID]QID
  201. }
  202. func (e *echo) Rversion(msize MaxSize, version string) (MaxSize, string, error) {
  203. if version != "9P2000" {
  204. return 0, "", fmt.Errorf("%v not supported; only 9P2000", version)
  205. }
  206. return msize, version, nil
  207. }
  208. func (e *echo) Rattach(FID, FID, string, string) (QID, error) {
  209. return QID{}, nil
  210. }
  211. func (e *echo) Rflush(o Tag) error {
  212. switch o {
  213. case 3:
  214. // Make it fancier, later.
  215. return nil
  216. }
  217. return fmt.Errorf("Rflush: bad Tag %v", o)
  218. }
  219. func (e *echo) Rwalk(fid FID, newfid FID, paths []string) ([]QID, error) {
  220. //fmt.Printf("walk(%d, %d, %d, %v\n", fid, newfid, len(paths), paths)
  221. if len(paths) > 1 {
  222. return nil, nil
  223. }
  224. switch paths[0] {
  225. case "null":
  226. return []QID{{Type: 0, Version: 0, Path: 0xaa55}}, nil
  227. }
  228. return nil, nil
  229. }
  230. func (e *echo) Ropen(fid FID, mode Mode) (QID, MaxSize, error) {
  231. //fmt.Printf("open(%v, %v\n", fid, mode)
  232. return QID{}, 4000, nil
  233. }
  234. func (e *echo) Rcreate(fid FID, name string, perm Perm, mode Mode) (QID, MaxSize, error) {
  235. //fmt.Printf("open(%v, %v\n", fid, mode)
  236. return QID{}, 5000, nil
  237. }
  238. func (e *echo) Rclunk(f FID) error {
  239. switch int(f) {
  240. case 2:
  241. // Make it fancier, later.
  242. if removedFID2 {
  243. return fmt.Errorf("Clunk: bad FID %v", f)
  244. }
  245. return nil
  246. }
  247. //fmt.Printf("clunk(%v)\n", f)
  248. return fmt.Errorf("Clunk: bad FID %v", f)
  249. }
  250. func (e *echo) Rstat(f FID) ([]byte, error) {
  251. switch int(f) {
  252. case 2:
  253. // Make it fancier, later.
  254. return []byte{}, nil
  255. }
  256. //fmt.Printf("stat(%v)\n", f)
  257. return []byte{}, fmt.Errorf("Stat: bad FID %v", f)
  258. }
  259. func (e *echo) Rwstat(f FID, s []byte) error {
  260. switch int(f) {
  261. case 2:
  262. // Make it fancier, later.
  263. return nil
  264. }
  265. //fmt.Printf("stat(%v)\n", f)y
  266. return fmt.Errorf("Wstat: bad FID %v", f)
  267. }
  268. func (e *echo) Rremove(f FID) error {
  269. switch int(f) {
  270. case 2:
  271. // Make it fancier, later.
  272. removedFID2 = true
  273. return nil
  274. }
  275. //fmt.Printf("remove(%v)\n", f)
  276. return fmt.Errorf("Remove: bad FID %v", f)
  277. }
  278. func (e *echo) Rread(f FID, o Offset, c Count) ([]byte, error) {
  279. switch int(f) {
  280. case 2:
  281. // Make it fancier, later.
  282. return []byte("HI"), nil
  283. }
  284. return nil, fmt.Errorf("Read: bad FID %v", f)
  285. }
  286. func (e *echo) Rwrite(f FID, o Offset, b []byte) (Count, error) {
  287. switch int(f) {
  288. case 2:
  289. // Make it fancier, later.
  290. return Count(len(b)), nil
  291. }
  292. return -1, fmt.Errorf("Write: bad FID %v", f)
  293. }
  294. func TestTManyRPCs(t *testing.T) {
  295. p, p2 := net.Pipe()
  296. c, err := NewClient(func(c *Client) error {
  297. c.FromNet, c.ToNet = p, p
  298. return nil
  299. },
  300. func(c *Client) error {
  301. c.Msize = 8192
  302. c.Trace = print // t.Logf
  303. return nil
  304. })
  305. if err != nil {
  306. t.Fatalf("%v", err)
  307. }
  308. t.Logf("Client is %v", c.String())
  309. s, err := NewListener(
  310. func() NineServer { return newEcho() },
  311. func(l *Listener) error {
  312. l.Trace = print
  313. return nil
  314. })
  315. if err != nil {
  316. t.Fatalf("NewServer: want nil, got %v", err)
  317. }
  318. if err := s.Accept(p2); err != nil {
  319. t.Fatalf("Accept: want nil, got %v", err)
  320. }
  321. for i := 0; i < 256*1024; i++ {
  322. _, _, err := c.CallTversion(8000, "9P2000")
  323. if err != nil {
  324. t.Fatalf("CallTversion: want nil, got %v", err)
  325. }
  326. }
  327. }
  328. func TestTMessages(t *testing.T) {
  329. p, p2 := net.Pipe()
  330. c, err := NewClient(func(c *Client) error {
  331. c.FromNet, c.ToNet = p, p
  332. return nil
  333. },
  334. func(c *Client) error {
  335. c.Msize = 8192
  336. c.Trace = print // t.Logf
  337. return nil
  338. })
  339. if err != nil {
  340. t.Fatalf("%v", err)
  341. }
  342. t.Logf("Client is %v", c.String())
  343. s, err := NewListener(
  344. func() NineServer { return newEcho() },
  345. func(l *Listener) error {
  346. l.Trace = print // t.Logf
  347. return nil
  348. })
  349. if err != nil {
  350. t.Fatalf("NewServer: want nil, got %v", err)
  351. }
  352. if err := s.Accept(p2); err != nil {
  353. t.Fatalf("Accept: want nil, got %v", err)
  354. }
  355. // If things really go to hell, change this to true.
  356. if false {
  357. m, v, err := c.CallTversion(8000, "9P2000")
  358. if err != nil {
  359. t.Fatalf("CallTversion: want nil, got %v", err)
  360. }
  361. t.Logf("CallTversion: msize %v version %v", m, v)
  362. t.Fatalf("Quit early")
  363. }
  364. // make sure server rejects requests until the first Tversion
  365. t.Logf("Server is %v", s.String())
  366. if _, err = c.CallTattach(0, 0, "", ""); err == nil {
  367. t.Fatalf("CallTattach: want err, got nil")
  368. }
  369. t.Logf("CallTattach: wanted an error and got %v", err)
  370. m, v, err := c.CallTversion(8000, "9p3000")
  371. if err == nil {
  372. t.Fatalf("CallTversion: want err, got nil")
  373. }
  374. t.Logf("CallTversion: wanted an error and got %v", err)
  375. m, v, err = c.CallTversion(8000, "9P2000")
  376. if err != nil {
  377. t.Fatalf("CallTversion: want nil, got %v", err)
  378. }
  379. t.Logf("CallTversion: msize %v version %v", m, v)
  380. t.Logf("Server is %v", s.String())
  381. a, err := c.CallTattach(0, 0, "", "")
  382. if err != nil {
  383. t.Fatalf("CallTattach: want nil, got %v", err)
  384. }
  385. t.Logf("Attach is %v", a)
  386. w, err := c.CallTwalk(0, 1, []string{"hi", "there"})
  387. // There should never be an error. The indication of a failed walk is that
  388. // the number of QIDS does not match.
  389. if err != nil {
  390. t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want nil, got %v", err)
  391. }
  392. if len(w) != 0 {
  393. t.Fatalf("CallTwalk(0,1,[\"hi\", \"there\"]): want 0 QIDS, got back %d", len(w))
  394. }
  395. t.Logf("Walk is %v", w)
  396. w, err = c.CallTwalk(0, 1, []string{"null"})
  397. if err != nil {
  398. t.Errorf("CallTwalk(0,1,\"null\"): want nil, got err %v", err)
  399. }
  400. if len(w) != 1 {
  401. t.Errorf("CallTwalk(0,1,\"null\"): want 1 QIDs, got back %d", len(w))
  402. }
  403. t.Logf("Walk is %v", w)
  404. q, iounit, err := c.CallTopen(1, 1)
  405. if err != nil {
  406. t.Fatalf("CallTopen: want nil, got %v", err)
  407. }
  408. t.Logf("Open is %v %v", q, iounit)
  409. d, err := c.CallTread(FID(2), 0, 5)
  410. if err != nil {
  411. t.Fatalf("CallTread: want nil, got %v", err)
  412. }
  413. t.Logf("Read is %v", d)
  414. _, err = c.CallTwrite(FID(2), 0, d)
  415. if err != nil {
  416. t.Fatalf("CallTread: want nil, got %v", err)
  417. }
  418. t.Logf("Read is %v", s)
  419. if err := c.CallTclunk(FID(2)); err != nil {
  420. t.Fatalf("CallTclunk: want nil, got %v", err)
  421. }
  422. if err := c.CallTremove(FID(1)); err == nil {
  423. t.Fatalf("CallTremove: want err, got nil")
  424. }
  425. if err := c.CallTremove(FID(2)); err != nil {
  426. t.Fatalf("CallTremove: want nil, got %v", err)
  427. }
  428. if err := c.CallTclunk(FID(2)); err == nil {
  429. t.Fatalf("Callclunk on removed file: want err, got nil")
  430. }
  431. if err := c.CallTremove(FID(1)); err == nil {
  432. t.Fatalf("CallTremove: want err, got nil")
  433. }
  434. st, err := c.CallTstat(FID(2))
  435. if err != nil {
  436. t.Fatalf("CallTstat: want nil, got %v", err)
  437. }
  438. t.Logf("Stat: Got %v", st)
  439. if _, err := c.CallTstat(FID(1)); err == nil {
  440. t.Fatalf("CallTstat: want err, got nil")
  441. }
  442. if err := c.CallTwstat(FID(2), []byte{}); err != nil {
  443. t.Fatalf("CallTwstat: want nil, got %v", err)
  444. }
  445. if err := c.CallTwstat(FID(1), []byte{}); err == nil {
  446. t.Fatalf("CallTwstat: want err, got nil")
  447. }
  448. if err := c.CallTflush(3); err != nil {
  449. t.Fatalf("CallTflush: want nil, got %v", err)
  450. }
  451. if err := c.CallTflush(2); err == nil {
  452. t.Fatalf("CallTflush: want err, got nil")
  453. }
  454. }
  455. func BenchmarkNull(b *testing.B) {
  456. p, p2 := net.Pipe()
  457. c, err := NewClient(func(c *Client) error {
  458. c.FromNet, c.ToNet = p, p
  459. return nil
  460. },
  461. func(c *Client) error {
  462. c.Msize = 8192
  463. return nil
  464. })
  465. if err != nil {
  466. b.Fatalf("%v", err)
  467. }
  468. b.Logf("Client is %v", c.String())
  469. s, err := NewListener(
  470. func() NineServer {
  471. return newEcho()
  472. })
  473. if err != nil {
  474. b.Fatalf("NewServer: want nil, got %v", err)
  475. }
  476. if err := s.Accept(p2); err != nil {
  477. b.Fatalf("Accept: want nil, got %v", err)
  478. }
  479. b.Logf("%d iterations", b.N)
  480. for i := 0; i < b.N; i++ {
  481. if _, err := c.CallTread(FID(2), 0, 5); err != nil {
  482. b.Fatalf("CallTread: want nil, got %v", err)
  483. }
  484. }
  485. }