func TestRTT_sortNodesByDistanceFrom(t *testing.T) { dir, server := testServer(t) defer os.RemoveAll(dir) defer server.Shutdown() codec := rpcClient(t, server) defer codec.Close() testutil.WaitForLeader(t, server.RPC, "dc1") seedCoordinates(t, codec, server) nodes := structs.Nodes{ &structs.Node{Node: "apple"}, &structs.Node{Node: "node1"}, &structs.Node{Node: "node2"}, &structs.Node{Node: "node3"}, &structs.Node{Node: "node4"}, &structs.Node{Node: "node5"}, } // The zero value for the source should not trigger any sorting. var source structs.QuerySource if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyNodeSort(t, nodes, "apple,node1,node2,node3,node4,node5") // Same for a source in some other DC. source.Node = "node1" source.Datacenter = "dc2" if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyNodeSort(t, nodes, "apple,node1,node2,node3,node4,node5") // Same for a source node in our DC that we have no coordinate for. source.Node = "apple" source.Datacenter = "dc1" if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyNodeSort(t, nodes, "apple,node1,node2,node3,node4,node5") // Set source to legit values relative to node1 but disable coordinates. source.Node = "node1" source.Datacenter = "dc1" server.config.DisableCoordinates = true if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyNodeSort(t, nodes, "apple,node1,node2,node3,node4,node5") // Now enable coordinates and sort relative to node1, note that apple // doesn't have any seeded coordinate info so it should end up at the // end, despite its lexical hegemony. server.config.DisableCoordinates = false if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyNodeSort(t, nodes, "node1,node4,node5,node2,node3,apple") }
// parseSource is used to parse the ?near=<node> query parameter, used for // sorting by RTT based on a source node. We set the source's DC to the target // DC in the request, if given, or else the agent's DC. func (s *HTTPServer) parseSource(req *http.Request, source *structs.QuerySource) { s.parseDC(req, &source.Datacenter) if node := req.URL.Query().Get("near"); node != "" { if node == "_agent" { source.Node = s.agent.config.NodeName } else { source.Node = node } } }
func TestRTT_sortNodesByDistanceFrom_CheckServiceNodes(t *testing.T) { dir, server := testServer(t) defer os.RemoveAll(dir) defer server.Shutdown() codec := rpcClient(t, server) defer codec.Close() testutil.WaitForLeader(t, server.RPC, "dc1") seedCoordinates(t, codec, server) nodes := structs.CheckServiceNodes{ structs.CheckServiceNode{Node: &structs.Node{Node: "apple"}}, structs.CheckServiceNode{Node: &structs.Node{Node: "node1"}}, structs.CheckServiceNode{Node: &structs.Node{Node: "node2"}}, structs.CheckServiceNode{Node: &structs.Node{Node: "node3"}}, structs.CheckServiceNode{Node: &structs.Node{Node: "node4"}}, structs.CheckServiceNode{Node: &structs.Node{Node: "node5"}}, } // Now sort relative to node1, note that apple doesn't have any // seeded coordinate info so it should end up at the end, despite // its lexical hegemony. var source structs.QuerySource source.Node = "node1" source.Datacenter = "dc1" if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyCheckServiceNodeSort(t, nodes, "node1,node4,node5,node2,node3,apple") // Try another sort from node2. Note that node5 and node3 are the // same distance away so the stable sort should preserve the order // they were in from the previous sort. source.Node = "node2" source.Datacenter = "dc1" if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyCheckServiceNodeSort(t, nodes, "node2,node5,node3,node4,node1,apple") // Let's exercise the stable sort explicitly to make sure we didn't // just get lucky. nodes[1], nodes[2] = nodes[2], nodes[1] if err := server.sortNodesByDistanceFrom(source, nodes); err != nil { t.Fatalf("err: %v", err) } verifyCheckServiceNodeSort(t, nodes, "node2,node3,node5,node4,node1,apple") }