...

Source file src/github.com/go-kit/kit/sd/etcd/integration_test.go

Documentation: github.com/go-kit/kit/sd/etcd

     1  //go:build flaky_integration
     2  // +build flaky_integration
     3  
     4  package etcd
     5  
     6  import (
     7  	"context"
     8  	"io"
     9  	"os"
    10  	"testing"
    11  	"time"
    12  
    13  	"github.com/go-kit/kit/endpoint"
    14  	"github.com/go-kit/kit/sd"
    15  	"github.com/go-kit/log"
    16  )
    17  
    18  // Package sd/etcd provides a wrapper around the etcd key/value store. This
    19  // example assumes the user has an instance of etcd installed and running
    20  // locally on port 2379.
    21  func TestIntegration(t *testing.T) {
    22  	addr := os.Getenv("ETCD_ADDR")
    23  	if addr == "" {
    24  		t.Skip("ETCD_ADDR not set; skipping integration test")
    25  	}
    26  
    27  	var (
    28  		prefix   = "/services/foosvc/" // known at compile time
    29  		instance = "1.2.3.4:8080"      // taken from runtime or platform, somehow
    30  		key      = prefix + instance
    31  		value    = "http://" + instance // based on our transport
    32  	)
    33  
    34  	client, err := NewClient(context.Background(), []string{addr}, ClientOptions{
    35  		DialTimeout:             2 * time.Second,
    36  		DialKeepAlive:           2 * time.Second,
    37  		HeaderTimeoutPerRequest: 2 * time.Second,
    38  	})
    39  	if err != nil {
    40  		t.Fatalf("NewClient(%q): %v", addr, err)
    41  	}
    42  
    43  	// Verify test data is initially empty.
    44  	entries, err := client.GetEntries(key)
    45  	if err == nil {
    46  		t.Fatalf("GetEntries(%q): expected error, got none", key)
    47  	}
    48  	t.Logf("GetEntries(%q): %v (OK)", key, err)
    49  
    50  	// Instantiate a new Registrar, passing in test data.
    51  	registrar := NewRegistrar(client, Service{
    52  		Key:   key,
    53  		Value: value,
    54  	}, log.With(log.NewLogfmtLogger(os.Stderr), "component", "registrar"))
    55  
    56  	// Register our instance.
    57  	registrar.Register()
    58  	t.Logf("Registered")
    59  
    60  	// Retrieve entries from etcd manually.
    61  	entries, err = client.GetEntries(key)
    62  	if err != nil {
    63  		t.Fatalf("client.GetEntries(%q): %v", key, err)
    64  	}
    65  	if want, have := 1, len(entries); want != have {
    66  		t.Fatalf("client.GetEntries(%q): want %d, have %d", key, want, have)
    67  	}
    68  	if want, have := value, entries[0]; want != have {
    69  		t.Fatalf("want %q, have %q", want, have)
    70  	}
    71  
    72  	instancer, err := NewInstancer(
    73  		client,
    74  		prefix,
    75  		log.With(log.NewLogfmtLogger(os.Stderr), "component", "instancer"),
    76  	)
    77  	if err != nil {
    78  		t.Fatalf("NewInstancer: %v", err)
    79  	}
    80  	endpointer := sd.NewEndpointer(
    81  		instancer,
    82  		func(string) (endpoint.Endpoint, io.Closer, error) { return endpoint.Nop, nil, nil },
    83  		log.With(log.NewLogfmtLogger(os.Stderr), "component", "instancer"),
    84  	)
    85  	t.Logf("Constructed Endpointer OK")
    86  
    87  	if !within(time.Second, func() bool {
    88  		endpoints, err := endpointer.Endpoints()
    89  		return err == nil && len(endpoints) == 1
    90  	}) {
    91  		t.Fatalf("Endpointer didn't see Register in time")
    92  	}
    93  	t.Logf("Endpointer saw Register OK")
    94  
    95  	// Deregister first instance of test data.
    96  	registrar.Deregister()
    97  	t.Logf("Deregistered")
    98  
    99  	// Check it was deregistered.
   100  	if !within(time.Second, func() bool {
   101  		endpoints, err := endpointer.Endpoints()
   102  		t.Logf("Checking Deregister: len(endpoints) = %d, err = %v", len(endpoints), err)
   103  		return err == nil && len(endpoints) == 0
   104  	}) {
   105  		t.Fatalf("Endpointer didn't see Deregister in time")
   106  	}
   107  
   108  	// Verify test data no longer exists in etcd.
   109  	_, err = client.GetEntries(key)
   110  	if err == nil {
   111  		t.Fatalf("GetEntries(%q): expected error, got none", key)
   112  	}
   113  	t.Logf("GetEntries(%q): %v (OK)", key, err)
   114  }
   115  
   116  func within(d time.Duration, f func() bool) bool {
   117  	deadline := time.Now().Add(d)
   118  	for time.Now().Before(deadline) {
   119  		if f() {
   120  			return true
   121  		}
   122  		time.Sleep(d / 10)
   123  	}
   124  	return false
   125  }
   126  

View as plain text