1// Copyright 2015 Keybase, Inc. All rights reserved. Use of 2// this source code is governed by the included BSD license. 3 4// +build windows 5 6package libkb 7 8import ( 9 "bufio" 10 "errors" 11 "fmt" 12 "os" 13 "os/exec" 14 "path/filepath" 15 "sync" 16 "testing" 17 "time" 18) 19 20func setupTest(t *testing.T, nm string) *TestContext { 21 tc := SetupTest(t, nm, 1) 22 tc.SetRuntimeDir(filepath.Join(tc.Tp.Home, "socket_windows_test")) 23 if err := tc.G.ConfigureSocketInfo(); err != nil { 24 t.Fatal(err) 25 } 26 return &tc 27} 28 29// It would be better to test across process boundaries, but this is better 30// than nothing: across gofuncs. We start a server func, then send it a string, 31// then synchronize with the server func. 32// 33// Another property of named pipes that is NOT tested here is security: 34// only processes in the same user account are supposed to be able to 35// open each other's named pipes. 36func TestWindowsNamedPipe(t *testing.T) { 37 tc := setupTest(t, "socket_windows_test") 38 defer tc.Cleanup() 39 40 listenSocket, err := NewSocket(tc.G) 41 if err != nil { 42 t.Fatal(err) 43 } 44 45 l, err := listenSocket.BindToSocket() 46 if err != nil { 47 t.Fatal(err) 48 } 49 50 // Do the server listening in a separate gofunc, which we synchronize 51 // with later after it has gotten a string 52 var wg sync.WaitGroup 53 wg.Add(1) 54 go func() { 55 defer wg.Done() 56 conn, err := l.Accept() 57 if err != nil { 58 t.Fatal(err) 59 } 60 answer, err := bufio.NewReader(conn).ReadString('\n') 61 if err != nil { 62 t.Fatal(err) 63 } 64 if answer != "Hi server!\n" { 65 t.Fatalf("Bad response over pipe: -%s-", answer) 66 } 67 }() 68 69 sendSocket, err := NewSocket(tc.G) 70 namedPipeClient(sendSocket, t) 71 wg.Wait() 72} 73 74// Dial the server over the pipe and send a string 75func namedPipeClient(sendSocket Socket, t *testing.T) { 76 conn, err := sendSocket.DialSocket() 77 if err != nil { 78 t.Fatal(err) 79 } 80 if _, err := fmt.Fprintln(conn, "Hi server!"); err != nil { 81 t.Fatal(err) 82 } 83} 84 85func TestWindowsPipeOwner(t *testing.T) { 86 87 if os.Getenv("JENKINS_URL") != "" { 88 t.Skip("Skipping pipeowner test - doesn't work on CI, works locally") 89 } 90 91 tc := setupTest(t, "socket_windows_test") 92 defer tc.Cleanup() 93 94 testPipeName := "\\\\.\\pipe\\kbservice\\test_pipe" 95 serverCmd := exec.Command("go", "run", "testfixtures\\kb_pipetest_server\\main.go", testPipeName) 96 err := serverCmd.Start() 97 if err != nil { 98 t.Fatal(err) 99 } 100 defer serverCmd.Process.Kill() 101 102 for i := 0; i < 20; i++ { 103 // Give the server time to open the pipe 104 time.Sleep(500 * time.Millisecond) 105 106 // Test existing pipe 107 owner, err := IsPipeowner(tc.G.Log, testPipeName) 108 if err != nil { 109 if i < 19 { 110 continue 111 } 112 t.Fatal(err) 113 } 114 if !owner.IsOwner { 115 t.Fatal(errors.New("Expected true getting owner of test pipe")) 116 } 117 } 118 119 // Test nonexisting 120 owner, err := IsPipeowner(tc.G.Log, testPipeName+"_nonexistent") 121 if err == nil { 122 t.Fatal(errors.New("Expected error getting owner of nonexistent pipe")) 123 } 124 if owner.IsOwner { 125 t.Fatal(errors.New("Expected false getting owner of nonexistent pipe")) 126 } 127} 128