| Index: http_test.go |
| diff --git a/http_test.go b/http_test.go |
| new file mode 100644 |
| index 0000000000000000000000000000000000000000..df09608e9be37f0c1ab4616738f05c1aa89a7299 |
| --- /dev/null |
| +++ b/http_test.go |
| @@ -0,0 +1,162 @@ |
| +/* |
| +Copyright 2013 Google Inc. |
| + |
| +Licensed under the Apache License, Version 2.0 (the "License"); |
| +you may not use this file except in compliance with the License. |
| +You may obtain a copy of the License at |
| + |
| + http://www.apache.org/licenses/LICENSE-2.0 |
| + |
| +Unless required by applicable law or agreed to in writing, software |
| +distributed under the License is distributed on an "AS IS" BASIS, |
| +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| +See the License for the specific language governing permissions and |
| +limitations under the License. |
| +*/ |
| + |
| +package groupcache |
| + |
| +import ( |
| + "errors" |
| + "flag" |
| + "log" |
| + "net" |
| + "net/http" |
| + "os" |
| + "os/exec" |
| + "strconv" |
| + "strings" |
| + "sync" |
| + "testing" |
| + "time" |
| +) |
| + |
| +var ( |
| + peerAddrs = flag.String("test_peer_addrs", "", "Comma-separated list of peer addresses; used by TestHTTPPool") |
| + peerIndex = flag.Int("test_peer_index", -1, "Index of which peer this child is; used by TestHTTPPool") |
| + peerChild = flag.Bool("test_peer_child", false, "True if running as a child process; used by TestHTTPPool") |
| +) |
| + |
| +func TestHTTPPool(t *testing.T) { |
| + if *peerChild { |
| + beChildForTestHTTPPool() |
| + os.Exit(0) |
| + } |
| + |
| + const ( |
| + nChild = 4 |
| + nGets = 100 |
| + ) |
| + |
| + var childAddr []string |
| + for i := 0; i < nChild; i++ { |
| + childAddr = append(childAddr, testChildAddr(t)) |
| + } |
| + |
| + var cmds []*exec.Cmd |
| + var wg sync.WaitGroup |
| + for i := 0; i < nChild; i++ { |
| + cmd := exec.Command(os.Args[0], |
| + "--test.run=TestHTTPPool", |
| + "--test_peer_child", |
| + "--test_peer_addrs="+strings.Join(childAddr, ","), |
| + "--test_peer_index="+strconv.Itoa(i), |
| + ) |
| + cmds = append(cmds, cmd) |
| + wg.Add(1) |
| + if err := cmd.Start(); err != nil { |
| + t.Fatal("failed to start child process: ", err) |
| + } |
| + go awaitAddrReady(t, childAddr[i], &wg) |
| bradfitz 2013/07/24 04:53:06 defer cmd.Process.Kill() so if we add more tests adg 2013/07/24 04:56:51 I do that two lines from here bradfitz 2013/07/24 04:58:14 oh hah. I'm sleepy. but my way is 7x shorter. |
| + } |
| + defer func() { |
| + for i := 0; i < nChild; i++ { |
| + if cmds[i].Process != nil { |
| + cmds[i].Process.Kill() |
| + } |
| + } |
| + }() |
| + wg.Wait() |
| + |
| + // Use a dummy self address so that we don't handle gets in-process. |
| + p := NewHTTPPool("should-be-ignored") |
| + p.Set(addrToURL(childAddr)...) |
| + |
| + // Dummy getter function. Gets should go to children only. |
| + // The only time this process will handle a get is when the |
| + // children can't be contacted for seome reason. |
| + getter := GetterFunc(func(ctx Context, key string, dest Sink) error { |
| + return errors.New("parent getter called; something's wrong") |
| + }) |
| + g := NewGroup("httpPoolTest", 1<<20, getter) |
| + |
| + for _, key := range testKeys(nGets) { |
| + var value string |
| + if err := g.Get(nil, key, StringSink(&value)); err != nil { |
| + t.Fatal(err) |
| + } |
| + if suffix := ":" + key; !strings.HasSuffix(value, suffix) { |
| + t.Errorf("Get(%q) = %q, want value ending in %q", key, value, suffix) |
| + } |
| + t.Logf("Get key=%q, value=%q (peer:key)", key, value) |
| + } |
| +} |
| + |
| +func testKeys(n int) (keys []string) { |
| + keys = make([]string, n) |
| + for i := range keys { |
| + keys[i] = strconv.Itoa(i) |
| + } |
| + return |
| +} |
| + |
| +func beChildForTestHTTPPool() { |
| + addrs := strings.Split(*peerAddrs, ",") |
| + |
| + p := NewHTTPPool("http://" + addrs[*peerIndex]) |
| + p.Set(addrToURL(addrs)...) |
| + |
| + getter := GetterFunc(func(ctx Context, key string, dest Sink) error { |
| + dest.SetString(strconv.Itoa(*peerIndex) + ":" + key) |
| + return nil |
| + }) |
| + NewGroup("httpPoolTest", 1<<20, getter) |
| + |
| + log.Fatal(http.ListenAndServe(addrs[*peerIndex], p)) |
| +} |
| + |
| +func testChildAddr(t *testing.T) string { |
| bradfitz 2013/07/24 04:53:06 this is racy. at least comment that it is. the pr adg 2013/07/24 04:56:51 Done. |
| + l, err := net.Listen("tcp", "127.0.0.1:0") |
| + if err != nil { |
| + t.Fatal(err) |
| + } |
| + defer l.Close() |
| + return l.Addr().String() |
| +} |
| + |
| +func addrToURL(addr []string) []string { |
| + url := make([]string, len(addr)) |
| + for i := range addr { |
| + url[i] = "http://" + addr[i] |
| + } |
| + return url |
| +} |
| + |
| +func awaitAddrReady(t *testing.T, addr string, wg *sync.WaitGroup) { |
| + defer wg.Done() |
| + const max = 1 * time.Second |
| + tries := 0 |
| + for { |
| + tries++ |
| + c, err := net.Dial("tcp", addr) |
| + if err == nil { |
| + c.Close() |
| + return |
| + } |
| + delay := time.Duration(tries) * 25 * time.Millisecond |
| + if delay > max { |
| + delay = max |
| + } |
| + time.Sleep(delay) |
| + } |
| +} |