func TestByteValidation(t *testing.T) {
	cases := []VersionCaseB{
		VersionCaseB{"foo.bar", Legacy, Strict, true},
		VersionCaseB{"foo.bar", Legacy, Medium, true},
		VersionCaseB{"foo.bar", Legacy, None, true},
		VersionCaseB{"foo..bar", Legacy, Strict, false},
		VersionCaseB{"foo..bar", Legacy, Medium, true},
		VersionCaseB{"foo..bar", Legacy, None, true},
		VersionCaseB{"foo..bar.ba::z", Legacy, Strict, false},
		VersionCaseB{"foo..bar.ba::z", Legacy, Medium, true},
		VersionCaseB{"foo..bar.ba::z", Legacy, None, true},
		VersionCaseB{"foo..bar.b\xbdz", Legacy, Strict, false},
		VersionCaseB{"foo..bar.b\xbdz", Legacy, Medium, false},
		VersionCaseB{"foo..bar.b\xbdz", Legacy, None, true},
		VersionCaseB{"foo..bar.b\x00z", Legacy, Strict, false},
		VersionCaseB{"foo..bar.b\x00z", Legacy, Medium, false},
		VersionCaseB{"foo..bar.b\x00z", Legacy, None, true},
		VersionCaseB{"foo.bar.aunit=no.baz", M20, Strict, false},
		VersionCaseB{"foo.bar.UNIT=no.baz", M20, Strict, false},
		VersionCaseB{"foo.bar.unita=no.bar", M20, None, false},
		VersionCaseB{"foo.bar.target_type_is_count.baz", M20NoEquals, Medium, false},
		VersionCaseB{"foo.bar.target_type_is_count", M20NoEquals, None, false},
		VersionCaseB{"target_type_is_count.foo.bar", M20NoEquals, Strict, false},
	}
	for _, c := range cases {
		version := GetVersion(c.in)
		assert.Equal(t, c.version, version)
		assert.Equal(t, InitialValidationB([]byte(c.in), version, c.legacyValidation) == nil, c.valid)
	}
}
func TestRateCountPckt(t *testing.T) {
	cases := []Case{
		Case{"foo.bar.unit=yes.baz", "foo.bar.unit=Pckt.baz.orig_unit=yes.pckt_type=sent.direction=in"},
		Case{"foo.bar.unit=yes", "foo.bar.unit=Pckt.orig_unit=yes.pckt_type=sent.direction=in"},
		Case{"unit=yes.foo.bar", "unit=Pckt.foo.bar.orig_unit=yes.pckt_type=sent.direction=in"},
		Case{"target_type=count.foo.unit=ok.bar", "target_type=count.foo.unit=Pckt.bar.orig_unit=ok.pckt_type=sent.direction=in"},
	}
	for _, c := range cases {
		assert.Equal(t, CountPckt(c.in, "prefix."), c.out)
		c = Case{
			c.in,
			strings.Replace(strings.Replace(c.out, "unit=Pckt", "unit=Pcktps", -1), "target_type=count", "target_type=rate", -1),
		}
		assert.Equal(t, RatePckt(c.in, "prefix."), c.out)
	}
	for _, c := range cases {
		c = Case{
			strings.Replace(c.in, "=", "_is_", -1),
			strings.Replace(c.out, "=", "_is_", -1),
		}
		assert.Equal(t, CountPckt(c.in, "prefix."), c.out)
		c = Case{
			c.in,
			strings.Replace(strings.Replace(c.out, "unit_is_Pckt", "unit_is_Pcktps", -1), "target_type_is_count", "target_type_is_rate", -1),
		}
		assert.Equal(t, RatePckt(c.in, "prefix."), c.out)
	}
}
func TestConsistentHashingDestinations(t *testing.T) {
	initialDestinations := []*Destination{
		&Destination{Addr: "10.0.0.1"},
		&Destination{Addr: "127.0.0.1:2003", Instance: "a"},
		&Destination{Addr: "127.0.0.1:2004", Instance: "b"}}
	hasher := NewConsistentHasherReplicaCount(initialDestinations, 2)
	expectedHashRing := hashRing{
		hashRingEntry{Position: uint16(7885), Hostname: "127.0.0.1", Instance: "a", DestinationIndex: 1},
		hashRingEntry{Position: uint16(10461), Hostname: "127.0.0.1", Instance: "b", DestinationIndex: 2},
		hashRingEntry{Position: uint16(24043), Hostname: "127.0.0.1", Instance: "a", DestinationIndex: 1},
		hashRingEntry{Position: uint16(35540), Hostname: "10.0.0.1", DestinationIndex: 0},
		hashRingEntry{Position: uint16(46982), Hostname: "10.0.0.1", DestinationIndex: 0},
		hashRingEntry{Position: uint16(54295), Hostname: "127.0.0.1", Instance: "b", DestinationIndex: 2}}
	assert.Equal(t, expectedHashRing, hasher.Ring)
	hasher.AddDestination(&Destination{Addr: "127.0.0.1", Instance: "c"})
	hasher.AddDestination(&Destination{Addr: "10.0.0.2"})
	expectedHashRing = hashRing{
		hashRingEntry{Position: uint16(6639), Hostname: "10.0.0.2", DestinationIndex: 4},
		hashRingEntry{Position: uint16(7885), Hostname: "127.0.0.1", Instance: "a", DestinationIndex: 1},
		hashRingEntry{Position: uint16(10461), Hostname: "127.0.0.1", Instance: "b", DestinationIndex: 2},
		hashRingEntry{Position: uint16(24043), Hostname: "127.0.0.1", Instance: "a", DestinationIndex: 1},
		hashRingEntry{Position: uint16(24467), Hostname: "127.0.0.1", Instance: "c", DestinationIndex: 3},
		hashRingEntry{Position: uint16(35540), Hostname: "10.0.0.1", DestinationIndex: 0},
		hashRingEntry{Position: uint16(46982), Hostname: "10.0.0.1", DestinationIndex: 0},
		hashRingEntry{Position: uint16(52177), Hostname: "10.0.0.2", DestinationIndex: 4},
		hashRingEntry{Position: uint16(53472), Hostname: "127.0.0.1", Instance: "c", DestinationIndex: 3},
		hashRingEntry{Position: uint16(54295), Hostname: "127.0.0.1", Instance: "b", DestinationIndex: 2}}
	assert.Equal(t, expectedHashRing, hasher.Ring)
	assert.Equal(t, 4, hasher.GetDestinationIndex([]byte("a.b.c.d")))
	assert.Equal(t, 1, hasher.GetDestinationIndex([]byte("a.b.c..d")))
	assert.Equal(t, 3, hasher.GetDestinationIndex([]byte("collectd.bar.memory.free")))
}
func TestValidate(t *testing.T) {
	cases := []VersionCase{
		VersionCase{"foo.bar.aunit=no.baz", M20, false},
		VersionCase{"foo.bar.UNIT=no.baz", M20, false},
		VersionCase{"foo.bar.unita=no.bar", M20, false},
		VersionCase{"foo.bar.target_type_is_count.baz", M20NoEquals, false},
		VersionCase{"foo.bar.target_type_is_count", M20NoEquals, false},
		VersionCase{"target_type_is_count.foo.bar", M20NoEquals, false},
	}
	for _, c := range cases {
		version := GetVersion(c.in)
		assert.Equal(t, c.version, version)
		assert.Equal(t, InitialValidation(c.in, version) == nil, c.valid)
	}
}
// only 1 kind of stat is enough, cause they all behave the same
func TestStat(t *testing.T) {
	cases := []Case{
		Case{"foo.bar.unit=yes.baz", "foo.bar.unit=yes.baz.stat=max_90"},
		Case{"foo.bar.unit=yes", "foo.bar.unit=yes.stat=max_90"},
		Case{"unit=yes.foo.bar", "unit=yes.foo.bar.stat=max_90"},
		Case{"target_type=count.foo.unit=ok.bar", "target_type=count.foo.unit=ok.bar.stat=max_90"},
	}
	for _, c := range cases {
		assert.Equal(t, Max(c.in, "prefix.", "90", ""), c.out)
	}
	// same but with equals and no percentile
	for i, c := range cases {
		cases[i] = Case{
			strings.Replace(c.in, "=", "_is_", -1),
			strings.Replace(strings.Replace(c.out, "=", "_is_", -1), "max_90", "max", 1),
		}
	}
	for _, c := range cases {
		assert.Equal(t, Max(c.in, "prefix.", "", ""), c.out)
	}
}
func TestDeriveCount(t *testing.T) {
	// metrics 2.0 cases with equals
	cases := []Case{
		Case{"foo.bar.unit=yes.baz", "foo.bar.unit=yesps.baz"},
		Case{"foo.bar.unit=yes", "foo.bar.unit=yesps"},
		Case{"unit=yes.foo.bar", "unit=yesps.foo.bar"},
		Case{"target_type=count.foo.unit=ok.bar", "target_type=rate.foo.unit=okps.bar"},
	}
	for _, c := range cases {
		assert.Equal(t, DeriveCount(c.in, "prefix."), c.out)
	}

	// same but with equals
	for i, c := range cases {
		cases[i] = Case{
			strings.Replace(c.in, "=", "_is_", -1),
			strings.Replace(c.out, "=", "_is_", -1),
		}
	}
	for _, c := range cases {
		assert.Equal(t, DeriveCount(c.in, "prefix."), c.out)
	}
}
func TestConsistentHashingComputeRingPosition(t *testing.T) {
	assert.Equal(t, uint16(54437), computeRingPosition([]byte("a.b.c.d")))
	assert.Equal(t, uint16(54301), computeRingPosition([]byte("")))
}