~nskaggs/+junk/xenial-test

« back to all changes in this revision

Viewing changes to src/gopkg.in/natefinch/npipe.v2/npipe_windows_test.go

  • Committer: Nicholas Skaggs
  • Date: 2016-10-24 20:56:05 UTC
  • Revision ID: nicholas.skaggs@canonical.com-20161024205605-z8lta0uvuhtxwzwl
Initi with beta15

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
package npipe
 
2
 
 
3
import (
 
4
        "bufio"
 
5
        "crypto/rand"
 
6
        "fmt"
 
7
        "io"
 
8
        "io/ioutil"
 
9
        "net"
 
10
        "net/rpc"
 
11
        "os"
 
12
        "path/filepath"
 
13
        "sync"
 
14
        "testing"
 
15
        "time"
 
16
)
 
17
 
 
18
const (
 
19
        clientMsg    = "Hi server!\n"
 
20
        serverMsg    = "Hi there, client!\n"
 
21
        fileTemplate = "62DA0493-99A1-4327-B5A8-6C4E4466C3FC.txt"
 
22
)
 
23
 
 
24
// TestBadDial tests that if you dial something other than a valid pipe path, that you get back a
 
25
// PipeError and that you don't accidently create a file on disk (since dial uses OpenFile)
 
26
func TestBadDial(t *testing.T) {
 
27
        fn := filepath.Join("C:\\", fileTemplate)
 
28
        ns := []string{fn, "http://www.google.com", "somethingbadhere"}
 
29
        for _, n := range ns {
 
30
                c, err := Dial(n)
 
31
                if _, ok := err.(PipeError); !ok {
 
32
                        t.Errorf("Dialing '%s' did not result in correct error! Expected PipeError, got '%v'",
 
33
                                n, err)
 
34
                }
 
35
                if c != nil {
 
36
                        t.Errorf("Dialing '%s' returned non-nil connection", n)
 
37
                }
 
38
                if b, _ := exists(n); b {
 
39
                        t.Errorf("Dialing '%s' incorrectly created file on disk", n)
 
40
                }
 
41
        }
 
42
}
 
43
 
 
44
// TestDialExistingFile tests that if you dial with the name of an existing file,
 
45
// that you don't accidentally open the file (since dial uses OpenFile)
 
46
func TestDialExistingFile(t *testing.T) {
 
47
        tempdir := os.TempDir()
 
48
        fn := filepath.Join(tempdir, fileTemplate)
 
49
        if f, err := os.Create(fn); err != nil {
 
50
                t.Fatalf("Unexpected error creating file '%s': '%v'", fn, err)
 
51
        } else {
 
52
                // we don't actually need to write to the file, just need it to exist
 
53
                f.Close()
 
54
                defer os.Remove(fn)
 
55
        }
 
56
        c, err := Dial(fn)
 
57
        if _, ok := err.(PipeError); !ok {
 
58
                t.Errorf("Dialing '%s' did not result in error! Expected PipeError, got '%v'", fn, err)
 
59
        }
 
60
        if c != nil {
 
61
                t.Errorf("Dialing '%s' returned non-nil connection", fn)
 
62
        }
 
63
}
 
64
 
 
65
// TestBadListen tests that if you listen on a bad address, that we get back a PipeError
 
66
func TestBadListen(t *testing.T) {
 
67
        addrs := []string{"not a valid pipe address", `\\127.0.0.1\pipe\TestBadListen`}
 
68
        for _, address := range addrs {
 
69
                ln, err := Listen(address)
 
70
                if _, ok := err.(PipeError); !ok {
 
71
                        t.Errorf("Listening on '%s' did not result in correct error! Expected PipeError, got '%v'",
 
72
                                address, err)
 
73
                }
 
74
                if ln != nil {
 
75
                        t.Errorf("Listening on '%s' returned non-nil listener.", address)
 
76
                }
 
77
        }
 
78
}
 
79
 
 
80
// TestDoubleListen makes sure we can't listen to the same address twice.
 
81
func TestDoubleListen(t *testing.T) {
 
82
        address := `\\.\pipe\TestDoubleListen`
 
83
        ln1, err := Listen(address)
 
84
        if err != nil {
 
85
                t.Fatalf("Listen(%q): %v", address, err)
 
86
        }
 
87
        defer ln1.Close()
 
88
 
 
89
        ln2, err := Listen(address)
 
90
        if err == nil {
 
91
                ln2.Close()
 
92
                t.Fatalf("second Listen on %q succeeded.", address)
 
93
        }
 
94
}
 
95
 
 
96
// TestPipeConnected tests whether we correctly handle clients connecting
 
97
// and then closing the connection between creating and connecting the
 
98
// pipe on the server side.
 
99
func TestPipeConnected(t *testing.T) {
 
100
        address := `\\.\pipe\TestPipeConnected`
 
101
        ln, err := Listen(address)
 
102
        if err != nil {
 
103
                t.Fatalf("Listen(%q): %v", address, err)
 
104
        }
 
105
        defer ln.Close()
 
106
 
 
107
        // Create a client connection and close it immediately.
 
108
        clientConn, err := Dial(address)
 
109
        if err != nil {
 
110
                t.Fatalf("Error from dial: %v", err)
 
111
        }
 
112
        clientConn.Close()
 
113
 
 
114
        content := "test"
 
115
        go func() {
 
116
                // Now create a real connection and send some data.
 
117
                clientConn, err := Dial(address)
 
118
                if err != nil {
 
119
                        t.Fatalf("Error from dial: %v", err)
 
120
                }
 
121
                if _, err := clientConn.Write([]byte(content)); err != nil {
 
122
                        t.Fatalf("Error writing to pipe: %v", err)
 
123
                }
 
124
                clientConn.Close()
 
125
        }()
 
126
 
 
127
        serverConn, err := ln.Accept()
 
128
        if err != nil {
 
129
                t.Fatalf("Error from accept: %v", err)
 
130
        }
 
131
        result, err := ioutil.ReadAll(serverConn)
 
132
        if err != nil {
 
133
                t.Fatalf("Error from ReadAll: %v", err)
 
134
        }
 
135
        if string(result) != content {
 
136
                t.Fatalf("Got %s, expected: %s", string(result), content)
 
137
        }
 
138
        serverConn.Close()
 
139
}
 
140
 
 
141
// TestListenCloseListen tests whether Close() actually closes a named pipe properly.
 
142
func TestListenCloseListen(t *testing.T) {
 
143
        address := `\\.\pipe\TestListenCloseListen`
 
144
        ln1, err := Listen(address)
 
145
        if err != nil {
 
146
                t.Fatalf("Listen(%q): %v", address, err)
 
147
        }
 
148
        ln1.Close()
 
149
 
 
150
        ln2, err := Listen(address)
 
151
        if err != nil {
 
152
                t.Fatalf("second Listen on %q failed.", address)
 
153
        }
 
154
        ln2.Close()
 
155
}
 
156
 
 
157
// TestCloseFileHandles tests that all PipeListener handles are actualy closed after
 
158
// calling Close()
 
159
func TestCloseFileHandles(t *testing.T) {
 
160
        address := `\\.\pipe\TestCloseFileHandles`
 
161
        ln, err := Listen(address)
 
162
        if err != nil {
 
163
                t.Fatalf("Error listening on %q: %v", address, err)
 
164
        }
 
165
        defer ln.Close()
 
166
        server := rpc.NewServer()
 
167
        service := &RPCService{}
 
168
        server.Register(service)
 
169
        go func() {
 
170
                for {
 
171
                        conn, err := ln.Accept()
 
172
                        if err != nil {
 
173
                                // Ignore errors produced by a closed listener.
 
174
                                if err != ErrClosed {
 
175
                                        t.Errorf("ln.Accept(): %v", err.Error())
 
176
                                }
 
177
                                break
 
178
                        }
 
179
                        go server.ServeConn(conn)
 
180
                }
 
181
        }()
 
182
        conn, err := Dial(address)
 
183
        if err != nil {
 
184
                t.Fatalf("Error dialing %q: %v", address, err)
 
185
        }
 
186
        client := rpc.NewClient(conn)
 
187
        defer client.Close()
 
188
        req := "dummy"
 
189
        resp := ""
 
190
        if err = client.Call("RPCService.GetResponse", req, &resp); err != nil {
 
191
                t.Fatalf("Error calling RPCService.GetResponse: %v", err)
 
192
        }
 
193
        if req != resp {
 
194
                t.Fatalf("Unexpected result (expected: %q, got: %q)", req, resp)
 
195
        }
 
196
        ln.Close()
 
197
 
 
198
        if ln.acceptHandle != 0 {
 
199
                t.Fatalf("Failed to close acceptHandle")
 
200
        }
 
201
        if ln.acceptOverlapped.HEvent != 0 {
 
202
                t.Fatalf("Failed to close acceptOverlapped handle")
 
203
        }
 
204
}
 
205
 
 
206
// TestCancelListen tests whether Accept() can be cancelled by closing the listener.
 
207
func TestCancelAccept(t *testing.T) {
 
208
        address := `\\.\pipe\TestCancelListener`
 
209
        ln, err := Listen(address)
 
210
        if err != nil {
 
211
                t.Fatalf("Listen(%q): %v", address, err)
 
212
        }
 
213
 
 
214
        cancelled := make(chan struct{})
 
215
        started := make(chan struct{})
 
216
        go func() {
 
217
                close(started)
 
218
                conn, _ := ln.Accept()
 
219
                if conn != nil {
 
220
                        t.Fatalf("Unexpected incoming connection: %v", conn)
 
221
                        conn.Close()
 
222
                }
 
223
                cancelled <- struct{}{}
 
224
        }()
 
225
        <-started
 
226
        // Close listener after 20ms. This should give the go routine enough time to be actually
 
227
        // waiting for incoming connections inside ln.Accept().
 
228
        time.AfterFunc(20*time.Millisecond, func() {
 
229
                if err := ln.Close(); err != nil {
 
230
                        t.Fatalf("Error closing listener: %v", err)
 
231
                }
 
232
        })
 
233
        // Any Close() should abort the ln.Accept() call within 100ms.
 
234
        // We fail with a timeout otherwise, to avoid blocking forever on a failing test.
 
235
        timeout := time.After(100 * time.Millisecond)
 
236
        select {
 
237
        case <-cancelled:
 
238
                // This is what should happen.
 
239
        case <-timeout:
 
240
                t.Fatal("Timeout trying to cancel accept.")
 
241
        }
 
242
}
 
243
 
 
244
// Test that PipeConn's read deadline works correctly
 
245
func TestReadDeadline(t *testing.T) {
 
246
        address := `\\.\pipe\TestReadDeadline`
 
247
        var wg sync.WaitGroup
 
248
        wg.Add(1)
 
249
 
 
250
        go listenAndWait(address, wg, t)
 
251
        defer wg.Done()
 
252
 
 
253
        c, err := Dial(address)
 
254
        if err != nil {
 
255
                t.Fatalf("Error dialing into pipe: %v", err)
 
256
        }
 
257
        if c == nil {
 
258
                t.Fatal("Unexpected nil connection from Dial")
 
259
        }
 
260
        defer c.Close()
 
261
        deadline := time.Now().Add(time.Millisecond * 50)
 
262
        c.SetReadDeadline(deadline)
 
263
        msg, err := bufio.NewReader(c).ReadString('\n')
 
264
        end := time.Now()
 
265
        if msg != "" {
 
266
                t.Errorf("Pipe read timeout returned a non-empty message: %s", msg)
 
267
        }
 
268
        if err == nil {
 
269
                t.Error("Pipe read timeout returned nil error")
 
270
        } else {
 
271
                pe, ok := err.(PipeError)
 
272
                if !ok {
 
273
                        t.Errorf("Got wrong error returned, expected PipeError, got '%t'", err)
 
274
                }
 
275
                if !pe.Timeout() {
 
276
                        t.Error("Pipe read timeout didn't return an error indicating the timeout")
 
277
                }
 
278
        }
 
279
        checkDeadline(deadline, end, t)
 
280
}
 
281
 
 
282
// listenAndWait simply sets up a pipe listener that does nothing and closes after the waitgroup
 
283
// is done.
 
284
func listenAndWait(address string, wg sync.WaitGroup, t *testing.T) {
 
285
        ln, err := Listen(address)
 
286
        if err != nil {
 
287
                t.Fatalf("Error starting to listen on pipe: %v", err)
 
288
        }
 
289
        if ln == nil {
 
290
                t.Fatal("Got unexpected nil listener")
 
291
        }
 
292
        conn, err := ln.Accept()
 
293
        if err != nil {
 
294
                t.Fatalf("Error accepting connection: %v", err)
 
295
        }
 
296
        if conn == nil {
 
297
                t.Fatal("Got unexpected nil connection")
 
298
        }
 
299
        defer conn.Close()
 
300
        // don't read or write anything
 
301
        wg.Wait()
 
302
}
 
303
 
 
304
// TestWriteDeadline tests that PipeConn's write deadline works correctly
 
305
func TestWriteDeadline(t *testing.T) {
 
306
        address := `\\.\pipe\TestWriteDeadline`
 
307
        var wg sync.WaitGroup
 
308
        wg.Add(1)
 
309
 
 
310
        go listenAndWait(address, wg, t)
 
311
        defer wg.Done()
 
312
        c, err := Dial(address)
 
313
        if err != nil {
 
314
                t.Fatalf("Error dialing into pipe: %v", err)
 
315
        }
 
316
        if c == nil {
 
317
                t.Fatal("Unexpected nil connection from Dial")
 
318
        }
 
319
 
 
320
        // windows pipes have a buffer, so even if we don't read from the pipe,
 
321
        // the write may succeed anyway, so we have to write a whole bunch to
 
322
        // test the time out
 
323
        deadline := time.Now().Add(time.Millisecond * 50)
 
324
        c.SetWriteDeadline(deadline)
 
325
        buffer := make([]byte, 1<<16)
 
326
        if _, err = io.ReadFull(rand.Reader, buffer); err != nil {
 
327
                t.Fatalf("Couldn't generate random buffer: %v", err)
 
328
        }
 
329
        _, err = c.Write(buffer)
 
330
 
 
331
        end := time.Now()
 
332
 
 
333
        if err == nil {
 
334
                t.Error("Pipe write timeout returned nil error")
 
335
        } else {
 
336
                pe, ok := err.(PipeError)
 
337
                if !ok {
 
338
                        t.Errorf("Got wrong error returned, expected PipeError, got '%t'", err)
 
339
                }
 
340
                if !pe.Timeout() {
 
341
                        t.Error("Pipe write timeout didn't return an error indicating the timeout")
 
342
                }
 
343
        }
 
344
        checkDeadline(deadline, end, t)
 
345
}
 
346
 
 
347
// TestDialTimeout tests that the DialTimeout function will actually timeout correctly
 
348
func TestDialTimeout(t *testing.T) {
 
349
        timeout := time.Millisecond * 150
 
350
        deadline := time.Now().Add(timeout)
 
351
        c, err := DialTimeout(`\\.\pipe\TestDialTimeout`, timeout)
 
352
        end := time.Now()
 
353
        if c != nil {
 
354
                t.Errorf("DialTimeout returned non-nil connection: %v", c)
 
355
        }
 
356
        if err == nil {
 
357
                t.Error("DialTimeout returned nil error after timeout")
 
358
        } else {
 
359
                pe, ok := err.(PipeError)
 
360
                if !ok {
 
361
                        t.Errorf("Got wrong error returned, expected PipeError, got '%t'", err)
 
362
                }
 
363
                if !pe.Timeout() {
 
364
                        t.Error("Dial timeout didn't return an error indicating the timeout")
 
365
                }
 
366
        }
 
367
        checkDeadline(deadline, end, t)
 
368
}
 
369
 
 
370
// TestDialNoTimeout tests that the DialTimeout function will properly wait for the pipe and
 
371
// connect when it is available
 
372
func TestDialNoTimeout(t *testing.T) {
 
373
        timeout := time.Millisecond * 500
 
374
        address := `\\.\pipe\TestDialNoTimeout`
 
375
        go func() {
 
376
                <-time.After(50 * time.Millisecond)
 
377
                listenAndClose(address, t)
 
378
        }()
 
379
 
 
380
        deadline := time.Now().Add(timeout)
 
381
        c, err := DialTimeout(address, timeout)
 
382
        end := time.Now()
 
383
 
 
384
        if c == nil {
 
385
                t.Error("DialTimeout returned unexpected nil connection")
 
386
        }
 
387
        if err != nil {
 
388
                t.Error("DialTimeout returned unexpected non-nil error: ", err)
 
389
        }
 
390
        if end.After(deadline) {
 
391
                t.Fatalf("Ended %v after deadline", end.Sub(deadline))
 
392
        }
 
393
}
 
394
 
 
395
// TestDial tests that you can dial before a pipe is available,
 
396
// and that it'll pick up the pipe once it's ready
 
397
func TestDial(t *testing.T) {
 
398
        address := `\\.\pipe\TestDial`
 
399
        var wg sync.WaitGroup
 
400
        wg.Add(1)
 
401
        go func() {
 
402
                wg.Done()
 
403
                conn, err := Dial(address)
 
404
                if err != nil {
 
405
                        t.Fatalf("Got unexpected error from Dial: %v", err)
 
406
                }
 
407
                if conn == nil {
 
408
                        t.Fatal("Got unexpected nil connection from Dial")
 
409
                }
 
410
                if err := conn.Close(); err != nil {
 
411
                        t.Fatalf("Got unexpected error from conection.Close(): %v", err)
 
412
                }
 
413
        }()
 
414
 
 
415
        wg.Wait()
 
416
        <-time.After(50 * time.Millisecond)
 
417
        listenAndClose(address, t)
 
418
}
 
419
 
 
420
type RPCService struct{}
 
421
 
 
422
func (s *RPCService) GetResponse(request string, response *string) error {
 
423
        *response = request
 
424
        return nil
 
425
}
 
426
 
 
427
// TestGoRPC tests that you can run go RPC over the pipe,
 
428
// and that overlapping bi-directional communication is working
 
429
// (write while a blocking read is in progress).
 
430
func TestGoRPC(t *testing.T) {
 
431
        address := `\\.\pipe\TestRPC`
 
432
        ln, err := Listen(address)
 
433
        if err != nil {
 
434
                t.Fatalf("Error listening on %q: %v", address, err)
 
435
        }
 
436
        waitExit := make(chan struct{})
 
437
        defer func() {
 
438
                ln.Close()
 
439
                <-waitExit
 
440
        }()
 
441
 
 
442
        go func() {
 
443
                server := rpc.NewServer()
 
444
                server.Register(&RPCService{})
 
445
                for {
 
446
                        conn, err := ln.Accept()
 
447
                        if err != nil {
 
448
                                // Ignore errors produced by a closed listener.
 
449
                                if err != ErrClosed {
 
450
                                        t.Errorf("ln.Accept(): %v", err.Error())
 
451
                                }
 
452
                                break
 
453
                        }
 
454
                        go server.ServeConn(conn)
 
455
                }
 
456
                close(waitExit)
 
457
        }()
 
458
        conn, err := Dial(address)
 
459
        if err != nil {
 
460
                t.Fatalf("Error dialing %q: %v", address, err)
 
461
        }
 
462
        client := rpc.NewClient(conn)
 
463
        defer client.Close()
 
464
        req := "dummy"
 
465
        var resp string
 
466
        if err = client.Call("RPCService.GetResponse", req, &resp); err != nil {
 
467
                t.Fatalf("Error calling RPCService.GetResponse: %v", err)
 
468
        }
 
469
        if req != resp {
 
470
                t.Fatalf("Unexpected result (expected: %q, got: %q)", req, resp)
 
471
        }
 
472
}
 
473
 
 
474
// listenAndClose is a helper method to just listen on a pipe and close as soon as someone connects.
 
475
func listenAndClose(address string, t *testing.T) {
 
476
        ln, err := Listen(address)
 
477
        if err != nil {
 
478
                t.Fatalf("Got unexpected error from Listen: %v", err)
 
479
        }
 
480
        if ln == nil {
 
481
                t.Fatal("Got unexpected nil listener from Listen")
 
482
        }
 
483
        conn, err := ln.Accept()
 
484
        if err != nil {
 
485
                t.Fatalf("Got unexpected error from Accept: %v", err)
 
486
        }
 
487
        if conn == nil {
 
488
                t.Fatal("Got unexpected nil connection from Accept")
 
489
        }
 
490
        if err := conn.Close(); err != nil {
 
491
                t.Fatalf("Got unexpected error from conection.Close(): %v", err)
 
492
        }
 
493
}
 
494
 
 
495
// TestCommonUseCase is a full run-through of the most common use case, where you create a listener
 
496
// and then dial into it with several clients in succession
 
497
func TestCommonUseCase(t *testing.T) {
 
498
        addrs := []string{`\\.\pipe\TestCommonUseCase`, `\\127.0.0.1\pipe\TestCommonUseCase`}
 
499
        // always listen on the . version, since IP won't work for listening
 
500
        ln, err := Listen(addrs[0])
 
501
        if err != nil {
 
502
                t.Fatalf("Listen(%q) failed: %v", addrs[0], err)
 
503
        }
 
504
        defer ln.Close()
 
505
 
 
506
        for _, address := range addrs {
 
507
                convos := 5
 
508
                clients := 10
 
509
 
 
510
                wg := sync.WaitGroup{}
 
511
 
 
512
                for x := 0; x < clients; x++ {
 
513
                        wg.Add(1)
 
514
                        go startClient(address, &wg, convos, t)
 
515
                }
 
516
 
 
517
                go startServer(ln, convos, t)
 
518
 
 
519
                select {
 
520
                case <-wait(&wg):
 
521
                // good!
 
522
                case <-time.After(time.Second):
 
523
                        t.Fatal("Failed to finish after a reasonable timeout")
 
524
                }
 
525
        }
 
526
}
 
527
 
 
528
// wait simply waits on the waitgroup and closes the returned channel when done.
 
529
func wait(wg *sync.WaitGroup) <-chan struct{} {
 
530
        done := make(chan struct{})
 
531
        go func() {
 
532
                wg.Wait()
 
533
                close(done)
 
534
        }()
 
535
        return done
 
536
}
 
537
 
 
538
// startServer accepts connections and spawns goroutines to handle them
 
539
func startServer(ln *PipeListener, iter int, t *testing.T) {
 
540
        for {
 
541
                conn, err := ln.Accept()
 
542
                if err == ErrClosed {
 
543
                        return
 
544
                }
 
545
                if err != nil {
 
546
                        t.Fatalf("Error accepting connection: %v", err)
 
547
                }
 
548
                go handleConnection(conn, iter, t)
 
549
        }
 
550
}
 
551
 
 
552
// handleConnection is the goroutine that handles connections on the server side
 
553
// it expects to read a message and then write a message, convos times, before exiting.
 
554
func handleConnection(conn net.Conn, convos int, t *testing.T) {
 
555
        r := bufio.NewReader(conn)
 
556
        for x := 0; x < convos; x++ {
 
557
                msg, err := r.ReadString('\n')
 
558
                if err != nil {
 
559
                        t.Fatalf("Error reading from server connection: %v", err)
 
560
                }
 
561
                if msg != clientMsg {
 
562
                        t.Fatalf("Read incorrect message from client. Expected '%s', got '%s'", clientMsg, msg)
 
563
                }
 
564
 
 
565
                if _, err := fmt.Fprint(conn, serverMsg); err != nil {
 
566
                        t.Fatalf("Error on server writing to pipe: %v", err)
 
567
                }
 
568
        }
 
569
        if err := conn.Close(); err != nil {
 
570
                t.Fatalf("Error closing server side of connection: %v", err)
 
571
        }
 
572
}
 
573
 
 
574
// startClient waits on a pipe at the given address. It expects to write a message and then
 
575
// read a message from the pipe, convos times, and then sends a message on the done
 
576
// channel
 
577
func startClient(address string, wg *sync.WaitGroup, convos int, t *testing.T) {
 
578
        defer wg.Done()
 
579
        c := make(chan *PipeConn)
 
580
        go asyncdial(address, c, t)
 
581
 
 
582
        var conn *PipeConn
 
583
        select {
 
584
        case conn = <-c:
 
585
        case <-time.After(time.Second):
 
586
                // Yes this is a long timeout, but sometimes it really does take a long time.
 
587
                t.Fatalf("Client timed out waiting for dial to resolve")
 
588
        }
 
589
        r := bufio.NewReader(conn)
 
590
        for x := 0; x < convos; x++ {
 
591
                if _, err := fmt.Fprint(conn, clientMsg); err != nil {
 
592
                        t.Fatalf("Error on client writing to pipe: %v", err)
 
593
                }
 
594
 
 
595
                msg, err := r.ReadString('\n')
 
596
                if err != nil {
 
597
                        t.Fatalf("Error reading from client connection: %v", err)
 
598
                }
 
599
                if msg != serverMsg {
 
600
                        t.Fatalf("Read incorrect message from server. Expected '%s', got '%s'", serverMsg, msg)
 
601
                }
 
602
        }
 
603
 
 
604
        if err := conn.Close(); err != nil {
 
605
                t.Fatalf("Error closing client side of pipe %v", err)
 
606
        }
 
607
}
 
608
 
 
609
// asyncdial is a helper that dials and returns the connection on the given channel.
 
610
// this is useful for being able to give dial a timeout
 
611
func asyncdial(address string, c chan *PipeConn, t *testing.T) {
 
612
        conn, err := Dial(address)
 
613
        if err != nil {
 
614
                t.Fatalf("Error from dial: %v", err)
 
615
        }
 
616
        c <- conn
 
617
}
 
618
 
 
619
// exists is a simple helper function to detect if a file exists on disk
 
620
func exists(path string) (bool, error) {
 
621
        _, err := os.Stat(path)
 
622
        if err == nil {
 
623
                return true, nil
 
624
        }
 
625
        if os.IsNotExist(err) {
 
626
                return false, nil
 
627
        }
 
628
        return false, err
 
629
}
 
630
 
 
631
func checkDeadline(deadline, end time.Time, t *testing.T) {
 
632
        if end.Before(deadline) {
 
633
                t.Fatalf("Ended %v before deadline", deadline.Sub(end))
 
634
        }
 
635
        diff := end.Sub(deadline)
 
636
 
 
637
        // we need a huge fudge factor here because Windows has really poor
 
638
        // resolution for timeouts, and in practice, the timeout can be 400ms or
 
639
        // more after the expected timeout.
 
640
        if diff > 500*time.Millisecond {
 
641
                t.Fatalf("Ended significantly (%v) after deadline", diff)
 
642
        }
 
643
}