From 624c465e2b164e261925f6398a416fe1a4a4c6b7 Mon Sep 17 00:00:00 2001 From: Atin Malaviya Date: Wed, 10 Dec 2014 10:02:23 -0500 Subject: [PATCH] Added more tests. Also added return of 404 if the session id to renew is not found --- command/agent/session_endpoint.go | 5 + command/agent/session_endpoint_test.go | 15 ++- consul/leader_test.go | 3 + consul/session_endpoint_test.go | 127 +++++++++++++++++++++++++ consul/state_store.go | 10 ++ consul/state_store_test.go | 42 +++++--- 6 files changed, 180 insertions(+), 22 deletions(-) diff --git a/command/agent/session_endpoint.go b/command/agent/session_endpoint.go index b9b6c6b97f..6de01db378 100644 --- a/command/agent/session_endpoint.go +++ b/command/agent/session_endpoint.go @@ -156,7 +156,12 @@ func (s *HTTPServer) SessionRenew(resp http.ResponseWriter, req *http.Request) ( defer setMeta(resp, &out.QueryMeta) if err := s.agent.RPC("Session.Renew", &args, &out); err != nil { return nil, err + } else if out.Sessions == nil { + resp.WriteHeader(404) + resp.Write([]byte(fmt.Sprintf("Session id '%s' not found", args.Session))) + return nil, nil } + return out.Sessions, nil } diff --git a/command/agent/session_endpoint_test.go b/command/agent/session_endpoint_test.go index a30afc0d0c..5a45879b66 100644 --- a/command/agent/session_endpoint_test.go +++ b/command/agent/session_endpoint_test.go @@ -250,11 +250,8 @@ func TestSessionTTL(t *testing.T) { t.Fatalf("err: %v", err) } respObj, ok = obj.(structs.Sessions) - if ok { - t.Fatalf("session '%s' should have been destroyed") - } if len(respObj) != 0 { - t.Fatalf("bad: %v", respObj) + t.Fatalf("session '%s' should have been destroyed", id) } }) } @@ -315,10 +312,10 @@ func TestSessionTTLRenew(t *testing.T) { } respObj, ok = obj.(structs.Sessions) if !ok { - t.Fatalf("session '%s' should have renewed") + t.Fatalf("session '%s' should have renewed", id) } if len(respObj) != 1 { - t.Fatalf("bad: %v", respObj) + t.Fatalf("session '%s' should have renewed", id) } // now wait for timeout and expect session to get destroyed @@ -332,11 +329,11 @@ func TestSessionTTLRenew(t *testing.T) { t.Fatalf("err: %v", err) } respObj, ok = obj.(structs.Sessions) - if ok { - t.Fatalf("session '%s' should have been destroyed") + if !ok { + t.Fatalf("session '%s' should have destroyed", id) } if len(respObj) != 0 { - t.Fatalf("bad: %v", respObj) + t.Fatalf("session '%s' should have destroyed", id) } }) } diff --git a/consul/leader_test.go b/consul/leader_test.go index 75535d56bb..1bd910858b 100644 --- a/consul/leader_test.go +++ b/consul/leader_test.go @@ -370,6 +370,9 @@ func TestLeader_LeftLeader(t *testing.T) { break } } + if leader == nil { + t.Fatalf("Should have a leader") + } leader.Leave() leader.Shutdown() time.Sleep(100 * time.Millisecond) diff --git a/consul/session_endpoint_test.go b/consul/session_endpoint_test.go index 7949752947..a745d16f10 100644 --- a/consul/session_endpoint_test.go +++ b/consul/session_endpoint_test.go @@ -5,6 +5,7 @@ import ( "github.com/hashicorp/consul/testutil" "os" "testing" + "time" ) func TestSessionEndpoint_Apply(t *testing.T) { @@ -223,6 +224,132 @@ func TestSessionEndpoint_List(t *testing.T) { } } +func TestSessionEndpoint_Renew(t *testing.T) { + dir1, s1 := testServer(t) + defer os.RemoveAll(dir1) + defer s1.Shutdown() + client := rpcClient(t, s1) + defer client.Close() + + testutil.WaitForLeader(t, client.Call, "dc1") + + s1.fsm.State().EnsureNode(1, structs.Node{"foo", "127.0.0.1"}) + ids := []string{} + for i := 0; i < 5; i++ { + arg := structs.SessionRequest{ + Datacenter: "dc1", + Op: structs.SessionCreate, + Session: structs.Session{ + Node: "foo", + TTL: "10s", + }, + } + var out string + if err := client.Call("Session.Apply", &arg, &out); err != nil { + t.Fatalf("err: %v", err) + } + ids = append(ids, out) + } + + getR := structs.DCSpecificRequest{ + Datacenter: "dc1", + } + + var sessions structs.IndexedSessions + if err := client.Call("Session.List", &getR, &sessions); err != nil { + t.Fatalf("err: %v", err) + } + + if sessions.Index == 0 { + t.Fatalf("Bad: %v", sessions) + } + if len(sessions.Sessions) != 5 { + t.Fatalf("Bad: %v", sessions.Sessions) + } + for i := 0; i < len(sessions.Sessions); i++ { + s := sessions.Sessions[i] + if !strContains(ids, s.ID) { + t.Fatalf("bad: %v", s) + } + if s.Node != "foo" { + t.Fatalf("bad: %v", s) + } + if s.TTL != "30s" { + t.Fatalf("bad: %v", s) + } + } + + // now sleep for ttl - since internally we use ttl*2 to destroy, this is ok + time.Sleep(10 * time.Second) + + // renew 3 out of 5 sessions + for i := 0; i < 3; i++ { + renewR := structs.SessionSpecificRequest{ + Datacenter: "dc1", + Session: ids[i], + } + var session structs.IndexedSessions + if err := client.Call("Session.Renew", &renewR, &session); err != nil { + t.Fatalf("err: %v", err) + } + + if session.Index == 0 { + t.Fatalf("Bad: %v", session) + } + if len(session.Sessions) != 1 { + t.Fatalf("Bad: %v", session.Sessions) + } + + s := session.Sessions[0] + if !strContains(ids, s.ID) { + t.Fatalf("bad: %v", s) + } + if s.Node != "foo" { + t.Fatalf("bad: %v", s) + } + } + + // now sleep for ttl*2 - 3 sessions should still be alive + time.Sleep(20 * time.Second) + + if err := client.Call("Session.List", &getR, &sessions); err != nil { + t.Fatalf("err: %v", err) + } + + if sessions.Index == 0 { + t.Fatalf("Bad: %v", sessions) + } + if len(sessions.Sessions) != 3 { + t.Fatalf("Bad: %v", sessions.Sessions) + } + for i := 0; i < len(sessions.Sessions); i++ { + s := sessions.Sessions[i] + if !strContains(ids, s.ID) { + t.Fatalf("bad: %v", s) + } + if s.Node != "foo" { + t.Fatalf("bad: %v", s) + } + if s.TTL != "30s" { + t.Fatalf("bad: %v", s) + } + } + + // now sleep again for ttl*2 - no sessions should still be alive + time.Sleep(20 * time.Second) + + if err := client.Call("Session.List", &getR, &sessions); err != nil { + t.Fatalf("err: %v", err) + } + + if sessions.Index != 0 { + t.Fatalf("Bad: %v", sessions) + } + if len(sessions.Sessions) != 0 { + t.Fatalf("Bad: %v", sessions.Sessions) + } +} + func TestSessionEndpoint_NodeSessions(t *testing.T) { dir1, s1 := testServer(t) defer os.RemoveAll(dir1) diff --git a/consul/state_store.go b/consul/state_store.go index 762d2e7519..f6a9add62d 100644 --- a/consul/state_store.go +++ b/consul/state_store.go @@ -1825,6 +1825,16 @@ func (s *StateSnapshot) SessionList() ([]*structs.Session, error) { return out, err } +// SessionListTTL is used to list all the open sessions +func (s *StateSnapshot) SessionListTTL() ([]*structs.Session, error) { + res, err := s.store.sessionTable.GetTxn(s.tx, "ttl") + out := make([]*structs.Session, len(res)) + for i, raw := range res { + out[i] = raw.(*structs.Session) + } + return out, err +} + // ACLList is used to list all of the ACLs func (s *StateSnapshot) ACLList() ([]*structs.ACL, error) { res, err := s.store.aclTable.GetTxn(s.tx, "id") diff --git a/consul/state_store_test.go b/consul/state_store_test.go index 0dba19abda..210ef24c59 100644 --- a/consul/state_store_test.go +++ b/consul/state_store_test.go @@ -703,13 +703,17 @@ func TestStoreSnapshot(t *testing.T) { if ok, err := store.KVSLock(18, d); err != nil || !ok { t.Fatalf("err: %v", err) } + session = &structs.Session{ID: generateUUID(), Node: "baz", TTL: "60s"} + if err := store.SessionCreate(19, session); err != nil { + t.Fatalf("err: %v", err) + } a1 := &structs.ACL{ ID: generateUUID(), Name: "User token", Type: structs.ACLTypeClient, } - if err := store.ACLSet(19, a1); err != nil { + if err := store.ACLSet(20, a1); err != nil { t.Fatalf("err: %v", err) } @@ -718,7 +722,7 @@ func TestStoreSnapshot(t *testing.T) { Name: "User token", Type: structs.ACLTypeClient, } - if err := store.ACLSet(20, a2); err != nil { + if err := store.ACLSet(21, a2); err != nil { t.Fatalf("err: %v", err) } @@ -730,7 +734,7 @@ func TestStoreSnapshot(t *testing.T) { defer snap.Close() // Check the last nodes - if idx := snap.LastIndex(); idx != 20 { + if idx := snap.LastIndex(); idx != 21 { t.Fatalf("bad: %v", idx) } @@ -785,15 +789,27 @@ func TestStoreSnapshot(t *testing.T) { t.Fatalf("missing KVS entries!") } - // Check there are 2 sessions + // Check there are 3 sessions sessions, err := snap.SessionList() if err != nil { t.Fatalf("err: %v", err) } - if len(sessions) != 2 { + if len(sessions) != 3 { t.Fatalf("missing sessions") } + // Check there is 1 session with TTL + sessions, err = snap.SessionListTTL() + if err != nil { + t.Fatalf("err: %v", err) + } + + if len(sessions) < 1 { + t.Fatalf("missing TTL session") + } else if len(sessions) > 1 { + t.Fatalf("too many TTL sessions") + } + // Check for an acl acls, err := snap.ACLList() if err != nil { @@ -804,13 +820,13 @@ func TestStoreSnapshot(t *testing.T) { } // Make some changes! - if err := store.EnsureService(21, "foo", &structs.NodeService{"db", "db", []string{"slave"}, 8000}); err != nil { + if err := store.EnsureService(22, "foo", &structs.NodeService{"db", "db", []string{"slave"}, 8000}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureService(22, "bar", &structs.NodeService{"db", "db", []string{"master"}, 8000}); err != nil { + if err := store.EnsureService(23, "bar", &structs.NodeService{"db", "db", []string{"master"}, 8000}); err != nil { t.Fatalf("err: %v", err) } - if err := store.EnsureNode(23, structs.Node{"baz", "127.0.0.3"}); err != nil { + if err := store.EnsureNode(24, structs.Node{"baz", "127.0.0.3"}); err != nil { t.Fatalf("err: %v", err) } checkAfter := &structs.HealthCheck{ @@ -820,16 +836,16 @@ func TestStoreSnapshot(t *testing.T) { Status: structs.HealthCritical, ServiceID: "db", } - if err := store.EnsureCheck(24, checkAfter); err != nil { + if err := store.EnsureCheck(26, checkAfter); err != nil { t.Fatalf("err: %v", err) } - if err := store.KVSDelete(25, "/web/b"); err != nil { + if err := store.KVSDelete(26, "/web/b"); err != nil { t.Fatalf("err: %v", err) } // Nuke an ACL - if err := store.ACLDelete(26, a1.ID); err != nil { + if err := store.ACLDelete(27, a1.ID); err != nil { t.Fatalf("err: %v", err) } @@ -883,12 +899,12 @@ func TestStoreSnapshot(t *testing.T) { t.Fatalf("missing KVS entries!") } - // Check there are 2 sessions + // Check there are 3 sessions sessions, err = snap.SessionList() if err != nil { t.Fatalf("err: %v", err) } - if len(sessions) != 2 { + if len(sessions) != 3 { t.Fatalf("missing sessions") }