func TestCollector(t *testing.T) { window := time.Millisecond c := app.NewCollector(window) r1 := report.MakeReport() r1.Endpoint.AddNode("foo", report.MakeNode()) r2 := report.MakeReport() r2.Endpoint.AddNode("bar", report.MakeNode()) if want, have := report.MakeReport(), c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(r1) if want, have := r1, c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(r2) merged := report.MakeReport() merged = merged.Merge(r1) merged = merged.Merge(r2) if want, have := merged, c.Report(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
// Main runs the app func appMain() { var ( window = flag.Duration("window", 15*time.Second, "window") listen = flag.String("http.address", ":"+strconv.Itoa(xfer.AppPort), "webserver listen address") logPrefix = flag.String("log.prefix", "<app>", "prefix for each log line") ) flag.Parse() if !strings.HasSuffix(*logPrefix, " ") { *logPrefix += " " } log.SetPrefix(*logPrefix) defer log.Print("app exiting") rand.Seed(time.Now().UnixNano()) app.UniqueID = strconv.FormatInt(rand.Int63(), 16) app.Version = version log.Printf("app starting, version %s, ID %s", app.Version, app.UniqueID) handler := router(app.NewCollector(*window)) go func() { log.Printf("listening on %s", *listen) log.Print(http.ListenAndServe(*listen, handler)) }() common.SignalHandlerLoop() }
func TestAPITopologyAddsKubernetes(t *testing.T) { router := mux.NewRouter() c := app.NewCollector(1 * time.Minute) app.RegisterReportPostHandler(c, router) app.RegisterTopologyRoutes(router, c) ts := httptest.NewServer(router) defer ts.Close() body := getRawJSON(t, ts, "/api/topology") var topologies []app.APITopologyDesc decoder := codec.NewDecoderBytes(body, &codec.JsonHandle{}) if err := decoder.Decode(&topologies); err != nil { t.Fatalf("JSON parse error: %s", err) } equals(t, 4, len(topologies)) // Enable the kubernetes topologies rpt := report.MakeReport() rpt.Pod = report.MakeTopology() rpt.Pod.Nodes[fixture.ClientPodNodeID] = kubernetes.NewPod(&api.Pod{ ObjectMeta: api.ObjectMeta{ Name: "pong-a", Namespace: "ping", Labels: map[string]string{"ponger": "true"}, }, Status: api.PodStatus{ HostIP: "1.2.3.4", ContainerStatuses: []api.ContainerStatus{ {ContainerID: "container1"}, {ContainerID: "container2"}, }, }, }).GetNode("") buf := &bytes.Buffer{} encoder := codec.NewEncoder(buf, &codec.MsgpackHandle{}) if err := encoder.Encode(rpt); err != nil { t.Fatalf("GOB encoding error: %s", err) } checkRequest(t, ts, "POST", "/api/report", buf.Bytes()) body = getRawJSON(t, ts, "/api/topology") decoder = codec.NewDecoderBytes(body, &codec.JsonHandle{}) if err := decoder.Decode(&topologies); err != nil { t.Fatalf("JSON parse error: %s", err) } equals(t, 4, len(topologies)) found := false for _, topology := range topologies { if topology.Name == "Pods" { found = true break } } if !found { t.Error("Could not find pods topology") } }
// Main runs the app func appMain() { var ( window = flag.Duration("window", 15*time.Second, "window") listen = flag.String("http.address", ":"+strconv.Itoa(xfer.AppPort), "webserver listen address") logLevel = flag.String("log.level", "info", "logging threshold level: debug|info|warn|error|fatal|panic") logPrefix = flag.String("log.prefix", "<app>", "prefix for each log line") weaveAddr = flag.String("weave.addr", app.DefaultWeaveURL, "Address on which to contact WeaveDNS") weaveHostname = flag.String("weave.hostname", app.DefaultHostname, "Hostname to advertise in WeaveDNS") containerName = flag.String("container.name", app.DefaultContainerName, "Name of this container (to lookup container ID)") dockerEndpoint = flag.String("docker", app.DefaultDockerEndpoint, "Location of docker endpoint (to lookup container ID)") ) flag.Parse() setLogLevel(*logLevel) setLogFormatter(*logPrefix) defer log.Info("app exiting") // Start background version checking checkpoint.CheckInterval(&checkpoint.CheckParams{ Product: "scope-app", Version: app.Version, SignatureFile: signatureFile, }, versionCheckPeriod, func(r *checkpoint.CheckResponse, err error) { if r.Outdated { log.Infof("Scope version %s is available; please update at %s", r.CurrentVersion, r.CurrentDownloadURL) } }) rand.Seed(time.Now().UnixNano()) app.UniqueID = strconv.FormatInt(rand.Int63(), 16) app.Version = version log.Infof("app starting, version %s, ID %s", app.Version, app.UniqueID) // If user supplied a weave router address, periodically try and register // out IP address in WeaveDNS. if *weaveAddr != "" { weave, err := newWeavePublisher( *dockerEndpoint, *weaveAddr, *weaveHostname, *containerName) if err != nil { log.Println("Failed to start weave integration:", err) } else { defer weave.Stop() } } handler := router(app.NewCollector(*window)) go func() { log.Infof("listening on %s", *listen) log.Info(http.ListenAndServe(*listen, handler)) }() common.SignalHandlerLoop() }
func TestReportPostHandler(t *testing.T) { test := func(contentType string, encoder func(interface{}) ([]byte, error)) { router := mux.NewRouter() c := app.NewCollector(1 * time.Minute) app.RegisterReportPostHandler(c, router) ts := httptest.NewServer(router) defer ts.Close() b, err := encoder(fixture.Report) if err != nil { t.Fatalf("Content-Type %s: %s", contentType, err) } req, err := http.NewRequest("POST", ts.URL+"/api/report", bytes.NewReader(b)) if err != nil { t.Fatalf("Error posting report: %v", err) } req.Header.Set("Content-Type", contentType) resp, err := http.DefaultClient.Do(req) if err != nil { t.Fatalf("Error posting report %v", err) } _, err = ioutil.ReadAll(resp.Body) resp.Body.Close() if err != nil { t.Fatalf("Error posting report: %v", err) } if resp.StatusCode != http.StatusOK { t.Fatalf("Error posting report: %d", resp.StatusCode) } ctx := context.Background() report, err := c.Report(ctx) if err != nil { t.Error(err) } if want, have := fixture.Report.Endpoint.Nodes, report.Endpoint.Nodes; len(have) == 0 || len(want) != len(have) { t.Fatalf("Content-Type %s: %v", contentType, test.Diff(have, want)) } } test("application/json", func(v interface{}) ([]byte, error) { buf := &bytes.Buffer{} err := codec.NewEncoder(buf, &codec.JsonHandle{}).Encode(v) return buf.Bytes(), err }) test("application/msgpack", func(v interface{}) ([]byte, error) { buf := &bytes.Buffer{} err := codec.NewEncoder(buf, &codec.MsgpackHandle{}).Encode(v) return buf.Bytes(), err }) }
func TestCollectorWait(t *testing.T) { window := time.Millisecond c := app.NewCollector(window) waiter := make(chan struct{}, 1) c.WaitOn(waiter) defer c.UnWait(waiter) c.(interface { Broadcast() }).Broadcast() select { case <-waiter: default: t.Fatal("Didn't unblock") } }
func TestCollectorExpire(t *testing.T) { now := time.Now() mtime.NowForce(now) defer mtime.NowReset() ctx := context.Background() window := 10 * time.Second c := app.NewCollector(window) // 1st check the collector is empty have, err := c.Report(ctx) if err != nil { t.Error(err) } if want := report.MakeReport(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } // Now check an added report is returned r1 := report.MakeReport() r1.Endpoint.AddNode(report.MakeNode("foo")) c.Add(ctx, r1) have, err = c.Report(ctx) if err != nil { t.Error(err) } if want := r1; !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } // Finally move time forward to expire the report mtime.NowForce(now.Add(window)) have, err = c.Report(ctx) if err != nil { t.Error(err) } if want := report.MakeReport(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func TestCollector(t *testing.T) { ctx := context.Background() window := 10 * time.Second c := app.NewCollector(window) r1 := report.MakeReport() r1.Endpoint.AddNode(report.MakeNode("foo")) r2 := report.MakeReport() r2.Endpoint.AddNode(report.MakeNode("foo")) have, err := c.Report(ctx) if err != nil { t.Error(err) } if want := report.MakeReport(); !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(ctx, r1) have, err = c.Report(ctx) if err != nil { t.Error(err) } if want := r1; !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } c.Add(ctx, r2) merged := report.MakeReport() merged = merged.Merge(r1) merged = merged.Merge(r2) have, err = c.Report(ctx) if err != nil { t.Error(err) } if want := merged; !reflect.DeepEqual(want, have) { t.Error(test.Diff(want, have)) } }
func collectorFactory(userIDer multitenant.UserIDer, collectorURL, s3URL, natsHostname string, window time.Duration, createTables bool) (app.Collector, error) { if collectorURL == "local" { return app.NewCollector(window), nil } parsed, err := url.Parse(collectorURL) if err != nil { return nil, err } if parsed.Scheme == "dynamodb" { s3, err := url.Parse(s3URL) if err != nil { return nil, fmt.Errorf("Valid URL for s3 required: %v", err) } dynamoDBConfig, err := awsConfigFromURL(parsed) if err != nil { return nil, err } s3Config, err := awsConfigFromURL(s3) if err != nil { return nil, err } tableName := strings.TrimPrefix(parsed.Path, "/") bucketName := strings.TrimPrefix(s3.Path, "/") dynamoCollector, err := multitenant.NewDynamoDBCollector( userIDer, dynamoDBConfig, s3Config, tableName, bucketName, natsHostname) if err != nil { return nil, err } if createTables { if err := dynamoCollector.CreateTables(); err != nil { return nil, err } } return dynamoCollector, nil } return nil, fmt.Errorf("Invalid collector '%s'", collectorURL) }