func TestAPI(t *testing.T) { alBuilder := datastructs.NewApplicationListBuilder() alBuilder.Add( 37, "AnApp", sources.ConnectorList{trisource.GetConnector()}) alBuilder.Add( 97, "AnotherApp", sources.ConnectorList{trisource.GetConnector()}) appList := alBuilder.Build() appStatus := datastructs.NewApplicationStatuses( appList, newStore( t, "TestAPI", 2, 100, 1.0, 10)) appStatus.MarkHostsActiveExclusively( 100.0, []string{"host1", "host2", "host3", "host4", "host5"}) endpointId, aStore := appStatus.EndpointIdByHostAndName( "host1", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 30.0, 510.0, 31.0, 520.0, 32.0, 530.0, 33.0, 540.0, 34.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host1", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 40.0, 510.0, 41.0, 520.0, 42.0, 530.0, 43.0, 540.0, 44.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host2", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 50.0, 510.0, 51.0, 520.0, 52.0, 530.0, 53.0, 540.0, 54.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host2", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 60.0, 510.0, 61.0, 520.0, 62.0, 530.0, 63.0, 540.0, 64.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnApp") addValues(t, aStore, endpointId, "/foo", 500.0, 70.0, 510.0, 71.0, 520.0, 72.0, 530.0, 73.0, 540.0, 74.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnotherApp") addValues(t, aStore, endpointId, "/foo", 500.0, 80.0, 510.0, 81.0, 520.0, 82.0, 530.0, 83.0, 540.0, 84.0) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host5", "AnApp") addValues(t, aStore, endpointId, "/bar", 700.0, 80.0, 800.0, 100.0) var taggedTimeSeriesSet *tsdb.TaggedTimeSeriesSet var err error if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 600.0, nil); err != nil { t.Fatal(err) } expected := &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {500.0, 55.5}, {520.0, 57.5}, {540.0, 59.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) if _, err = tsdbimpl.Query( appStatus, "/not there", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 600.0, nil); err != tsdbimpl.ErrNoSuchMetric { t.Error("Expected ErrNoSuchName") } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/bar", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 500.0, 1000.0, nil); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/bar", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {700.0, 80.0}, {800.0, 100.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 501.0, 539.0, nil); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options := &tsdbimpl.QueryOptions{ GroupByHostName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host1", }, Values: tsdb.TimeSeries{ {500.0, 35.5}, {520.0, 37.5}, {540.0, 39.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", }, Values: tsdb.TimeSeries{ {500.0, 55.5}, {520.0, 57.5}, {540.0, 59.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", }, Values: tsdb.TimeSeries{ {500.0, 75.5}, {520.0, 77.5}, {540.0, 79.0}, }, }, }, GroupedByHostName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 700.0, 900.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", GroupedByHostName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64}, }, }, }, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host1", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 30.5}, {520.0, 32.5}, {540.0, 34.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host1", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 40.5}, {520.0, 42.5}, {540.0, 44.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 70.5}, {520.0, 72.5}, {540.0, 74.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnotherApp", }, Values: tsdb.TimeSeries{ {500.0, 80.5}, {520.0, 82.5}, {540.0, 84.0}, }, }, }, GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 700.0, 900.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "AnApp" }), GroupByHostName: true, GroupByAppName: true, } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Tags: tsdb.TagSet{ HostName: "host2", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 50.5}, {520.0, 52.5}, {540.0, 54.0}, }, }, { Tags: tsdb.TagSet{ HostName: "host3", AppName: "AnApp", }, Values: tsdb.TimeSeries{ {500.0, 70.5}, {520.0, 72.5}, {540.0, 74.0}, }, }, }, GroupedByHostName: true, GroupedByAppName: true, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "AnApp" }), } if taggedTimeSeriesSet, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != nil { t.Fatal(err) } expected = &tsdb.TaggedTimeSeriesSet{ MetricName: "/foo", Data: []tsdb.TaggedTimeSeries{ { Values: tsdb.TimeSeries{ {500.0, 60.5}, {520.0, 62.5}, {540.0, 64.0}, }, }, }, } assertTaggedTimeSeriesSetEquals( t, expected, taggedTimeSeriesSet, ) options = &tsdbimpl.QueryOptions{ HostNameFilter: tagFilter(func(s string) bool { return s == "host2" || s == "host3" }), AppNameFilter: tagFilter(func(s string) bool { return s == "No app" }), } if _, err = tsdbimpl.Query( appStatus, "/foo", func(start, end float64) (tsdb.Aggregator, error) { return aggregators.New( start, end, aggregators.Avg, 20.0, aggregators.Avg, aggregators.NaN, nil), nil }, 400.0, 700.0, options); err != tsdbimpl.ErrNoSuchMetric { t.Error("Expected ErrNoSuchMetric") } }
func TestMarkHostsActiveExclusively(t *testing.T) { alBuilder := NewApplicationListBuilder() alBuilder.Add( 35, "AnApp", sources.ConnectorList{trisource.GetConnector()}) alBuilder.Add( 92, "AnotherApp", sources.ConnectorList{snmpsource.NewConnector("community")}) appList := alBuilder.Build() appStatus := NewApplicationStatuses( appList, newStore(t, "TestMarkHostsActiveExclusively", 1, 100, 1.0, 10)) appStatus.MarkHostsActiveExclusively( 92.5, []string{"host1", "host2", "host3"}) activateEndpoints(appStatus.ActiveEndpointIds()) astore := appStatus.Store() visitor := newActiveInactiveLists() astore.VisitAllEndpoints(visitor) assertDeepEqual( t, map[string]bool{ "host1:35": true, "host1:92": true, "host2:35": true, "host2:92": true, "host3:35": true, "host3:92": true, }, visitor.Active) assertDeepEqual( t, make(map[string]bool), visitor.Inactive) appStatus.MarkHostsActiveExclusively(61.7, []string{"host2", "host4"}) activeEndpointIds, astore := appStatus.ActiveEndpointIds() assertValueEquals(t, 4, len(activeEndpointIds)) activateEndpoints(activeEndpointIds, astore) visitor = newActiveInactiveLists() astore.VisitAllEndpoints(visitor) assertDeepEqual( t, map[string]bool{ "host2:35": true, "host2:92": true, "host4:35": true, "host4:92": true, }, visitor.Active) assertDeepEqual( t, map[string]bool{ "host1:35": true, "host1:92": true, "host3:35": true, "host3:92": true, }, visitor.Inactive) endpointId, aStore := appStatus.EndpointIdByHostAndName( "host3", "AnApp") assertValueEquals(t, "host3", endpointId.HostName()) assertValueEquals(t, uint(35), endpointId.Port()) // Trying to add to inactive endpoint should fail if _, err := aStore.AddBatch(endpointId, 9999.0, metrics.SimpleList(nil)); err != store.ErrInactive { t.Error("Adding to inactive endpoint should fail.") } stats := appStatus.All() ByHostAndName(stats) assertValueEquals(t, 8, len(stats)) assertValueEquals(t, "host1", stats[0].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[0].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[0].Name) assertValueEquals(t, false, stats[0].Active) assertValueEquals(t, "host1", stats[1].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[1].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[1].Name) assertValueEquals(t, false, stats[1].Active) assertValueEquals(t, "host2", stats[2].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[2].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[2].Name) assertValueEquals(t, true, stats[2].Active) assertValueEquals(t, "host2", stats[3].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[3].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[3].Name) assertValueEquals(t, true, stats[3].Active) assertValueEquals(t, "host3", stats[4].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[4].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[4].Name) assertValueEquals(t, false, stats[4].Active) assertValueEquals(t, "host3", stats[5].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[5].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[5].Name) assertValueEquals(t, false, stats[5].Active) assertValueEquals(t, "host4", stats[6].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[6].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[6].Name) assertValueEquals(t, true, stats[6].Active) assertValueEquals(t, "host4", stats[7].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[7].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[7].Name) assertValueEquals(t, true, stats[7].Active) appStatus.MarkHostsActiveExclusively(61.7, []string{"host2", "host3", "host4"}) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnApp") var noMetrics metrics.SimpleList // Trying to add to active endpoint should succeed if _, err := aStore.AddBatch(endpointId, 9999.0, noMetrics); err != nil { t.Error("Adding to active endpoint should succeed.") } stats = appStatus.All() ByHostAndName(stats) assertValueEquals(t, 8, len(stats)) assertValueEquals(t, "host1", stats[0].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[0].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[0].Name) assertValueEquals(t, false, stats[0].Active) assertValueEquals(t, "host1", stats[1].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[1].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[1].Name) assertValueEquals(t, false, stats[1].Active) assertValueEquals(t, "host2", stats[2].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[2].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[2].Name) assertValueEquals(t, true, stats[2].Active) assertValueEquals(t, "host2", stats[3].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[3].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[3].Name) assertValueEquals(t, true, stats[3].Active) assertValueEquals(t, "host3", stats[4].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[4].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[4].Name) assertValueEquals(t, true, stats[4].Active) assertValueEquals(t, "host3", stats[5].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[5].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[5].Name) assertValueEquals(t, true, stats[5].Active) assertValueEquals(t, "host4", stats[6].EndpointId.HostName()) assertValueEquals( t, "tricorder", stats[6].EndpointId.ConnectorName()) assertValueEquals(t, "AnApp", stats[6].Name) assertValueEquals(t, true, stats[6].Active) assertValueEquals(t, "host4", stats[7].EndpointId.HostName()) assertValueEquals( t, "snmp", stats[7].EndpointId.ConnectorName()) assertValueEquals(t, "AnotherApp", stats[7].Name) assertValueEquals(t, true, stats[7].Active) }
func TestHighPriorityEviction(t *testing.T) { alBuilder := NewApplicationListBuilder() alBuilder.Add(37, "AnApp", sources.ConnectorList{trisource.GetConnector()}) appList := alBuilder.Build() // 9 values appStatus := NewApplicationStatuses( appList, newStore( t, "TestHighPriorityEviction", 1, 6, 1.0, 10)) // host1, host2, host3 marked active // 2 values to AnApp:/foo on host1, host2 and host3 // 3rd value to anApp:/foo on host1, host2 only // host1 and host2 only marked active giving host3:AnApp:/foo // an inactive marker as third value // 4th value added to AnApp:/foo on host1 and host2 only addDataForHighPriorityEvictionTest(appStatus) endpointId, aStore := appStatus.EndpointIdByHostAndName( "host3", "AnApp") var result []store.Record aStore.ByNameAndEndpoint( "/foo", endpointId, 0.0, math.Inf(0), store.AppendTo(&result)) // Since the high priority threshhold is 100%, // we don't expect all the // pages of host3:AnApp:/foo to get reclaimed. if len(result) <= 1 { t.Error("Expected host3:AnApp:/foo to have at least 2 values") } // 9 values appStatus = NewApplicationStatuses( appList, newStore(t, "TestHighPriorityEviction2", 1, 6, 0.0, 10)) // host1, host2, host3 marked active // 3 values to AnApp:/foo on host1, host2 and host3 // host1 and host2 only marked active // 4th value added to AnApp:/foo on host1 and host2 only addDataForHighPriorityEvictionTest(appStatus) endpointId, aStore = appStatus.EndpointIdByHostAndName( "host3", "AnApp") result = nil aStore.ByNameAndEndpoint( "/foo", endpointId, 0.0, math.Inf(0), store.AppendTo(&result)) // Since the high priority threshhold is 0%, // we do expect all the pages for host3:Anpp:/foo to get reclaimed if len(result) > 1 { t.Error("Expected host3:AnApp:/foo to have only 1 value") } }
func newTricorder(unused map[string]string) (sources.ConnectorList, error) { return sources.ConnectorList{ trisource.GetConnector(), jsonsource.GetConnector()}, nil }