func TestJoinUpdatesExistingPeers(t *testing.T) { test := quiz.Test(t) nodeA := testNode() defer nodeA.Close() nodeB := testNode() defer nodeB.Close() nodeC := testNode() defer nodeC.Close() httpclient.Put(nodeA.URL+"/peers/join", nodeB.URL) httpclient.Put(nodeA.URL+"/peers/join", nodeC.URL) var statusCode int var body string statusCode, body = httpclient.Get(nodeA.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(nodeB.URL) test.Expect(body).ToContain(nodeC.URL) statusCode, body = httpclient.Get(nodeB.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(nodeA.URL) test.Expect(body).ToContain(nodeC.URL) statusCode, body = httpclient.Get(nodeC.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(nodeA.URL) test.Expect(body).ToContain(nodeB.URL) }
func TestResizeCleansUpReplicas(t *testing.T) { test := quiz.Test(t) serverA := testServer() defer serverA.Close() serverB := testServer() defer serverB.Close() serverC := testServer() defer serverC.Close() serverD := testServer() defer serverD.Close() httpclient.Put(serverA.URL+"/peers/join", serverB.URL) httpclient.Put(serverA.URL+"/peers/join", serverC.URL) httpclient.Put(serverA.URL+"/settings/n", "1") // this key will be owned by c before and after d joins // however it's replicas will first by a then d key := "a" httpclient.Put(serverA.URL+"/data/"+key, "foo") httpclient.Put(serverA.URL+"/peers/join", serverD.URL) _, aHasKey := serverA.node.values[key] _, cHasKey := serverC.node.values[key] _, dHasKey := serverD.node.values[key] test.Expect(aHasKey).ToBeFalse() test.Expect(cHasKey).ToBeTrue() test.Expect(dHasKey).ToBeTrue() }
func TestFetchesAcrossNodes(t *testing.T) { test := quiz.Test(t) serverA := testServer() defer serverA.Close() serverB := testServer() defer serverB.Close() httpclient.Put(serverA.URL+"/peers/join", serverB.URL) // "a"'s hash will be stored on serverB key := "a" var statusCode int var body string statusCode, _ = httpclient.Put(serverA.URL+"/data/"+key, "bar") test.Expect(statusCode).ToEqual(201) statusCode, body = httpclient.Get(serverB.URL+"/data/"+key, "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual("bar") statusCode, body = httpclient.Get(serverA.URL+"/data/"+key, "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual("bar") }
func TestNodeSetNValueUpdatesPeersOnJoin(t *testing.T) { test := quiz.Test(t) nodeA := testNode() defer nodeA.Close() nodeB := testNode() defer nodeB.Close() nodeC := testNode() defer nodeC.Close() httpclient.Put(nodeA.URL+"/peers/join", nodeB.URL) statusCode, _ := httpclient.Put(nodeA.URL+"/settings/n", "1") test.Expect(statusCode).ToEqual(201) httpclient.Put(nodeA.URL+"/peers/join", nodeC.URL) _, body := httpclient.Get(nodeA.URL+"/stats", "") test.Expect(body).ToContain(`"nValue":1`) _, body = httpclient.Get(nodeB.URL+"/stats", "") test.Expect(body).ToContain(`"nValue":1`) _, body = httpclient.Get(nodeC.URL+"/stats", "") test.Expect(body).ToContain(`"nValue":1`) }
func TestUpdateKey(t *testing.T) { test := quiz.Test(t) server := testServer() defer server.Close() httpclient.Put(server.URL+"/data/mykey", "bar") httpclient.Put(server.URL+"/data/mykey", "baz") statusCode, body := httpclient.Get(server.URL+"/data/mykey", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual("baz") }
func TestGetMultiplePeers(t *testing.T) { test := quiz.Test(t) node := testNode() defer node.Close() httpclient.Put(node.URL+"/peers", "peer1.url") httpclient.Put(node.URL+"/peers", "peer2.url") statusCode, body := httpclient.Get(node.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual(`{"peers":["peer1.url","peer2.url"]}`) }
func TestAddPeerFailsOnMultipleCalls(t *testing.T) { test := quiz.Test(t) node := testNode() defer node.Close() var statusCode int statusCode, _ = httpclient.Put(node.URL+"/peers", "peer.url") test.Expect(statusCode).ToEqual(201) statusCode, _ = httpclient.Put(node.URL+"/peers", "peer.url") test.Expect(statusCode).ToEqual(409) }
func TestFailedWriteUpdatesPeerList(t *testing.T) { test := quiz.Test(t) serverA := testServer() defer serverA.Close() serverB := testServer() peerURL := serverB.URL key := "a" httpclient.Put(serverA.URL+"/peers/join", serverB.URL) serverB.Close() httpclient.Put(serverA.URL+"/data/"+key, "foo") _, body := httpclient.Get(serverA.URL+"/peers", "") test.Expect(body).ToContain("dead:" + peerURL) }
func (server *Server) handoffKey(address string, key string, value string) { server.logger.Printf("Passing off '%s'->'%s' to %s", key, value, address) statusCode, _ := httpclient.Put(address+"/set/"+key, value) if statusCode == 0 { server.NotifyDown(address) } }
func TestErrorOnNGreaterThanTotalPeers(t *testing.T) { test := quiz.Test(t) nodeA := testNode() defer nodeA.Close() statusCode, _ := httpclient.Put(nodeA.URL+"/settings/n", "5") test.Expect(statusCode).ToEqual(422) }
func TestErrorOnNonIntForNValue(t *testing.T) { test := quiz.Test(t) nodeA := testNode() defer nodeA.Close() statusCode, _ := httpclient.Put(nodeA.URL+"/settings/n", "notint") test.Expect(statusCode).ToEqual(422) }
func (peer *Peer) evaluateKeyOwnership() { for key, value := range peer.values { owner := peer.ring.NodeForKey(key) if owner.GetName() != peer.url { httpclient.Put(owner.GetName()+"/data/"+key, value) delete(peer.values, key) } } }
func TestNodeSetRing(t *testing.T) { test := quiz.Test(t) node := testNode() defer node.Close() statusCode, _ := httpclient.Put(node.URL+"/ring", `{"ring":["`+node.URL+`","b","c"]}`) test.Expect(statusCode).ToEqual(201) _, body := httpclient.Get(node.URL+"/stats", "") test.Expect(body).ToContain(`"ring":["` + node.URL + `","b","c"]`) }
func (peer *Peer) join(newPeer string) { for _, p := range peer.Peers { httpclient.Put(p+"/peers", newPeer) httpclient.Put(newPeer+"/peers", p) } peer.addPeer(newPeer) peer.ring.AddNode(newPeer) httpclient.Put(newPeer+"/peers", peer.url) nValue := strconv.Itoa(peer.ring.GetNValue()) httpclient.Put(newPeer+"/settings/set/n", nValue) for _, p := range peer.Peers { nodes := httpclient.JsonData{ "ring": peer.ring.GetNodes(), } httpclient.Put(p+"/ring", nodes.Encode()) } peer.evaluateKeyOwnership() }
func TestStatsKeys(t *testing.T) { test := quiz.Test(t) server := testServer() defer server.Close() httpclient.Put(server.URL+"/data/mykey", "bar") statusCode, body := httpclient.Get(server.URL+"/stats/keys", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(`"count":1`) test.Expect(body).ToContain(`"data":{"mykey":"bar"}`) }
func TestReplicationOnPut(t *testing.T) { test := quiz.Test(t) serverA := testServer() defer serverA.Close() serverB := testServer() defer serverB.Close() httpclient.Put(serverA.URL+"/peers/join", serverB.URL) httpclient.Put(serverA.URL+"/settings/n", "1") // "a"'s hash will be stored on serverB key := "a" httpclient.Put(serverA.URL+"/data/"+key, "bar") _, aHasKey := serverA.node.values["a"] _, bHasKey := serverB.node.values["a"] test.Expect(aHasKey).ToBeTrue() test.Expect(bHasKey).ToBeTrue() }
func TestAddPeer(t *testing.T) { test := quiz.Test(t) node := testNode() defer node.Close() statusCode, _ := httpclient.Put(node.URL+"/peers", "peer.url") test.Expect(statusCode).ToEqual(201) statusCode, body := httpclient.Get(node.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual(`{"peers":["peer.url"]}`) }
func TestMoveKeys(t *testing.T) { test := quiz.Test(t) serverA := testServer() defer serverA.Close() serverB := testServer() defer serverB.Close() serverC := testServer() defer serverC.Close() httpclient.Put(serverA.URL+"/peers/join", serverB.URL) // this key will first be on server B then will be on server C key := "b" httpclient.Put(serverA.URL+"/data/"+key, "foo") httpclient.Put(serverA.URL+"/peers/join", serverC.URL) _, bHasKey := serverB.node.values[key] _, cHasKey := serverC.node.values[key] test.Expect(bHasKey).ToBeFalse() test.Expect(cHasKey).ToBeTrue() }
func TestJoinCallsBack(t *testing.T) { test := quiz.Test(t) nodeA := testNode() defer nodeA.Close() nodeB := testNode() defer nodeB.Close() httpclient.Put(nodeA.URL+"/peers/join", nodeB.URL) var statusCode int var body string statusCode, body = httpclient.Get(nodeA.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual(`{"peers":["` + nodeB.URL + `"]}`) statusCode, body = httpclient.Get(nodeB.URL+"/peers", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToEqual(`{"peers":["` + nodeA.URL + `"]}`) }
func TestAddNodeUpdatesRing(t *testing.T) { test := quiz.Test(t) var statusCode int var body string nodeA := testNode() defer nodeA.Close() nodeB := testNode() defer nodeB.Close() httpclient.Put(nodeA.URL+"/peers/join", nodeB.URL) statusCode, body = httpclient.Get(nodeA.URL+"/stats", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(`"vnodeCount":512`) test.Expect(body).ToContain(`"vnodeStart":0`) statusCode, body = httpclient.Get(nodeB.URL+"/stats", "") test.Expect(statusCode).ToEqual(200) test.Expect(body).ToContain(`"vnodeCount":512`) test.Expect(body).ToContain(`"vnodeStart":2147483137`) }
func (peer *Peer) Handler(m *pat.PatternServeMux) { m.Get("/stats", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { stats := httpclient.JsonData{ "ring": peer.ring.GetNodes(), "vnodeCount": peer.node.VnodeCount(), "vnodeSize": peer.node.VnodeSize(), "vnodeStart": peer.node.VnodeStart(), "nValue": peer.ring.GetNValue(), } w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) io.WriteString(w, stats.Encode()) })) m.Put("/ring", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { body, _ := ioutil.ReadAll(request.Body) data := map[string][]string{} json.Unmarshal(body, &data) peer.ring.SetNodes(data["ring"]) peer.node = peer.ring.Get(peer.url) peer.evaluateKeyOwnership() w.WriteHeader(201) })) m.Put("/settings/set/n", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { body, _ := ioutil.ReadAll(request.Body) n, err := strconv.Atoi(string(body)) if err == nil { peer.ring.SetNValue(n) w.WriteHeader(201) } else { w.WriteHeader(422) } })) m.Put("/settings/n", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { body, _ := ioutil.ReadAll(request.Body) n, err := strconv.Atoi(string(body)) if err == nil && n < peer.peerCount() { peer.ring.SetNValue(n) for _, p := range peer.Peers { httpclient.Put(p+"/settings/set/n", string(body)) } w.WriteHeader(201) } else { w.WriteHeader(422) } })) m.Put("/peers", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { body, _ := ioutil.ReadAll(request.Body) newPeerURL := string(body) if peer.peerExists(newPeerURL) { w.WriteHeader(409) } else { peer.addPeer(newPeerURL) w.WriteHeader(201) } })) m.Put("/peers/join", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { body, _ := ioutil.ReadAll(request.Body) newPeerURL := string(body) peer.logger.Printf("%s requesting to join", newPeerURL) if peer.peerExists(newPeerURL) { w.WriteHeader(409) } else { peer.join(newPeerURL) w.WriteHeader(201) } })) m.Get("/peers", http.HandlerFunc(func(w http.ResponseWriter, request *http.Request) { if peer.HasPeer() { w.Header().Set("Content-Type", "application/json") w.WriteHeader(200) io.WriteString(w, httpclient.JsonData{"peers": peer.Peers}.Encode()) } else { w.WriteHeader(404) } })) }