mirror of
https://github.com/status-im/consul.git
synced 2025-01-09 21:35:52 +00:00
8455077e5d
This is necessary as consul-api's tests require a real consul instance to be running. We can't directly import an agent to fire up an instance, due to the way this would create an import cycle. These tests instead will start a consul instance using the binary in $PATH (if it exists).
226 lines
4.4 KiB
Go
226 lines
4.4 KiB
Go
package api
|
|
|
|
import (
|
|
crand "crypto/rand"
|
|
"fmt"
|
|
"io/ioutil"
|
|
"net/http"
|
|
"os"
|
|
"os/exec"
|
|
"testing"
|
|
"time"
|
|
)
|
|
|
|
var consulConfig = `{
|
|
"ports": {
|
|
"http": 18800
|
|
},
|
|
"data_dir": "%s",
|
|
"bootstrap": true,
|
|
"server": true
|
|
}`
|
|
|
|
type testServer struct {
|
|
pid int
|
|
dataDir string
|
|
configFile string
|
|
}
|
|
|
|
func (s *testServer) stop() {
|
|
defer os.RemoveAll(s.dataDir)
|
|
defer os.RemoveAll(s.configFile)
|
|
|
|
cmd := exec.Command("kill", "-9", fmt.Sprintf("%d", s.pid))
|
|
if err := cmd.Run(); err != nil {
|
|
panic(err)
|
|
}
|
|
}
|
|
|
|
func newTestServer(t *testing.T) *testServer {
|
|
if path, err := exec.LookPath("consul"); err != nil || path == "" {
|
|
t.Log("consul not found on $PATH, skipping")
|
|
t.SkipNow()
|
|
}
|
|
|
|
pidFile, err := ioutil.TempFile("", "consul")
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
pidFile.Close()
|
|
os.Remove(pidFile.Name())
|
|
|
|
dataDir, err := ioutil.TempDir("", "consul")
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
configFile, err := ioutil.TempFile("", "consul")
|
|
if err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
configContent := fmt.Sprintf(consulConfig, dataDir)
|
|
if _, err := configFile.WriteString(configContent); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
configFile.Close()
|
|
|
|
// Start the server
|
|
cmd := exec.Command("consul", "agent", "-config-file", configFile.Name())
|
|
if err := cmd.Start(); err != nil {
|
|
t.Fatalf("err: %s", err)
|
|
}
|
|
|
|
// Allow the server some time to start, and verify we have a leader.
|
|
client := new(http.Client)
|
|
for i := 0; ; i++ {
|
|
if i >= 20 {
|
|
t.Fatal("Server failed to start")
|
|
}
|
|
time.Sleep(100 * time.Millisecond)
|
|
|
|
resp, err := client.Get("http://127.0.0.1:18800/v1/status/leader")
|
|
if err != nil {
|
|
continue
|
|
}
|
|
defer resp.Body.Close()
|
|
|
|
body, err := ioutil.ReadAll(resp.Body)
|
|
if err != nil || len(body) == 2 {
|
|
continue
|
|
}
|
|
|
|
break
|
|
}
|
|
|
|
return &testServer{
|
|
pid: cmd.Process.Pid,
|
|
dataDir: dataDir,
|
|
configFile: configFile.Name(),
|
|
}
|
|
}
|
|
|
|
func makeClient(t *testing.T) (*Client, *testServer) {
|
|
server := newTestServer(t)
|
|
conf := DefaultConfig()
|
|
conf.Address = "127.0.0.1:18800"
|
|
client, err := NewClient(conf)
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
return client, server
|
|
}
|
|
|
|
func testKey() string {
|
|
buf := make([]byte, 16)
|
|
if _, err := crand.Read(buf); err != nil {
|
|
panic(fmt.Errorf("Failed to read random bytes: %v", err))
|
|
}
|
|
|
|
return fmt.Sprintf("%08x-%04x-%04x-%04x-%12x",
|
|
buf[0:4],
|
|
buf[4:6],
|
|
buf[6:8],
|
|
buf[8:10],
|
|
buf[10:16])
|
|
}
|
|
|
|
func TestSetQueryOptions(t *testing.T) {
|
|
c, s := makeClient(t)
|
|
defer s.stop()
|
|
|
|
r := c.newRequest("GET", "/v1/kv/foo")
|
|
q := &QueryOptions{
|
|
Datacenter: "foo",
|
|
AllowStale: true,
|
|
RequireConsistent: true,
|
|
WaitIndex: 1000,
|
|
WaitTime: 100 * time.Second,
|
|
Token: "12345",
|
|
}
|
|
r.setQueryOptions(q)
|
|
|
|
if r.params.Get("dc") != "foo" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if _, ok := r.params["stale"]; !ok {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if _, ok := r.params["consistent"]; !ok {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if r.params.Get("index") != "1000" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if r.params.Get("wait") != "100000ms" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if r.params.Get("token") != "12345" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
}
|
|
|
|
func TestSetWriteOptions(t *testing.T) {
|
|
c, s := makeClient(t)
|
|
defer s.stop()
|
|
|
|
r := c.newRequest("GET", "/v1/kv/foo")
|
|
q := &WriteOptions{
|
|
Datacenter: "foo",
|
|
Token: "23456",
|
|
}
|
|
r.setWriteOptions(q)
|
|
|
|
if r.params.Get("dc") != "foo" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
if r.params.Get("token") != "23456" {
|
|
t.Fatalf("bad: %v", r.params)
|
|
}
|
|
}
|
|
|
|
func TestRequestToHTTP(t *testing.T) {
|
|
c, s := makeClient(t)
|
|
defer s.stop()
|
|
|
|
r := c.newRequest("DELETE", "/v1/kv/foo")
|
|
q := &QueryOptions{
|
|
Datacenter: "foo",
|
|
}
|
|
r.setQueryOptions(q)
|
|
req, err := r.toHTTP()
|
|
if err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
if req.Method != "DELETE" {
|
|
t.Fatalf("bad: %v", req)
|
|
}
|
|
if req.URL.String() != "http://127.0.0.1:18800/v1/kv/foo?dc=foo" {
|
|
t.Fatalf("bad: %v", req)
|
|
}
|
|
}
|
|
|
|
func TestParseQueryMeta(t *testing.T) {
|
|
resp := &http.Response{
|
|
Header: make(map[string][]string),
|
|
}
|
|
resp.Header.Set("X-Consul-Index", "12345")
|
|
resp.Header.Set("X-Consul-LastContact", "80")
|
|
resp.Header.Set("X-Consul-KnownLeader", "true")
|
|
|
|
qm := &QueryMeta{}
|
|
if err := parseQueryMeta(resp, qm); err != nil {
|
|
t.Fatalf("err: %v", err)
|
|
}
|
|
|
|
if qm.LastIndex != 12345 {
|
|
t.Fatalf("Bad: %v", qm)
|
|
}
|
|
if qm.LastContact != 80*time.Millisecond {
|
|
t.Fatalf("Bad: %v", qm)
|
|
}
|
|
if !qm.KnownLeader {
|
|
t.Fatalf("Bad: %v", qm)
|
|
}
|
|
}
|