New test agent

This commit is contained in:
Alex Dadgar
2017-07-19 22:14:36 -07:00
parent dedb9127a3
commit 873587381d
15 changed files with 360 additions and 110 deletions

View File

@@ -13,7 +13,7 @@ import (
)
func TestHTTP_AgentSelf(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/agent/self", nil)
if err != nil {
@@ -39,7 +39,7 @@ func TestHTTP_AgentSelf(t *testing.T) {
}
func TestHTTP_AgentJoin(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Determine the join address
member := s.Agent.Server().LocalMember()
addr := fmt.Sprintf("%s:%d", member.Addr, member.Port)
@@ -70,7 +70,7 @@ func TestHTTP_AgentJoin(t *testing.T) {
}
func TestHTTP_AgentMembers(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/agent/members", nil)
if err != nil {
@@ -93,7 +93,7 @@ func TestHTTP_AgentMembers(t *testing.T) {
}
func TestHTTP_AgentForceLeave(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("PUT", "/v1/agent/force-leave?node=foo", nil)
if err != nil {
@@ -110,7 +110,7 @@ func TestHTTP_AgentForceLeave(t *testing.T) {
}
func TestHTTP_AgentSetServers(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Establish a baseline number of servers
req, err := http.NewRequest("GET", "/v1/agent/servers", nil)
if err != nil {
@@ -187,7 +187,7 @@ func TestHTTP_AgentListKeys(t *testing.T) {
httpTest(t, func(c *Config) {
c.Server.EncryptKey = key1
}, func(s *TestServer) {
}, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/agent/keyring/list", nil)
if err != nil {
t.Fatalf("err: %s", err)
@@ -211,7 +211,7 @@ func TestHTTP_AgentInstallKey(t *testing.T) {
httpTest(t, func(c *Config) {
c.Server.EncryptKey = key1
}, func(s *TestServer) {
}, func(s *TestAgent) {
b, err := json.Marshal(&structs.KeyringRequest{Key: key2})
if err != nil {
t.Fatalf("err: %v", err)
@@ -249,7 +249,7 @@ func TestHTTP_AgentRemoveKey(t *testing.T) {
httpTest(t, func(c *Config) {
c.Server.EncryptKey = key1
}, func(s *TestServer) {
}, func(s *TestAgent) {
b, err := json.Marshal(&structs.KeyringRequest{Key: key2})
if err != nil {
t.Fatalf("err: %v", err)

View File

@@ -13,7 +13,7 @@ import (
)
func TestHTTP_AllocsList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
alloc1 := mock.Alloc()
@@ -59,7 +59,7 @@ func TestHTTP_AllocsList(t *testing.T) {
}
func TestHTTP_AllocsPrefixList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
@@ -118,7 +118,7 @@ func TestHTTP_AllocsPrefixList(t *testing.T) {
}
func TestHTTP_AllocQuery(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
alloc := mock.Alloc()
@@ -164,7 +164,7 @@ func TestHTTP_AllocQuery(t *testing.T) {
}
func TestHTTP_AllocQuery_Payload(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
alloc := mock.Alloc()
@@ -220,7 +220,7 @@ func TestHTTP_AllocQuery_Payload(t *testing.T) {
}
func TestHTTP_AllocStats(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/client/allocation/123/foo", nil)
if err != nil {
@@ -237,7 +237,7 @@ func TestHTTP_AllocStats(t *testing.T) {
}
func TestHTTP_AllocSnapshot(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/client/allocation/123/snapshot", nil)
if err != nil {
@@ -254,7 +254,7 @@ func TestHTTP_AllocSnapshot(t *testing.T) {
}
func TestHTTP_AllocGC(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/client/allocation/123/gc", nil)
if err != nil {
@@ -271,7 +271,7 @@ func TestHTTP_AllocGC(t *testing.T) {
}
func TestHTTP_AllocAllGC(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/client/gc", nil)
if err != nil {

View File

@@ -12,7 +12,7 @@ import (
func TestHTTP_DeploymentList(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
d1 := mock.Deployment()
@@ -42,7 +42,7 @@ func TestHTTP_DeploymentList(t *testing.T) {
func TestHTTP_DeploymentPrefixList(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
d1 := mock.Deployment()
@@ -75,7 +75,7 @@ func TestHTTP_DeploymentPrefixList(t *testing.T) {
func TestHTTP_DeploymentAllocations(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
j := mock.Job()
@@ -113,7 +113,7 @@ func TestHTTP_DeploymentAllocations(t *testing.T) {
func TestHTTP_DeploymentQuery(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
d := mock.Deployment()
@@ -141,7 +141,7 @@ func TestHTTP_DeploymentQuery(t *testing.T) {
func TestHTTP_DeploymentPause(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
j := mock.Job()
@@ -178,7 +178,7 @@ func TestHTTP_DeploymentPause(t *testing.T) {
func TestHTTP_DeploymentPromote(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
j := mock.Job()
@@ -215,7 +215,7 @@ func TestHTTP_DeploymentPromote(t *testing.T) {
func TestHTTP_DeploymentAllocHealth(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
j := mock.Job()
@@ -256,7 +256,7 @@ func TestHTTP_DeploymentAllocHealth(t *testing.T) {
func TestHTTP_DeploymentFail(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
j := mock.Job()

View File

@@ -10,7 +10,7 @@ import (
)
func TestHTTP_EvalList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
eval1 := mock.Eval()
@@ -54,7 +54,7 @@ func TestHTTP_EvalList(t *testing.T) {
}
func TestHTTP_EvalPrefixList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
eval1 := mock.Eval()
@@ -105,7 +105,7 @@ func TestHTTP_EvalPrefixList(t *testing.T) {
}
func TestHTTP_EvalAllocations(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
alloc1 := mock.Alloc()
@@ -153,7 +153,7 @@ func TestHTTP_EvalAllocations(t *testing.T) {
}
func TestHTTP_EvalQuery(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Directly manipulate the state
state := s.Agent.server.State()
eval := mock.Eval()

View File

@@ -25,7 +25,7 @@ import (
)
func TestAllocDirFS_List_MissingParams(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/client/fs/ls/", nil)
if err != nil {
t.Fatalf("err: %v", err)
@@ -40,7 +40,7 @@ func TestAllocDirFS_List_MissingParams(t *testing.T) {
}
func TestAllocDirFS_Stat_MissingParams(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/client/fs/stat/", nil)
if err != nil {
t.Fatalf("err: %v", err)
@@ -67,7 +67,7 @@ func TestAllocDirFS_Stat_MissingParams(t *testing.T) {
}
func TestAllocDirFS_ReadAt_MissingParams(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/client/fs/readat/", nil)
if err != nil {
t.Fatalf("err: %v", err)
@@ -500,7 +500,7 @@ func TestStreamFramer_Order_PlainText(t *testing.T) {
}
func TestHTTP_Stream_MissingParams(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/client/fs/stream/", nil)
if err != nil {
t.Fatalf("err: %v", err)
@@ -560,7 +560,7 @@ func (n nopWriteCloser) Close() error {
}
func TestHTTP_Stream_NoFile(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -576,7 +576,7 @@ func TestHTTP_Stream_NoFile(t *testing.T) {
}
func TestHTTP_Stream_Modify(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -651,7 +651,7 @@ func TestHTTP_Stream_Modify(t *testing.T) {
}
func TestHTTP_Stream_Truncate(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -760,7 +760,7 @@ func TestHTTP_Stream_Truncate(t *testing.T) {
}
func TestHTTP_Stream_Delete(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -842,7 +842,7 @@ func TestHTTP_Stream_Delete(t *testing.T) {
}
func TestHTTP_Logs_NoFollow(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir and create the log dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -923,7 +923,7 @@ func TestHTTP_Logs_NoFollow(t *testing.T) {
}
func TestHTTP_Logs_Follow(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Get a temp alloc dir and create the log dir
ad := tempAllocDir(t)
defer os.RemoveAll(ad.AllocDir)
@@ -1029,7 +1029,7 @@ func BenchmarkHTTP_Logs_Follow(t *testing.B) {
runtime.MemProfileRate = 1
s := makeHTTPServer(t, nil)
defer s.Cleanup()
defer s.Shutdown()
testutil.WaitForLeader(t, s.Agent.RPC)
// Get a temp alloc dir and create the log dir

View File

@@ -35,7 +35,7 @@ type HTTPServer struct {
mux *http.ServeMux
listener net.Listener
logger *log.Logger
addr string
Addr string
}
// NewHTTPServer starts new HTTP server over the agent
@@ -76,7 +76,7 @@ func NewHTTPServer(agent *Agent, config *Config) (*HTTPServer, error) {
mux: mux,
listener: ln,
logger: agent.logger,
addr: ln.Addr().String(),
Addr: ln.Addr().String(),
}
srv.registerHandlers(config.EnableDebug)
@@ -97,7 +97,7 @@ func newScadaHttp(agent *Agent, list net.Listener) *HTTPServer {
mux: mux,
listener: list,
logger: agent.logger,
addr: scadaHTTPAddr,
Addr: scadaHTTPAddr,
}
srv.registerHandlers(false) // Never allow debug for SCADA

View File

@@ -12,7 +12,6 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"os"
"strconv"
"testing"
"time"
@@ -23,41 +22,17 @@ import (
"github.com/hashicorp/nomad/testutil"
)
type TestServer struct {
T testing.TB
Dir string
Agent *Agent
Server *HTTPServer
}
func (s *TestServer) Cleanup() {
s.Server.Shutdown()
s.Agent.Shutdown()
os.RemoveAll(s.Dir)
}
// makeHTTPServer returns a test server whose logs will be written to
// the passed writer. If the writer is nil, the logs are written to stderr.
func makeHTTPServer(t testing.TB, cb func(c *Config)) *TestServer {
dir, agent := makeAgent(t, cb)
srv, err := NewHTTPServer(agent, agent.config)
if err != nil {
t.Fatalf("err: %v", err)
}
s := &TestServer{
T: t,
Dir: dir,
Agent: agent,
Server: srv,
}
return s
func makeHTTPServer(t testing.TB, cb func(c *Config)) *TestAgent {
return NewTestAgent(t.Name(), cb)
}
func BenchmarkHTTPRequests(b *testing.B) {
s := makeHTTPServer(b, func(c *Config) {
c.Client.Enabled = false
})
defer s.Cleanup()
defer s.Shutdown()
job := mock.Job()
var allocs []*structs.Allocation
@@ -146,7 +121,7 @@ func TestSetMeta(t *testing.T) {
func TestSetHeaders(t *testing.T) {
s := makeHTTPServer(t, nil)
s.Agent.config.HTTPAPIResponseHeaders = map[string]string{"foo": "bar"}
defer s.Cleanup()
defer s.Shutdown()
resp := httptest.NewRecorder()
handler := func(resp http.ResponseWriter, req *http.Request) (interface{}, error) {
@@ -165,7 +140,7 @@ func TestSetHeaders(t *testing.T) {
func TestContentTypeIsJSON(t *testing.T) {
s := makeHTTPServer(t, nil)
defer s.Cleanup()
defer s.Shutdown()
resp := httptest.NewRecorder()
@@ -197,7 +172,7 @@ func TestPrettyPrintBare(t *testing.T) {
func testPrettyPrint(pretty string, prettyFmt bool, t *testing.T) {
s := makeHTTPServer(t, nil)
defer s.Cleanup()
defer s.Shutdown()
r := &structs.Job{Name: "foo"}
@@ -316,7 +291,7 @@ func TestParseConsistency(t *testing.T) {
func TestParseRegion(t *testing.T) {
s := makeHTTPServer(t, nil)
defer s.Cleanup()
defer s.Shutdown()
req, err := http.NewRequest("GET",
"/v1/jobs?region=foo", nil)
@@ -360,7 +335,7 @@ func TestHTTP_VerifyHTTPSClient(t *testing.T) {
KeyFile: fookey,
}
})
defer s.Cleanup()
defer s.Shutdown()
reqURL := fmt.Sprintf("https://%s/v1/agent/self", s.Agent.config.AdvertiseAddrs.HTTP)
@@ -492,9 +467,9 @@ func getIndex(t *testing.T, resp *httptest.ResponseRecorder) uint64 {
return uint64(val)
}
func httpTest(t testing.TB, cb func(c *Config), f func(srv *TestServer)) {
func httpTest(t testing.TB, cb func(c *Config), f func(srv *TestAgent)) {
s := makeHTTPServer(t, cb)
defer s.Cleanup()
defer s.Shutdown()
testutil.WaitForLeader(t, s.Agent.RPC)
f(s)
}

View File

@@ -18,7 +18,7 @@ import (
)
func TestHTTP_JobsList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
for i := 0; i < 3; i++ {
// Create the job
job := mock.Job()
@@ -70,7 +70,7 @@ func TestHTTP_PrefixJobsList(t *testing.T) {
"aabbbbbb-e8f7-fd38-c855-ab94ceb89706",
"aabbcccc-e8f7-fd38-c855-ab94ceb89706",
}
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
for i := 0; i < 3; i++ {
// Create the job
job := mock.Job()
@@ -119,7 +119,7 @@ func TestHTTP_PrefixJobsList(t *testing.T) {
}
func TestHTTP_JobsRegister(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := api.MockJob()
args := api.JobRegisterRequest{
@@ -169,7 +169,7 @@ func TestHTTP_JobsRegister(t *testing.T) {
}
func TestHTTP_JobsRegister_Defaulting(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := api.MockJob()
@@ -226,7 +226,7 @@ func TestHTTP_JobsRegister_Defaulting(t *testing.T) {
}
func TestHTTP_JobQuery(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
args := structs.JobRegisterRequest{
@@ -271,7 +271,7 @@ func TestHTTP_JobQuery(t *testing.T) {
}
func TestHTTP_JobQuery_Payload(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
@@ -324,7 +324,7 @@ func TestHTTP_JobQuery_Payload(t *testing.T) {
}
func TestHTTP_JobUpdate(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := api.MockJob()
args := api.JobRegisterRequest{
@@ -374,7 +374,7 @@ func TestHTTP_JobUpdate(t *testing.T) {
}
func TestHTTP_JobDelete(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
args := structs.JobRegisterRequest{
@@ -466,7 +466,7 @@ func TestHTTP_JobDelete(t *testing.T) {
}
func TestHTTP_JobForceEvaluate(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
args := structs.JobRegisterRequest{
@@ -505,7 +505,7 @@ func TestHTTP_JobForceEvaluate(t *testing.T) {
}
func TestHTTP_JobEvaluations(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
args := structs.JobRegisterRequest{
@@ -552,7 +552,7 @@ func TestHTTP_JobEvaluations(t *testing.T) {
}
func TestHTTP_JobAllocations(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
alloc1 := mock.Alloc()
args := structs.JobRegisterRequest{
@@ -605,7 +605,7 @@ func TestHTTP_JobAllocations(t *testing.T) {
func TestHTTP_JobDeployments(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
j := mock.Job()
args := structs.JobRegisterRequest{
@@ -643,7 +643,7 @@ func TestHTTP_JobDeployments(t *testing.T) {
func TestHTTP_JobDeployment(t *testing.T) {
assert := assert.New(t)
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
j := mock.Job()
args := structs.JobRegisterRequest{
@@ -680,7 +680,7 @@ func TestHTTP_JobDeployment(t *testing.T) {
}
func TestHTTP_JobVersions(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := mock.Job()
args := structs.JobRegisterRequest{
@@ -751,7 +751,7 @@ func TestHTTP_JobVersions(t *testing.T) {
}
func TestHTTP_PeriodicForce(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create and register a periodic job.
job := mock.PeriodicJob()
args := structs.JobRegisterRequest{
@@ -790,7 +790,7 @@ func TestHTTP_PeriodicForce(t *testing.T) {
}
func TestHTTP_JobPlan(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
job := api.MockJob()
args := api.JobPlanRequest{
@@ -826,7 +826,7 @@ func TestHTTP_JobPlan(t *testing.T) {
}
func TestHTTP_JobDispatch(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the parameterized job
job := mock.Job()
job.Type = "batch"
@@ -874,7 +874,7 @@ func TestHTTP_JobDispatch(t *testing.T) {
}
func TestHTTP_JobRevert(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job and register it twice
job := mock.Job()
regReq := structs.JobRegisterRequest{
@@ -926,7 +926,7 @@ func TestHTTP_JobRevert(t *testing.T) {
}
func TestHTTP_JobStable(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job and register it twice
job := mock.Job()
regReq := structs.JobRegisterRequest{

View File

@@ -10,7 +10,7 @@ import (
)
func TestHTTP_NodesList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
for i := 0; i < 3; i++ {
// Create the node
node := mock.Node()
@@ -57,7 +57,7 @@ func TestHTTP_NodesList(t *testing.T) {
}
func TestHTTP_NodesPrefixList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
ids := []string{
"12345678-abcd-efab-cdef-123456789abc",
"12345678-aaaa-efab-cdef-123456789abc",
@@ -113,7 +113,7 @@ func TestHTTP_NodesPrefixList(t *testing.T) {
}
func TestHTTP_NodeForceEval(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the node
node := mock.Node()
args := structs.NodeRegisterRequest{
@@ -164,7 +164,7 @@ func TestHTTP_NodeForceEval(t *testing.T) {
}
func TestHTTP_NodeAllocations(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
node := mock.Node()
args := structs.NodeRegisterRequest{
@@ -221,7 +221,7 @@ func TestHTTP_NodeAllocations(t *testing.T) {
}
func TestHTTP_NodeDrain(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the node
node := mock.Node()
args := structs.NodeRegisterRequest{
@@ -272,7 +272,7 @@ func TestHTTP_NodeDrain(t *testing.T) {
}
func TestHTTP_NodeQuery(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Create the job
node := mock.Node()
args := structs.NodeRegisterRequest{

View File

@@ -11,7 +11,7 @@ import (
)
func TestHTTP_OperatorRaftConfiguration(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
body := bytes.NewBuffer(nil)
req, err := http.NewRequest("GET", "/v1/operator/raft/configuration", body)
if err != nil {
@@ -39,7 +39,7 @@ func TestHTTP_OperatorRaftConfiguration(t *testing.T) {
}
func TestHTTP_OperatorRaftPeer(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
body := bytes.NewBuffer(nil)
req, err := http.NewRequest("DELETE", "/v1/operator/raft/peer?address=nope", body)
if err != nil {

View File

@@ -7,7 +7,7 @@ import (
)
func TestHTTP_RegionList(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/regions", nil)
if err != nil {

View File

@@ -7,7 +7,7 @@ import (
)
func TestClientStatsRequest(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
req, err := http.NewRequest("GET", "/v1/client/stats/?since=foo", nil)
if err != nil {
t.Fatalf("err: %v", err)

View File

@@ -7,7 +7,7 @@ import (
)
func TestHTTP_StatusLeader(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/status/leader", nil)
if err != nil {
@@ -29,7 +29,7 @@ func TestHTTP_StatusLeader(t *testing.T) {
}
func TestHTTP_StatusPeers(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("GET", "/v1/status/peers", nil)
if err != nil {

View File

@@ -7,7 +7,7 @@ import (
)
func TestHTTP_SystemGarbageCollect(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("PUT", "/v1/system/gc", nil)
if err != nil {
@@ -23,7 +23,7 @@ func TestHTTP_SystemGarbageCollect(t *testing.T) {
}
func TestHTTP_ReconcileJobSummaries(t *testing.T) {
httpTest(t, nil, func(s *TestServer) {
httpTest(t, nil, func(s *TestAgent) {
// Make the HTTP request
req, err := http.NewRequest("PUT", "/v1/system/reconcile/summaries", nil)
if err != nil {

275
command/agent/testagent.go Normal file
View File

@@ -0,0 +1,275 @@
package agent
import (
"fmt"
"io"
"io/ioutil"
"math/rand"
"net/http"
"net/http/httptest"
"os"
"path/filepath"
"runtime"
"strings"
"time"
"github.com/hashicorp/nomad/api"
"github.com/hashicorp/nomad/nomad"
"github.com/hashicorp/nomad/nomad/structs"
sconfig "github.com/hashicorp/nomad/nomad/structs/config"
"github.com/hashicorp/nomad/testutil"
)
func init() {
rand.Seed(time.Now().UnixNano()) // seed random number generator
}
// TempDir defines the base dir for temporary directories.
var TempDir = os.TempDir()
// TestAgent encapsulates an Agent with a default configuration and
// startup procedure suitable for testing. It panics if there are errors
// during creation or startup instead of returning errors. It manages a
// temporary data directory which is removed after shutdown.
type TestAgent struct {
// Name is an optional name of the agent.
Name string
// ConfigCallback is an optional callback that allows modification of the
// configuration before the agent is started.
ConfigCallback func(*Config)
// Config is the agent configuration. If Config is nil then
// TestConfig() is used. If Config.DataDir is set then it is
// the callers responsibility to clean up the data directory.
// Otherwise, a temporary data directory is created and removed
// when Shutdown() is called.
Config *Config
// LogOutput is the sink for the logs. If nil, logs are written
// to os.Stderr.
LogOutput io.Writer
// DataDir is the data directory which is used when Config.DataDir
// is not set. It is created automatically and removed when
// Shutdown() is called.
DataDir string
// Key is the optional encryption key for the keyring.
Key string
// Server is a reference to the started HTTP endpoint.
// It is valid after Start().
Server *HTTPServer
// Agent is the embedded Nomad agent.
// It is valid after Start().
*Agent
}
// NewTestAgent returns a started agent with the given name and
// configuration. It panics if the agent could not be started. The
// caller should call Shutdown() to stop the agent and remove temporary
// directories.
func NewTestAgent(name string, configCallback func(*Config)) *TestAgent {
a := &TestAgent{Name: name, ConfigCallback: configCallback}
a.Start()
return a
}
// Start starts a test agent. It panics if the agent could not be started.
func (a *TestAgent) Start() *TestAgent {
if a.Agent != nil {
panic("TestAgent already started")
}
if a.Config == nil {
a.Config = a.config()
}
if a.Config.DataDir == "" {
name := "agent"
if a.Name != "" {
name = a.Name + "-agent"
}
name = strings.Replace(name, "/", "_", -1)
d, err := ioutil.TempDir(TempDir, name)
if err != nil {
panic(fmt.Sprintf("Error creating data dir %s: %s", filepath.Join(TempDir, name), err))
}
a.DataDir = d
a.Config.DataDir = d
a.Config.NomadConfig.DataDir = d
}
for i := 10; i >= 0; i-- {
pickRandomPorts(a.Config)
// write the keyring
if a.Key != "" {
writeKey := func(key, filename string) {
path := filepath.Join(a.Config.DataDir, filename)
if err := initKeyring(path, key); err != nil {
panic(fmt.Sprintf("Error creating keyring %s: %s", path, err))
}
}
writeKey(a.Key, serfKeyring)
}
// we need the err var in the next exit condition
if agent, err := a.start(); err == nil {
a.Agent = agent
break
} else if i == 0 {
fmt.Println(a.Name, "Error starting agent:", err)
runtime.Goexit()
} else {
agent.Shutdown()
wait := time.Duration(rand.Int31n(2000)) * time.Millisecond
fmt.Println(a.Name, "retrying in", wait)
time.Sleep(wait)
}
// Clean out the data dir if we are responsible for it before we
// try again, since the old ports may have gotten written to
// the data dir, such as in the Raft configuration.
if a.DataDir != "" {
if err := os.RemoveAll(a.DataDir); err != nil {
fmt.Println(a.Name, "Error resetting data dir:", err)
runtime.Goexit()
}
}
}
if a.Config.Server.BootstrapExpect == 1 && a.Config.Server.Enabled {
testutil.WaitForResult(func() (bool, error) {
args := &structs.GenericRequest{}
var leader string
err := a.RPC("Status.Leader", args, &leader)
return leader != "", err
}, func(err error) {
panic(fmt.Sprintf("failed to find leader: %v", err))
})
} else {
testutil.WaitForResult(func() (bool, error) {
req, _ := http.NewRequest("GET", "/v1/agent/self", nil)
resp := httptest.NewRecorder()
_, err := a.Server.AgentSelfRequest(resp, req)
return err == nil && resp.Code == 200, err
}, func(err error) {
panic(fmt.Sprintf("failed OK response: %v", err))
})
}
return a
}
func (a *TestAgent) start() (*Agent, error) {
if a.LogOutput == nil {
a.LogOutput = os.Stderr
}
agent, err := NewAgent(a.Config, a.LogOutput)
if err != nil {
return nil, err
}
// Setup the HTTP server
http, err := NewHTTPServer(agent, a.Config)
if err != nil {
return agent, err
}
a.Server = http
return agent, nil
}
// Shutdown stops the agent and removes the data directory if it is
// managed by the test agent.
func (a *TestAgent) Shutdown() error {
defer func() {
if a.DataDir != "" {
os.RemoveAll(a.DataDir)
}
}()
// shutdown agent before endpoints
a.Server.Shutdown()
return a.Agent.Shutdown()
}
func (a *TestAgent) HTTPAddr() string {
if a.Server == nil {
return ""
}
return a.Server.Addr
}
func (a *TestAgent) Client() *api.Client {
conf := api.DefaultConfig()
conf.Address = a.HTTPAddr()
c, err := api.NewClient(conf)
if err != nil {
panic(fmt.Sprintf("Error creating consul API client: %s", err))
}
return c
}
// FivePorts returns the first port number of a block of
// five random ports.
func FivePorts() int {
return 1030 + int(rand.Int31n(6440))*5
}
// pickRandomPorts selects random ports from fixed size random blocks of
// ports. This does not eliminate the chance for port conflict but
// reduces it significanltly with little overhead. Furthermore, asking
// the kernel for a random port by binding to port 0 prolongs the test
// execution (in our case +20sec) while also not fully eliminating the
// chance of port conflicts for concurrently executed test binaries.
// Instead of relying on one set of ports to be sufficient we retry
// starting the agent with different ports on port conflict.
func pickRandomPorts(c *Config) {
port := FivePorts()
c.Ports.HTTP = port + 1
c.Ports.RPC = port + 2
c.Ports.Serf = port + 3
}
// TestConfig returns a unique default configuration for testing an
// agent.
func (a *TestAgent) config() *Config {
conf := DevConfig()
// Customize the server configuration
config := nomad.DefaultConfig()
conf.NomadConfig = config
// Bind and set ports
conf.BindAddr = "127.0.0.1"
conf.NodeName = fmt.Sprintf("Node %d", conf.Ports.RPC)
conf.Consul = sconfig.DefaultConsulConfig()
conf.Vault.Enabled = new(bool)
// Tighten the Serf timing
config.SerfConfig.MemberlistConfig.SuspicionMult = 2
config.SerfConfig.MemberlistConfig.RetransmitMult = 2
config.SerfConfig.MemberlistConfig.ProbeTimeout = 50 * time.Millisecond
config.SerfConfig.MemberlistConfig.ProbeInterval = 100 * time.Millisecond
config.SerfConfig.MemberlistConfig.GossipInterval = 100 * time.Millisecond
// Tighten the Raft timing
config.RaftConfig.LeaderLeaseTimeout = 20 * time.Millisecond
config.RaftConfig.HeartbeatTimeout = 40 * time.Millisecond
config.RaftConfig.ElectionTimeout = 40 * time.Millisecond
config.RaftConfig.StartAsLeader = true
config.RaftTimeout = 500 * time.Millisecond
if err := conf.normalizeAddrs(); err != nil {
panic(fmt.Sprintf("error normalizing config: %v", err))
}
if a.ConfigCallback != nil {
a.ConfigCallback(conf)
}
return conf
}