Example #1
0
func TestMeasureQueues(t *testing.T) {
	// Setup Listen
	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26081",
	}
	var tiers []coco.Tier
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)

	poll(t, apiConfig.Bind)

	// Setup Measure
	chans := map[string]chan collectd.Packet{
		"a": make(chan collectd.Packet, 1000),
		"b": make(chan collectd.Packet, 1000),
		"c": make(chan collectd.Packet, 1000),
	}
	measureConfig := coco.MeasureConfig{
		TickInterval: *new(coco.Duration),
	}
	measureConfig.TickInterval.UnmarshalText([]byte("10ms"))
	go coco.Measure(measureConfig, chans, &tiers)

	// Test pushing packets
	for _, c := range chans {
		for i := 0; i < 950; i++ {
			c <- collectd.Packet{}
		}
	}

	time.Sleep(10 * time.Millisecond)

	// Test
	resp, err := http.Get("http://127.0.0.1:26081/debug/vars")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Errorf("Error when decoding JSON %+v.", err)
		t.Errorf("Response body: %s", string(body))
		t.FailNow()
	}

	counts := result["coco"].(map[string]interface{})["queues"].(map[string]interface{})
	expected := 950
	for k, v := range counts {
		c := int(v.(float64))
		if c != expected {
			t.Errorf("Expected %s to equal %d, got %.2f", k, expected, v)
		}
	}
}
Example #2
0
func TestBlacklisted(t *testing.T) {
	// Setup Filter
	config := coco.FilterConfig{
		Blacklist: "/(vmem|irq|entropy|users)/",
	}
	raw := make(chan collectd.Packet)
	filtered := make(chan collectd.Packet)
	items := make(chan coco.BlacklistItem, 1000000)
	go coco.Filter(config, raw, filtered, items)

	// Setup blacklist
	blacklisted := map[string]map[string]int64{}
	go coco.Blacklist(items, &blacklisted)

	// Setup Api
	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26082",
	}
	var tiers []coco.Tier
	go coco.Api(apiConfig, &tiers, &blacklisted)
	poll(t, apiConfig.Bind)

	// Push 10 metrics through that should be blacklisted
	for i := 0; i < 10; i++ {
		raw <- collectd.Packet{
			Hostname:     "foo",
			Plugin:       "irq",
			Type:         "irq",
			TypeInstance: strconv.Itoa(i),
		}
	}

	// Fetch blacklisted metrics
	resp, err := http.Get("http://127.0.0.1:26082/blacklisted")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Errorf("Error when decoding JSON %+v.", err)
		t.Errorf("Response body: %s", string(body))
		t.FailNow()
	}

	// Test the metrics have been blacklisted
	count := len(result["foo"].(map[string]interface{}))
	expected := 10
	if count != expected {
		t.Errorf("Expected %d blacklisted metrics, got %d", count, expected)
	}
}
Example #3
0
func TestSendWhenMissingConnection(t *testing.T) {
	// Setup tiers
	tierConfig := make(map[string]coco.TierConfig)
	tierConfig["a"] = coco.TierConfig{Targets: []string{"127.0.0.1:29000", "a.example:29000", "b.example:29000", "c.example:29000"}}

	var tiers []coco.Tier
	for k, v := range tierConfig {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	// Launch Api so we can query expvars
	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26880",
	}
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)

	poll(t, apiConfig.Bind)

	// Launch Send so we can test dispatch behaviour
	filtered := make(chan collectd.Packet)
	go coco.Send(&tiers, filtered)

	// Query the expvars
	var actual float64
	var expected float64
	var vars map[string]interface{}
	vars = fetchExpvar(t, apiConfig.Bind)
	actual = vars["coco"].(map[string]interface{})["errors"].(map[string]interface{})["send.disconnected"].(float64)
	expected = 0
	if actual != expected {
		t.Fatalf("Expected coco.errors.send.disconnected to be %d, was %d", expected, actual)
	}

	// Dispatch a single packet
	send := collectd.Packet{
		Hostname: "foo",
		Plugin:   "load",
		Type:     "load",
	}
	filtered <- send

	// Check the failure count has increased
	vars = fetchExpvar(t, apiConfig.Bind)
	actual = vars["coco"].(map[string]interface{})["errors"].(map[string]interface{})["send.disconnected"].(float64)
	expected = 1
	if actual != expected {
		t.Fatalf("Expected coco.errors.send.disconnected to be %d, was %d", expected, actual)
	}
}
Example #4
0
func TestVirtualReplicasMagic(t *testing.T) {
	// Setup tiers
	tierConfig := make(map[string]coco.TierConfig)
	tierConfig["a"] = coco.TierConfig{Targets: []string{"127.0.0.1:25811", "127.0.0.1:25812", "127.0.0.1:25813"}}
	tierConfig["b"] = coco.TierConfig{Targets: []string{"127.0.0.1:25821", "127.0.0.1:25822", "127.0.0.1:25823"}}
	tierConfig["c"] = coco.TierConfig{Targets: []string{"127.0.0.1:25831", "127.0.0.1:25832", "127.0.0.1:25833"}}

	var tiers []coco.Tier
	for k, v := range tierConfig {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	// Setup Send
	filtered := make(chan collectd.Packet)
	go coco.Send(&tiers, filtered)

	// Setup Api
	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26840",
	}
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)
	poll(t, apiConfig.Bind)

	// Fetch exposed tiers
	resp, err := http.Get("http://127.0.0.1:26840/tiers")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	//var result []coco.Tier
	var result []map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Errorf("Error when decoding JSON %+v.", err)
		t.Errorf("Response body: %s", string(body))
		t.FailNow()
	}

	for _, tier := range result {
		if tier["virtual_replicas"] == nil {
			t.Errorf("tier '%s' doesn't expose virtual replicas", tier["name"])
		}
		t.Logf("tier '%s' has %.0f virtual replicas", tier["name"], tier["virtual_replicas"])
	}
}
Example #5
0
func TestTierLookup(t *testing.T) {
	// Setup sender
	tierConfig := make(map[string]coco.TierConfig)
	tierConfig["a"] = coco.TierConfig{Targets: []string{"127.0.0.1:25887"}}
	tierConfig["b"] = coco.TierConfig{Targets: []string{"127.0.0.1:25888"}}
	tierConfig["c"] = coco.TierConfig{Targets: []string{"127.0.0.1:25889"}}

	var tiers []coco.Tier
	for k, v := range tierConfig {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	filtered := make(chan collectd.Packet)
	go coco.Send(&tiers, filtered)

	// Setup API
	apiConfig := coco.ApiConfig{
		Bind: "0.0.0.0:25999",
	}
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)

	poll(t, apiConfig.Bind)

	// Test
	resp, err := http.Get("http://127.0.0.1:25999/lookup?name=abc")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	var result map[string]string
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Fatalf("Error when decoding JSON %+v. Response body: %s", err, string(body))
	}

	for k, v := range tierConfig {
		if result[k] != v.Targets[0] {
			t.Errorf("Couldn't find tier %s in response: %s", k, string(body))
		}
	}
}
Example #6
0
func main() {
	kingpin.Version("1.0.0")
	kingpin.Parse()

	var config coco.Config
	if _, err := toml.DecodeFile(*configPath, &config); err != nil {
		log.Fatalln("fatal:", err)
		return
	}

	// Setup data structures to be shared across components
	blacklisted := map[string]map[string]int64{}
	raw := make(chan collectd.Packet, 1000000)
	filtered := make(chan collectd.Packet, 1000000)
	items := make(chan coco.BlacklistItem, 1000000)

	var tiers []coco.Tier
	for k, v := range config.Tiers {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	if len(tiers) == 0 {
		log.Fatal("No tiers configured. Exiting.")
	}

	chans := map[string]chan collectd.Packet{
		"raw":      raw,
		"filtered": filtered,
		//"blacklist_items": items,
	}
	go coco.Measure(config.Measure, chans, &tiers)

	// Launch components to do the work
	go coco.Listen(config.Listen, raw)
	for i := 0; i < 4; i++ {
		go coco.Filter(config.Filter, raw, filtered, items)
	}
	go coco.Blacklist(items, &blacklisted)
	go coco.Send(&tiers, filtered)
	coco.Api(config.Api, &tiers, &blacklisted)
}
Example #7
0
func TestExpvars(t *testing.T) {
	// Setup API
	tierConfig := make(map[string]coco.TierConfig)
	tierConfig["a"] = coco.TierConfig{Targets: []string{"127.0.0.1:25887"}}

	var tiers []coco.Tier
	for k, v := range tierConfig {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26080",
	}
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)

	poll(t, apiConfig.Bind)

	// Test
	resp, err := http.Get("http://127.0.0.1:26080/debug/vars")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}

	body, err := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Errorf("Error when decoding JSON %+v.", err)
		t.Errorf("Response body: %s", string(body))
		t.FailNow()
	}

	if result["cmdline"] == nil {
		t.Errorf("Couldn't find 'cmdline' key in JSON.")
		t.Errorf("JSON object: %+v", result)
		t.FailNow()
	}
}
Example #8
0
func TestMeasureDistributionSummaryStats(t *testing.T) {
	// Setup tiers
	tierConfig := make(map[string]coco.TierConfig)
	tierConfig["a"] = coco.TierConfig{Targets: []string{"127.0.0.1:25811", "127.0.0.1:25812", "127.0.0.1:25813"}}
	tierConfig["b"] = coco.TierConfig{Targets: []string{"127.0.0.1:25821", "127.0.0.1:25822", "127.0.0.1:25823"}}
	tierConfig["c"] = coco.TierConfig{Targets: []string{"127.0.0.1:25831", "127.0.0.1:25832", "127.0.0.1:25833"}}

	for _, v := range tierConfig {
		for _, target := range v.Targets {
			go MockListener(t, target)
		}
	}

	var tiers []coco.Tier
	for k, v := range tierConfig {
		tier := coco.Tier{Name: k, Targets: v.Targets}
		tiers = append(tiers, tier)
	}

	// Setup Api
	apiConfig := coco.ApiConfig{
		Bind: "127.0.0.1:26810",
	}
	blacklisted := map[string]map[string]int64{}
	go coco.Api(apiConfig, &tiers, &blacklisted)
	poll(t, apiConfig.Bind)

	// Setup Measure
	chans := map[string]chan collectd.Packet{}
	measureConfig := coco.MeasureConfig{
		TickInterval: *new(coco.Duration),
	}
	measureConfig.TickInterval.UnmarshalText([]byte("100ms"))
	go coco.Measure(measureConfig, chans, &tiers)

	// Setup Send
	filtered := make(chan collectd.Packet)
	go coco.Send(&tiers, filtered)

	// Push packets to Send
	// 1000 hosts
	for i := 0; i < 1000; i++ {
		// up to 24 cpus per host
		iter := rand.Intn(24)
		for n := 0; n < iter; n++ {
			types := []string{"user", "system", "steal", "wait"}
			for _, typ := range types {
				filtered <- collectd.Packet{
					Hostname: "foo" + string(i),
					Plugin:   "cpu-" + strconv.Itoa(n),
					Type:     "cpu-" + typ,
				}
			}
		}
	}

	time.Sleep(10 * time.Millisecond)

	// Fetch exposed expvars
	resp, err := http.Get("http://127.0.0.1:26810/debug/vars")
	if err != nil {
		t.Fatalf("HTTP GET failed: %s", err)
	}
	body, err := ioutil.ReadAll(resp.Body)
	var result map[string]interface{}
	err = json.Unmarshal(body, &result)
	if err != nil {
		t.Errorf("Error when decoding JSON %+v.", err)
		t.Errorf("Response body: %s", string(body))
		t.FailNow()
	}

	// Test the exposed expvars data looks sane
	tierProps := result["coco"].(map[string]interface{})["hash.metrics_per_host"].(map[string]interface{})
	t.Logf("Expvar tier props: %+v\n", tierProps)
	if len(tiers) != len(tierProps) {
		t.Errorf("Expected %d tiers to be exposed, got %d\n", len(tiers), len(tierProps))
		//t.Errorf("Tiers: %+v\n", tiers)
		t.Errorf("Exposed tiers: %+v\n", tierProps)
	}
	for _, tier := range tiers {
		targetProps := tierProps[tier.Name].(map[string]interface{})
		if len(targetProps) != len(tier.Targets)+1 {
			t.Errorf("Expected %d targets to be exposed, got %d\n", len(tier.Targets)+1, len(targetProps))
			t.Errorf("Tier targets: %+v\n", tier.Targets)
			t.Errorf("Exposed target properties: %+v\n", targetProps)
		}
		for _, target := range tier.Targets {
			props := targetProps[target].(map[string]interface{})
			for _, k := range []string{"95e", "avg", "max", "min", "sum"} {
				if props[k] == nil {
					t.Errorf("Expected %s metric was not exposed on %s\n", k, target)
				}
			}
		}
	}
}