api_topologies_test.go 7.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252
  1. package app_test
  2. import (
  3. "bytes"
  4. "context"
  5. "net/http/httptest"
  6. "net/url"
  7. "testing"
  8. "time"
  9. "github.com/gorilla/mux"
  10. "github.com/ugorji/go/codec"
  11. apiv1 "k8s.io/api/core/v1"
  12. metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
  13. "github.com/weaveworks/common/test"
  14. "github.com/weaveworks/scope/app"
  15. "github.com/weaveworks/scope/probe/docker"
  16. "github.com/weaveworks/scope/probe/kubernetes"
  17. "github.com/weaveworks/scope/render"
  18. "github.com/weaveworks/scope/render/detailed"
  19. "github.com/weaveworks/scope/render/expected"
  20. "github.com/weaveworks/scope/report"
  21. "github.com/weaveworks/scope/test/fixture"
  22. "github.com/weaveworks/scope/test/reflect"
  23. "github.com/weaveworks/scope/test/utils"
  24. )
  25. const (
  26. systemGroupID = "system"
  27. customAPITopologyOptionFilterID = "containerLabelFilter0"
  28. )
  29. func TestAPITopology(t *testing.T) {
  30. ts := topologyServer()
  31. defer ts.Close()
  32. body := getRawJSON(t, ts, "/api/topology")
  33. var topologies []app.APITopologyDesc
  34. decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
  35. if err := decoder.Decode(&topologies); err != nil {
  36. t.Fatalf("JSON parse error: %s", err)
  37. }
  38. equals(t, 6, len(topologies))
  39. for _, topology := range topologies {
  40. is200(t, ts, topology.URL)
  41. for _, subTopology := range topology.SubTopologies {
  42. is200(t, ts, subTopology.URL)
  43. }
  44. // TODO: add ECS nodes in report fixture
  45. if topology.Name == "Tasks" || topology.Name == "Services" {
  46. continue
  47. }
  48. if have := topology.Stats.EdgeCount; have <= 0 {
  49. t.Errorf("EdgeCount isn't positive for %s: %d", topology.Name, have)
  50. }
  51. if have := topology.Stats.NodeCount; have <= 0 {
  52. t.Errorf("NodeCount isn't positive for %s: %d", topology.Name, have)
  53. }
  54. if have := topology.Stats.NonpseudoNodeCount; have <= 0 {
  55. t.Errorf("NonpseudoNodeCount isn't positive for %s: %d", topology.Name, have)
  56. }
  57. }
  58. }
  59. func TestContainerLabelFilter(t *testing.T) {
  60. topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, false)
  61. if err != nil {
  62. t.Fatalf("Topology Registry Report error: %s", err)
  63. }
  64. // only the filtered container with fixture.TestLabelKey1 should be present
  65. equals(t, 1, len(topologySummaries))
  66. for key := range topologySummaries {
  67. equals(t, report.MakeContainerNodeID(fixture.ClientContainerID), key)
  68. }
  69. }
  70. func TestContainerLabelFilterExclude(t *testing.T) {
  71. topologySummaries, err := getTestContainerLabelFilterTopologySummary(t, true)
  72. if err != nil {
  73. t.Fatalf("Topology Registry Report error: %s", err)
  74. }
  75. // all containers but the excluded container should be present
  76. for key := range topologySummaries {
  77. id := report.MakeContainerNodeID(fixture.ServerContainerNodeID)
  78. if id == key {
  79. t.Errorf("Didn't expect to find %q in report", id)
  80. }
  81. }
  82. }
  83. func TestRendererForTopologyWithFiltering(t *testing.T) {
  84. ts := topologyServer()
  85. defer ts.Close()
  86. topologyRegistry := app.MakeRegistry()
  87. option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", render.IsApplication, false)
  88. topologyRegistry.AddContainerFilters(option)
  89. urlvalues := url.Values{}
  90. urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
  91. urlvalues.Set("stopped", "running")
  92. urlvalues.Set("pseudo", "hide")
  93. renderer, filter, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
  94. if err != nil {
  95. t.Fatalf("Topology Registry Report error: %s", err)
  96. }
  97. input := fixture.Report.Copy()
  98. input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
  99. docker.LabelPrefix + "works.weave.role": "system",
  100. })
  101. have := utils.Prune(render.Render(context.Background(), input, renderer, filter).Nodes)
  102. want := utils.Prune(expected.RenderedContainers.Copy())
  103. delete(want, fixture.ClientContainerNodeID)
  104. delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
  105. delete(want, render.OutgoingInternetID)
  106. if !reflect.DeepEqual(want, have) {
  107. t.Error(test.Diff(want, have))
  108. }
  109. }
  110. func TestRendererForTopologyNoFiltering(t *testing.T) {
  111. ts := topologyServer()
  112. defer ts.Close()
  113. topologyRegistry := app.MakeRegistry()
  114. option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", nil, false)
  115. topologyRegistry.AddContainerFilters(option)
  116. urlvalues := url.Values{}
  117. urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
  118. urlvalues.Set("stopped", "running")
  119. urlvalues.Set("pseudo", "hide")
  120. renderer, filter, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
  121. if err != nil {
  122. t.Fatalf("Topology Registry Report error: %s", err)
  123. }
  124. input := fixture.Report.Copy()
  125. input.Container.Nodes[fixture.ClientContainerNodeID] = input.Container.Nodes[fixture.ClientContainerNodeID].WithLatests(map[string]string{
  126. docker.LabelPrefix + "works.weave.role": "system",
  127. })
  128. have := utils.Prune(render.Render(context.Background(), input, renderer, filter).Nodes)
  129. want := utils.Prune(expected.RenderedContainers.Copy())
  130. delete(want, render.MakePseudoNodeID(render.UncontainedID, fixture.ServerHostID))
  131. delete(want, render.OutgoingInternetID)
  132. if !reflect.DeepEqual(want, have) {
  133. t.Error(test.Diff(want, have))
  134. }
  135. }
  136. func getTestContainerLabelFilterTopologySummary(t *testing.T, exclude bool) (detailed.NodeSummaries, error) {
  137. ts := topologyServer()
  138. defer ts.Close()
  139. var (
  140. topologyRegistry = app.MakeRegistry()
  141. filterFunc render.FilterFunc
  142. )
  143. if exclude == true {
  144. filterFunc = render.DoesNotHaveLabel(fixture.TestLabelKey2, fixture.ApplicationLabelValue2)
  145. } else {
  146. filterFunc = render.HasLabel(fixture.TestLabelKey1, fixture.ApplicationLabelValue1)
  147. }
  148. option := app.MakeAPITopologyOption(customAPITopologyOptionFilterID, "title", filterFunc, false)
  149. topologyRegistry.AddContainerFilters(option)
  150. urlvalues := url.Values{}
  151. urlvalues.Set(systemGroupID, customAPITopologyOptionFilterID)
  152. urlvalues.Set("stopped", "running")
  153. urlvalues.Set("pseudo", "hide")
  154. renderer, filter, err := topologyRegistry.RendererForTopology("containers", urlvalues, fixture.Report)
  155. if err != nil {
  156. return nil, err
  157. }
  158. ctx := context.Background()
  159. return detailed.Summaries(ctx, detailed.RenderContext{Report: fixture.Report}, render.Render(ctx, fixture.Report, renderer, filter).Nodes), nil
  160. }
  161. func TestAPITopologyAddsKubernetes(t *testing.T) {
  162. router := mux.NewRouter()
  163. c := app.NewCollector(1 * time.Minute)
  164. app.RegisterReportPostHandler(c, router)
  165. app.RegisterTopologyRoutes(router, c, map[string]bool{"foo_capability": true})
  166. ts := httptest.NewServer(router)
  167. defer ts.Close()
  168. body := getRawJSON(t, ts, "/api/topology")
  169. var topologies []app.APITopologyDesc
  170. decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{})
  171. if err := decoder.Decode(&topologies); err != nil {
  172. t.Fatalf("JSON parse error: %s", err)
  173. }
  174. equals(t, 6, len(topologies))
  175. // Enable the kubernetes topologies
  176. rpt := report.MakeReport()
  177. rpt.Pod = report.MakeTopology()
  178. rpt.Pod.Nodes[fixture.ClientPodNodeID] = kubernetes.NewPod(&apiv1.Pod{
  179. ObjectMeta: metav1.ObjectMeta{
  180. Name: "pong-a",
  181. Namespace: "ping",
  182. Labels: map[string]string{"ponger": "true"},
  183. },
  184. Status: apiv1.PodStatus{
  185. HostIP: "1.2.3.4",
  186. ContainerStatuses: []apiv1.ContainerStatus{
  187. {ContainerID: "container1"},
  188. {ContainerID: "container2"},
  189. },
  190. },
  191. Spec: apiv1.PodSpec{
  192. SecurityContext: &apiv1.PodSecurityContext{},
  193. },
  194. }).GetNode("")
  195. buf := &bytes.Buffer{}
  196. encoder := codec.NewEncoder(buf, &codec.MsgpackHandle{})
  197. if err := encoder.Encode(rpt); err != nil {
  198. t.Fatalf("Msgpack encoding error: %s", err)
  199. }
  200. checkRequest(t, ts, "POST", "/api/report", buf.Bytes())
  201. body = getRawJSON(t, ts, "/api/topology")
  202. decoder = codec.NewDecoderBytes(body, &codec.JsonHandle{})
  203. if err := decoder.Decode(&topologies); err != nil {
  204. t.Fatalf("JSON parse error: %s", err)
  205. }
  206. equals(t, 6, len(topologies))
  207. found := false
  208. for _, topology := range topologies {
  209. if topology.Name == "Pods" {
  210. found = true
  211. break
  212. }
  213. }
  214. if !found {
  215. t.Error("Could not find pods topology")
  216. }
  217. }