2 Copyright 2013 Google Inc.
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
8 http://www.apache.org/licenses/LICENSE-2.0
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.
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")
40 func TestHTTPPool(t *testing.T) {
42 beChildForTestHTTPPool()
51 var childAddr []string
52 for i := 0; i < nChild; i++ {
53 childAddr = append(childAddr, pickFreeAddr(t))
58 for i := 0; i < nChild; i++ {
59 cmd := exec.Command(os.Args[0],
60 "--test.run=TestHTTPPool",
62 "--test_peer_addrs="+strings.Join(childAddr, ","),
63 "--test_peer_index="+strconv.Itoa(i),
65 cmds = append(cmds, cmd)
67 if err := cmd.Start(); err != nil {
68 t.Fatal("failed to start child process: ", err)
70 go awaitAddrReady(t, childAddr[i], &wg)
73 for i := 0; i < nChild; i++ {
74 if cmds[i].Process != nil {
75 cmds[i].Process.Kill()
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)...)
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")
91 g := NewGroup("httpPoolTest", 1<<20, getter)
93 for _, key := range testKeys(nGets) {
95 if err := g.Get(nil, key, StringSink(&value)); err != nil {
98 if suffix := ":" + key; !strings.HasSuffix(value, suffix) {
99 t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix)
101 t.Logf("Get key=%q, value=%q (peer:key)", key, value)
105 func testKeys(n int) (keys []string) {
106 keys = make([]string, n)
107 for i := range keys {
108 keys[i] = strconv.Itoa(i)
113 func beChildForTestHTTPPool() {
114 addrs := strings.Split(*peerAddrs, ",")
116 p := NewHTTPPool("http://" + addrs[*peerIndex])
117 p.Set(addrToURL(addrs)...)
119 getter := GetterFunc(func(ctx Context, key string, dest Sink) error {
120 dest.SetString(strconv.Itoa(*peerIndex) + ":" + key)
123 NewGroup("httpPoolTest", 1<<20, getter)
125 log.Fatal(http.ListenAndServe(addrs[*peerIndex], p))
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")
138 return l.Addr().String()
141 func addrToURL(addr []string) []string {
142 url := make([]string, len(addr))
143 for i := range addr {
144 url[i] = "http://" + addr[i]
149 func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) {
151 const max = 1 * time.Second
155 c, err := net.Dial("tcp", addr)
160 delay := time.Duration(tries) * 25 * time.Millisecond