From bbf715fdaf6993760b3bfdc05fd95c01c2ef38dd Mon Sep 17 00:00:00 2001 From: Frank Schroeder Date: Wed, 5 Jul 2017 12:38:11 +0200 Subject: [PATCH] agent: fix data races with registerEndpoint Only register a different endpoint after it has been fully created. --- agent/acl_test.go | 134 +++---- agent/dns_test.go | 38 +- agent/prepared_query_endpoint_test.go | 482 +++++++++++++------------- 3 files changed, 331 insertions(+), 323 deletions(-) diff --git a/agent/acl_test.go b/agent/acl_test.go index dba1bc9b0..bcee072d7 100644 --- a/agent/acl_test.go +++ b/agent/acl_test.go @@ -46,16 +46,17 @@ func TestACL_Version8(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // With version 8 enforcement off, this should not get called. + getPolicyFn: func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { + t.Fatalf("should not have called to server") + return nil + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // With version 8 enforcement off, this should not get called. - m.getPolicyFn = func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { - t.Fatalf("should not have called to server") - return nil - } if token, err := a.resolveToken("nope"); token != nil || err != nil { t.Fatalf("bad: %v err: %v", token, err) } @@ -69,15 +70,16 @@ func TestACL_Disabled(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // Fetch a token without ACLs enabled and make sure the manager sees it. + getPolicyFn: func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { + return errors.New(aclDisabled) + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // Fetch a token without ACLs enabled and make sure the manager sees it. - m.getPolicyFn = func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { - return errors.New(aclDisabled) - } if a.acls.isDisabled() { t.Fatalf("should not be disabled yet") } @@ -122,18 +124,18 @@ func TestACL_Special_IDs(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // An empty ID should get mapped to the anonymous token. + getPolicyFn: func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { + if req.ACL != "anonymous" { + t.Fatalf("bad: %#v", *req) + } + return errors.New(aclNotFound) + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - - // An empty ID should get mapped to the anonymous token. - m.getPolicyFn = func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { - if req.ACL != "anonymous" { - t.Fatalf("bad: %#v", *req) - } - return errors.New(aclNotFound) - } _, err := a.resolveToken("") if err == nil || !strings.Contains(err.Error(), aclNotFound) { t.Fatalf("err: %v", err) @@ -175,15 +177,16 @@ func TestACL_Down_Deny(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // Resolve with ACLs down. + getPolicyFn: func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { + return fmt.Errorf("ACLs are broken") + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // Resolve with ACLs down. - m.getPolicyFn = func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { - return fmt.Errorf("ACLs are broken") - } acl, err := a.resolveToken("nope") if err != nil { t.Fatalf("err: %v", err) @@ -205,15 +208,16 @@ func TestACL_Down_Allow(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // Resolve with ACLs down. + getPolicyFn: func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { + return fmt.Errorf("ACLs are broken") + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // Resolve with ACLs down. - m.getPolicyFn = func(*structs.ACLPolicyRequest, *structs.ACLPolicy) error { - return fmt.Errorf("ACLs are broken") - } acl, err := a.resolveToken("nope") if err != nil { t.Fatalf("err: %v", err) @@ -235,26 +239,27 @@ func TestACL_Down_Extend(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // Populate the cache for one of the tokens. + getPolicyFn: func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { + *reply = structs.ACLPolicy{ + Parent: "allow", + Policy: &rawacl.Policy{ + Agents: []*rawacl.AgentPolicy{ + &rawacl.AgentPolicy{ + Node: cfg.NodeName, + Policy: "read", + }, + }, + }, + } + return nil + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // Populate the cache for one of the tokens. - m.getPolicyFn = func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { - *reply = structs.ACLPolicy{ - Parent: "allow", - Policy: &rawacl.Policy{ - Agents: []*rawacl.AgentPolicy{ - &rawacl.AgentPolicy{ - Node: cfg.NodeName, - Policy: "read", - }, - }, - }, - } - return nil - } acl, err := a.resolveToken("yep") if err != nil { t.Fatalf("err: %v", err) @@ -312,28 +317,29 @@ func TestACL_Cache(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockServer{} + m := MockServer{ + // Populate the cache for one of the tokens. + getPolicyFn: func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { + *reply = structs.ACLPolicy{ + ETag: "hash1", + Parent: "deny", + Policy: &rawacl.Policy{ + Agents: []*rawacl.AgentPolicy{ + &rawacl.AgentPolicy{ + Node: cfg.NodeName, + Policy: "read", + }, + }, + }, + TTL: 10 * time.Millisecond, + } + return nil + }, + } if err := a.registerEndpoint("ACL", &m); err != nil { t.Fatalf("err: %v", err) } - // Populate the cache for one of the tokens. - m.getPolicyFn = func(req *structs.ACLPolicyRequest, reply *structs.ACLPolicy) error { - *reply = structs.ACLPolicy{ - ETag: "hash1", - Parent: "deny", - Policy: &rawacl.Policy{ - Agents: []*rawacl.AgentPolicy{ - &rawacl.AgentPolicy{ - Node: cfg.NodeName, - Policy: "read", - }, - }, - }, - TTL: 10 * time.Millisecond, - } - return nil - } acl, err := a.resolveToken("yep") if err != nil { t.Fatalf("err: %v", err) diff --git a/agent/dns_test.go b/agent/dns_test.go index e2d6ef43a..90e905d6a 100644 --- a/agent/dns_test.go +++ b/agent/dns_test.go @@ -3919,15 +3919,16 @@ func TestDNS_PreparedQuery_AllowStale(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockPreparedQuery{} - if err := a.registerEndpoint("PreparedQuery", &m); err != nil { - t.Fatalf("err: %v", err) + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + // Return a response that's perpetually too stale. + reply.LastContact = 2 * time.Second + return nil + }, } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - // Return a response that's perpetually too stale. - reply.LastContact = 2 * time.Second - return nil + if err := a.registerEndpoint("PreparedQuery", &m); err != nil { + t.Fatalf("err: %v", err) } // Make sure that the lookup terminates and results in an SOA since @@ -4000,19 +4001,20 @@ func TestDNS_PreparedQuery_AgentSource(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} - if err := a.registerEndpoint("PreparedQuery", &m); err != nil { - t.Fatalf("err: %v", err) + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + // Check that the agent inserted its self-name and datacenter to + // the RPC request body. + if args.Agent.Datacenter != a.Config.Datacenter || + args.Agent.Node != a.Config.NodeName { + t.Fatalf("bad: %#v", args.Agent) + } + return nil + }, } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - // Check that the agent inserted its self-name and datacenter to - // the RPC request body. - if args.Agent.Datacenter != a.Config.Datacenter || - args.Agent.Node != a.Config.NodeName { - t.Fatalf("bad: %#v", args.Agent) - } - return nil + if err := a.registerEndpoint("PreparedQuery", &m); err != nil { + t.Fatalf("err: %v", err) } { diff --git a/agent/prepared_query_endpoint_test.go b/agent/prepared_query_endpoint_test.go index 01a061fd3..5ae6f4392 100644 --- a/agent/prepared_query_endpoint_test.go +++ b/agent/prepared_query_endpoint_test.go @@ -73,44 +73,44 @@ func TestPreparedQuery_Create(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + applyFn: func(args *structs.PreparedQueryRequest, reply *string) error { + expected := &structs.PreparedQueryRequest{ + Datacenter: "dc1", + Op: structs.PreparedQueryCreate, + Query: &structs.PreparedQuery{ + Name: "my-query", + Session: "my-session", + Service: structs.ServiceQuery{ + Service: "my-service", + Failover: structs.QueryDatacenterOptions{ + NearestN: 4, + Datacenters: []string{"dc1", "dc2"}, + }, + OnlyPassing: true, + Tags: []string{"foo", "bar"}, + NodeMeta: map[string]string{"somekey": "somevalue"}, + }, + DNS: structs.QueryDNSOptions{ + TTL: "10s", + }, + }, + WriteRequest: structs.WriteRequest{ + Token: "my-token", + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + *reply = "my-id" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.applyFn = func(args *structs.PreparedQueryRequest, reply *string) error { - expected := &structs.PreparedQueryRequest{ - Datacenter: "dc1", - Op: structs.PreparedQueryCreate, - Query: &structs.PreparedQuery{ - Name: "my-query", - Session: "my-session", - Service: structs.ServiceQuery{ - Service: "my-service", - Failover: structs.QueryDatacenterOptions{ - NearestN: 4, - Datacenters: []string{"dc1", "dc2"}, - }, - OnlyPassing: true, - Tags: []string{"foo", "bar"}, - NodeMeta: map[string]string{"somekey": "somevalue"}, - }, - DNS: structs.QueryDNSOptions{ - TTL: "10s", - }, - }, - WriteRequest: structs.WriteRequest{ - Token: "my-token", - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - *reply = "my-id" - return nil - } - body := bytes.NewBuffer(nil) enc := json.NewEncoder(body) raw := map[string]interface{}{ @@ -158,16 +158,16 @@ func TestPreparedQuery_List(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + listFn: func(args *structs.DCSpecificRequest, reply *structs.IndexedPreparedQueries) error { + // Return an empty response. + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.listFn = func(args *structs.DCSpecificRequest, reply *structs.IndexedPreparedQueries) error { - // Return an empty response. - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query", body) resp := httptest.NewRecorder() @@ -191,30 +191,30 @@ func TestPreparedQuery_List(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + listFn: func(args *structs.DCSpecificRequest, reply *structs.IndexedPreparedQueries) error { + expected := &structs.DCSpecificRequest{ + Datacenter: "dc1", + QueryOptions: structs.QueryOptions{ + Token: "my-token", + RequireConsistent: true, + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + query := &structs.PreparedQuery{ + ID: "my-id", + } + reply.Queries = append(reply.Queries, query) + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.listFn = func(args *structs.DCSpecificRequest, reply *structs.IndexedPreparedQueries) error { - expected := &structs.DCSpecificRequest{ - Datacenter: "dc1", - QueryOptions: structs.QueryOptions{ - Token: "my-token", - RequireConsistent: true, - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - query := &structs.PreparedQuery{ - ID: "my-id", - } - reply.Queries = append(reply.Queries, query) - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query?token=my-token&consistent=true", body) resp := httptest.NewRecorder() @@ -241,16 +241,16 @@ func TestPreparedQuery_Execute(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + // Just return an empty response. + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - // Just return an empty response. - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id/execute", body) resp := httptest.NewRecorder() @@ -274,38 +274,38 @@ func TestPreparedQuery_Execute(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + expected := &structs.PreparedQueryExecuteRequest{ + Datacenter: "dc1", + QueryIDOrName: "my-id", + Limit: 5, + Source: structs.QuerySource{ + Datacenter: "dc1", + Node: "my-node", + }, + Agent: structs.QuerySource{ + Datacenter: a.Config.Datacenter, + Node: a.Config.NodeName, + }, + QueryOptions: structs.QueryOptions{ + Token: "my-token", + RequireConsistent: true, + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + // Just set something so we can tell this is returned. + reply.Failovers = 99 + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - expected := &structs.PreparedQueryExecuteRequest{ - Datacenter: "dc1", - QueryIDOrName: "my-id", - Limit: 5, - Source: structs.QuerySource{ - Datacenter: "dc1", - Node: "my-node", - }, - Agent: structs.QuerySource{ - Datacenter: a.Config.Datacenter, - Node: a.Config.NodeName, - }, - QueryOptions: structs.QueryOptions{ - Token: "my-token", - RequireConsistent: true, - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - // Just set something so we can tell this is returned. - reply.Failovers = 99 - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id/execute?token=my-token&consistent=true&near=my-node&limit=5", body) resp := httptest.NewRecorder() @@ -330,25 +330,25 @@ func TestPreparedQuery_Execute(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + if args.Source.Node != "" { + t.Fatalf("expect node to be empty, got %q", args.Source.Node) + } + expect := structs.QuerySource{ + Datacenter: a.Config.Datacenter, + Node: a.Config.NodeName, + } + if !reflect.DeepEqual(args.Agent, expect) { + t.Fatalf("expect: %#v\nactual: %#v", expect, args.Agent) + } + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - if args.Source.Node != "" { - t.Fatalf("expect node to be empty, got %q", args.Source.Node) - } - expect := structs.QuerySource{ - Datacenter: a.Config.Datacenter, - Node: a.Config.NodeName, - } - if !reflect.DeepEqual(args.Agent, expect) { - t.Fatalf("expect: %#v\nactual: %#v", expect, args.Agent) - } - return nil - } - req, _ := http.NewRequest("GET", "/v1/query/my-id/execute", nil) resp := httptest.NewRecorder() if _, err := a.srv.PreparedQuerySpecific(resp, req); err != nil { @@ -364,24 +364,24 @@ func TestPreparedQuery_Execute(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + nodesResponse := make(structs.CheckServiceNodes, 1) + nodesResponse[0].Node = &structs.Node{ + Node: "foo", Address: "127.0.0.1", + TaggedAddresses: map[string]string{ + "wan": "127.0.0.2", + }, + } + reply.Nodes = nodesResponse + reply.Datacenter = "dc2" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - nodesResponse := make(structs.CheckServiceNodes, 1) - nodesResponse[0].Node = &structs.Node{ - Node: "foo", Address: "127.0.0.1", - TaggedAddresses: map[string]string{ - "wan": "127.0.0.2", - }, - } - reply.Nodes = nodesResponse - reply.Datacenter = "dc2" - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id/execute?dc=dc2", body) resp := httptest.NewRecorder() @@ -414,24 +414,24 @@ func TestPreparedQuery_Execute(t *testing.T) { a := NewTestAgent(t.Name(), cfg) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + executeFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { + nodesResponse := make(structs.CheckServiceNodes, 1) + nodesResponse[0].Node = &structs.Node{ + Node: "foo", Address: "127.0.0.1", + TaggedAddresses: map[string]string{ + "wan": "127.0.0.2", + }, + } + reply.Nodes = nodesResponse + reply.Datacenter = "dc1" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.executeFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExecuteResponse) error { - nodesResponse := make(structs.CheckServiceNodes, 1) - nodesResponse[0].Node = &structs.Node{ - Node: "foo", Address: "127.0.0.1", - TaggedAddresses: map[string]string{ - "wan": "127.0.0.2", - }, - } - reply.Nodes = nodesResponse - reply.Datacenter = "dc1" - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id/execute?dc=dc2", body) resp := httptest.NewRecorder() @@ -478,38 +478,38 @@ func TestPreparedQuery_Explain(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + explainFn: func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExplainResponse) error { + expected := &structs.PreparedQueryExecuteRequest{ + Datacenter: "dc1", + QueryIDOrName: "my-id", + Limit: 5, + Source: structs.QuerySource{ + Datacenter: "dc1", + Node: "my-node", + }, + Agent: structs.QuerySource{ + Datacenter: a.Config.Datacenter, + Node: a.Config.NodeName, + }, + QueryOptions: structs.QueryOptions{ + Token: "my-token", + RequireConsistent: true, + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + // Just set something so we can tell this is returned. + reply.Query.Name = "hello" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.explainFn = func(args *structs.PreparedQueryExecuteRequest, reply *structs.PreparedQueryExplainResponse) error { - expected := &structs.PreparedQueryExecuteRequest{ - Datacenter: "dc1", - QueryIDOrName: "my-id", - Limit: 5, - Source: structs.QuerySource{ - Datacenter: "dc1", - Node: "my-node", - }, - Agent: structs.QuerySource{ - Datacenter: a.Config.Datacenter, - Node: a.Config.NodeName, - }, - QueryOptions: structs.QueryOptions{ - Token: "my-token", - RequireConsistent: true, - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - // Just set something so we can tell this is returned. - reply.Query.Name = "hello" - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id/explain?token=my-token&consistent=true&near=my-node&limit=5", body) resp := httptest.NewRecorder() @@ -551,31 +551,31 @@ func TestPreparedQuery_Get(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + getFn: func(args *structs.PreparedQuerySpecificRequest, reply *structs.IndexedPreparedQueries) error { + expected := &structs.PreparedQuerySpecificRequest{ + Datacenter: "dc1", + QueryID: "my-id", + QueryOptions: structs.QueryOptions{ + Token: "my-token", + RequireConsistent: true, + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + query := &structs.PreparedQuery{ + ID: "my-id", + } + reply.Queries = append(reply.Queries, query) + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.getFn = func(args *structs.PreparedQuerySpecificRequest, reply *structs.IndexedPreparedQueries) error { - expected := &structs.PreparedQuerySpecificRequest{ - Datacenter: "dc1", - QueryID: "my-id", - QueryOptions: structs.QueryOptions{ - Token: "my-token", - RequireConsistent: true, - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - query := &structs.PreparedQuery{ - ID: "my-id", - } - reply.Queries = append(reply.Queries, query) - return nil - } - body := bytes.NewBuffer(nil) req, _ := http.NewRequest("GET", "/v1/query/my-id?token=my-token&consistent=true", body) resp := httptest.NewRecorder() @@ -616,45 +616,45 @@ func TestPreparedQuery_Update(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + applyFn: func(args *structs.PreparedQueryRequest, reply *string) error { + expected := &structs.PreparedQueryRequest{ + Datacenter: "dc1", + Op: structs.PreparedQueryUpdate, + Query: &structs.PreparedQuery{ + ID: "my-id", + Name: "my-query", + Session: "my-session", + Service: structs.ServiceQuery{ + Service: "my-service", + Failover: structs.QueryDatacenterOptions{ + NearestN: 4, + Datacenters: []string{"dc1", "dc2"}, + }, + OnlyPassing: true, + Tags: []string{"foo", "bar"}, + NodeMeta: map[string]string{"somekey": "somevalue"}, + }, + DNS: structs.QueryDNSOptions{ + TTL: "10s", + }, + }, + WriteRequest: structs.WriteRequest{ + Token: "my-token", + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + *reply = "don't care" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.applyFn = func(args *structs.PreparedQueryRequest, reply *string) error { - expected := &structs.PreparedQueryRequest{ - Datacenter: "dc1", - Op: structs.PreparedQueryUpdate, - Query: &structs.PreparedQuery{ - ID: "my-id", - Name: "my-query", - Session: "my-session", - Service: structs.ServiceQuery{ - Service: "my-service", - Failover: structs.QueryDatacenterOptions{ - NearestN: 4, - Datacenters: []string{"dc1", "dc2"}, - }, - OnlyPassing: true, - Tags: []string{"foo", "bar"}, - NodeMeta: map[string]string{"somekey": "somevalue"}, - }, - DNS: structs.QueryDNSOptions{ - TTL: "10s", - }, - }, - WriteRequest: structs.WriteRequest{ - Token: "my-token", - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - *reply = "don't care" - return nil - } - body := bytes.NewBuffer(nil) enc := json.NewEncoder(body) raw := map[string]interface{}{ @@ -694,30 +694,30 @@ func TestPreparedQuery_Delete(t *testing.T) { a := NewTestAgent(t.Name(), nil) defer a.Shutdown() - m := MockPreparedQuery{} + m := MockPreparedQuery{ + applyFn: func(args *structs.PreparedQueryRequest, reply *string) error { + expected := &structs.PreparedQueryRequest{ + Datacenter: "dc1", + Op: structs.PreparedQueryDelete, + Query: &structs.PreparedQuery{ + ID: "my-id", + }, + WriteRequest: structs.WriteRequest{ + Token: "my-token", + }, + } + if !reflect.DeepEqual(args, expected) { + t.Fatalf("bad: %v", args) + } + + *reply = "don't care" + return nil + }, + } if err := a.registerEndpoint("PreparedQuery", &m); err != nil { t.Fatalf("err: %v", err) } - m.applyFn = func(args *structs.PreparedQueryRequest, reply *string) error { - expected := &structs.PreparedQueryRequest{ - Datacenter: "dc1", - Op: structs.PreparedQueryDelete, - Query: &structs.PreparedQuery{ - ID: "my-id", - }, - WriteRequest: structs.WriteRequest{ - Token: "my-token", - }, - } - if !reflect.DeepEqual(args, expected) { - t.Fatalf("bad: %v", args) - } - - *reply = "don't care" - return nil - } - body := bytes.NewBuffer(nil) enc := json.NewEncoder(body) raw := map[string]interface{}{