OSDN Git Service

Hulk did something
[bytom/vapor.git] / vendor / github.com / golang / groupcache / http_test.go
1 /*
2 Copyright 2013 Google Inc.
3
4 Licensed under the Apache License, Version 2.0 (the "License");
5 you may not use this file except in compliance with the License.
6 You may obtain a copy of the License at
7
8      http://www.apache.org/licenses/LICENSE-2.0
9
10 Unless required by applicable law or agreed to in writing, software
11 distributed under the License is distributed on an "AS IS" BASIS,
12 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 See the License for the specific language governing permissions and
14 limitations under the License.
15 */
16
17 package groupcache
18
19 import (
20         "errors"
21         "flag"
22         "log"
23         "net"
24         "net/http"
25         "os"
26         "os/exec"
27         "strconv"
28         "strings"
29         "sync"
30         "testing"
31         "time"
32 )
33
34 var (
35         peerAddrs = flag.String("test_peer_addrs", "", "Comma-separated list of peer addresses; used by TestHTTPPool")
36         peerIndex = flag.Int("test_peer_index", -1, "Index of which peer this child is; used by TestHTTPPool")
37         peerChild = flag.Bool("test_peer_child", false, "True if running as a child process; used by TestHTTPPool")
38 )
39
40 func TestHTTPPool(t *testing.T) {
41         if *peerChild {
42                 beChildForTestHTTPPool()
43                 os.Exit(0)
44         }
45
46         const (
47                 nChild = 4
48                 nGets  = 100
49         )
50
51         var childAddr []string
52         for i := 0; i < nChild; i++ {
53                 childAddr = append(childAddr, pickFreeAddr(t))
54         }
55
56         var cmds []*exec.Cmd
57         var wg sync.WaitGroup
58         for i := 0; i < nChild; i++ {
59                 cmd := exec.Command(os.Args[0],
60                         "--test.run=TestHTTPPool",
61                         "--test_peer_child",
62                         "--test_peer_addrs="+strings.Join(childAddr, ","),
63                         "--test_peer_index="+strconv.Itoa(i),
64                 )
65                 cmds = append(cmds, cmd)
66                 wg.Add(1)
67                 if err := cmd.Start(); err != nil {
68                         t.Fatal("failed to start child process: ", err)
69                 }
70                 go awaitAddrReady(t, childAddr[i], &wg)
71         }
72         defer func() {
73                 for i := 0; i < nChild; i++ {
74                         if cmds[i].Process != nil {
75                                 cmds[i].Process.Kill()
76                         }
77                 }
78         }()
79         wg.Wait()
80
81         // Use a dummy self address so that we don't handle gets in-process.
82         p := NewHTTPPool("should-be-ignored")
83         p.Set(addrToURL(childAddr)...)
84
85         // Dummy getter function. Gets should go to children only.
86         // The only time this process will handle a get is when the
87         // children can't be contacted for some reason.
88         getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
89                 return errors.New("parent getter called; something's wrong")
90         })
91         g := NewGroup("httpPoolTest", 1<<20, getter)
92
93         for _, key := range testKeys(nGets) {
94                 var value string
95                 if err := g.Get(nil, key, StringSink(&value)); err != nil {
96                         t.Fatal(err)
97                 }
98                 if suffix := ":" + key; !strings.HasSuffix(value, suffix) {
99                         t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix)
100                 }
101                 t.Logf("Get key=%q, value=%q (peer:key)", key, value)
102         }
103 }
104
105 func testKeys(n int) (keys []string) {
106         keys = make([]string, n)
107         for i := range keys {
108                 keys[i] = strconv.Itoa(i)
109         }
110         return
111 }
112
113 func beChildForTestHTTPPool() {
114         addrs := strings.Split(*peerAddrs, ",")
115
116         p := NewHTTPPool("http://" + addrs[*peerIndex])
117         p.Set(addrToURL(addrs)...)
118
119         getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
120                 dest.SetString(strconv.Itoa(*peerIndex) + ":" + key)
121                 return nil
122         })
123         NewGroup("httpPoolTest", 1<<20, getter)
124
125         log.Fatal(http.ListenAndServe(addrs[*peerIndex], p))
126 }
127
128 // This is racy. Another process could swoop in and steal the port between the
129 // call to this function and the next listen call. Should be okay though.
130 // The proper way would be to pass the l.File() as ExtraFiles to the child
131 // process, and then close your copy once the child starts.
132 func pickFreeAddr(t *testing.T) string {
133         l, err := net.Listen("tcp", "127.0.0.1:0")
134         if err != nil {
135                 t.Fatal(err)
136         }
137         defer l.Close()
138         return l.Addr().String()
139 }
140
141 func addrToURL(addr []string) []string {
142         url := make([]string, len(addr))
143         for i := range addr {
144                 url[i] = "http://" + addr[i]
145         }
146         return url
147 }
148
149 func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) {
150         defer wg.Done()
151         const max = 1 * time.Second
152         tries := 0
153         for {
154                 tries++
155                 c, err := net.Dial("tcp", addr)
156                 if err == nil {
157                         c.Close()
158                         return
159                 }
160                 delay := time.Duration(tries) * 25 * time.Millisecond
161                 if delay > max {
162                         delay = max
163                 }
164                 time.Sleep(delay)
165         }
166 }