github.com/insionng/yougam@v0.0.0-20170714101924-2bc18d833463/libraries/golang/groupcache/http_test.go (about)

     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  }