diff --git a/plugin/collector/snap-plugin-collector-mock2/mock/mock.go b/plugin/collector/snap-plugin-collector-mock2/mock/mock.go index 5cff01f50..9e8e6a478 100644 --- a/plugin/collector/snap-plugin-collector-mock2/mock/mock.go +++ b/plugin/collector/snap-plugin-collector-mock2/mock/mock.go @@ -44,6 +44,9 @@ const ( type Mock struct { } +// list of available hosts +var availableHosts = getAllHostnames() + // CollectMetrics collects metrics for testing func (f *Mock) CollectMetrics(mts []plugin.MetricType) ([]plugin.MetricType, error) { for _, p := range mts { @@ -64,21 +67,48 @@ func (f *Mock) CollectMetrics(mts []plugin.MetricType) ([]plugin.MetricType, err if c, ok := mts[i].Config().Table()["panic"]; ok && c.(ctypes.ConfigValueBool).Value { panic("Oops!") } - if mts[i].Namespace()[2].Value == "*" { - for j := 0; j < 10; j++ { + + if isDynamic, _ := mts[i].Namespace().IsDynamic(); isDynamic { + requestedHosts := []string{} + + if mts[i].Namespace()[2].Value == "*" { + // when dynamic element is not specified (equals an asterisk) + // then consider all available hosts as requested hosts + requestedHosts = append(requestedHosts, availableHosts...) + } else { + // when the dynamic element is specified + // then consider this specified host as requested hosts + host := mts[i].Namespace()[2].Value + + // check if specified host is available in system + if contains(availableHosts, host) { + requestedHosts = append(requestedHosts, host) + } else { + return nil, fmt.Errorf("requested hostname `%s` is not available (list of available hosts: %s)", host, availableHosts) + } + + } + // collect data for each of requested hosts + for _, host := range requestedHosts { + //generate random data + data := randInt(65, 90) + 1000 + // prepare namespace as a copy of incoming dynamic namespace, + // but with the set value of dynamic element ns := make([]core.NamespaceElement, len(mts[i].Namespace())) copy(ns, mts[i].Namespace()) - ns[2].Value = fmt.Sprintf("host%d", j) - data := randInt(65, 90) + 1000 + ns[2].Value = host + + // metric with set data, ns, timestamp and the version of the plugin mt := plugin.MetricType{ Data_: data, Namespace_: ns, Timestamp_: time.Now(), - Version_: mts[i].Version(), Unit_: mts[i].Unit(), + Version_: mts[i].Version(), } metrics = append(metrics, mt) } + } else { data := randInt(65, 90) + 1000 mts[i].Data_ = data @@ -89,7 +119,7 @@ func (f *Mock) CollectMetrics(mts []plugin.MetricType) ([]plugin.MetricType, err return metrics, nil } -//GetMetricTypes returns metric types for testing +// GetMetricTypes returns metric types for testing func (f *Mock) GetMetricTypes(cfg plugin.ConfigType) ([]plugin.MetricType, error) { mts := []plugin.MetricType{} if _, ok := cfg.Table()["test-fail"]; ok { @@ -124,7 +154,7 @@ func (f *Mock) GetMetricTypes(cfg plugin.ConfigType) ([]plugin.MetricType, error return mts, nil } -//GetConfigPolicy returns a ConfigPolicy for testing +// GetConfigPolicy returns a ConfigPolicy for testing func (f *Mock) GetConfigPolicy() (*cpolicy.ConfigPolicy, error) { c := cpolicy.New() rule, _ := cpolicy.NewStringRule("name", false, "bob") @@ -136,7 +166,7 @@ func (f *Mock) GetConfigPolicy() (*cpolicy.ConfigPolicy, error) { return c, nil } -//Meta returns meta data for testing +// Meta returns meta data for testing func Meta() *plugin.PluginMeta { return plugin.NewPluginMeta( Name, @@ -149,7 +179,26 @@ func Meta() *plugin.PluginMeta { ) } -//Random number generator +// contains reports whether a given item is found in a slice +func contains(slice []string, item string) bool { + for _, s := range slice { + if s == item { + return true + } + } + return false +} + +// getAllHostnames returns all available hostnames ('host0', 'host1', ..., 'host9') +func getAllHostnames() []string { + res := []string{} + for j := 0; j < 10; j++ { + res = append(res, fmt.Sprintf("host%d", j)) + } + return res +} + +// random number generator func randInt(min int, max int) int { return min + rand.Intn(max-min) } diff --git a/plugin/collector/snap-plugin-collector-mock2/mock/mock_medium_test.go b/plugin/collector/snap-plugin-collector-mock2/mock/mock_medium_test.go new file mode 100644 index 000000000..322c82e59 --- /dev/null +++ b/plugin/collector/snap-plugin-collector-mock2/mock/mock_medium_test.go @@ -0,0 +1,280 @@ +// +build medium + +/* +http://www.apache.org/licenses/LICENSE-2.0.txt + + +Copyright 2016 Intel Corporation + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. +*/ + +package mock + +import ( + "math/rand" + "testing" + "time" + + "github.com/intelsdi-x/snap-plugin-utilities/str" + "github.com/intelsdi-x/snap/control/plugin" + "github.com/intelsdi-x/snap/core" + "github.com/intelsdi-x/snap/core/cdata" + "github.com/intelsdi-x/snap/core/ctypes" + . "github.com/smartystreets/goconvey/convey" +) + +func TestCollectMetric(t *testing.T) { + ns0 := core.NewNamespace("intel", "mock", "test") + ns1 := core.NewNamespace("intel", "mock", "foo") + ns2 := core.NewNamespace("intel", "mock", "bar") + ns3 := core.NewNamespace("intel", "mock").AddDynamicElement("host", "name of the host").AddStaticElement("baz") + + Convey("Testing CollectMetric", t, func() { + + newPlg := new(Mock) + So(newPlg, ShouldNotBeNil) + + Convey("with 'test' config variable'", func() { + + node := cdata.NewNode() + node.AddItem("test", ctypes.ConfigValueBool{Value: true}) + cfg := plugin.ConfigType{ConfigDataNode: node} + + Convey("testing specific metrics", func() { + mTypes := []plugin.MetricType{ + plugin.MetricType{Namespace_: ns0, Config_: cfg.ConfigDataNode}, + plugin.MetricType{Namespace_: ns1, Config_: cfg.ConfigDataNode}, + plugin.MetricType{Namespace_: ns2, Config_: cfg.ConfigDataNode}, + } + mts, _ := newPlg.CollectMetrics(mTypes) + + Convey("returned metrics should have data type integer", func() { + for _, mt := range mts { + _, ok := mt.Data_.(int) + So(ok, ShouldBeTrue) + } + }) + }) + + Convey("testing dynamic metric", func() { + + mt := plugin.MetricType{Namespace_: ns3, Config_: cfg.ConfigDataNode} + + Convey("for none specified instance", func() { + mts, _ := newPlg.CollectMetrics([]plugin.MetricType{mt}) + + // there is 10 available hosts (host0, host1, ..., host9) + So(len(mts), ShouldEqual, 10) + + Convey("returned metrics should have data type integer", func() { + for _, mt := range mts { + _, ok := mt.Data_.(int) + So(ok, ShouldBeTrue) + } + }) + + Convey("returned metrics should remain dynamic", func() { + for _, mt := range mts { + isDynamic, _ := mt.Namespace().IsDynamic() + So(isDynamic, ShouldBeTrue) + } + }) + + }) + + Convey("for specified instance which is available - host0", func() { + mt.Namespace()[2].Value = "host0" + mts, _ := newPlg.CollectMetrics([]plugin.MetricType{mt}) + + // only one metric for this specific hostname should be returned + So(len(mts), ShouldEqual, 1) + So(mts[0].Namespace().String(), ShouldEqual, "/intel/mock/host0/baz") + + Convey("returned metric should have data type integer", func() { + _, ok := mts[0].Data_.(int) + So(ok, ShouldBeTrue) + }) + + Convey("returned metric should remain dynamic", func() { + isDynamic, _ := mt.Namespace().IsDynamic() + So(isDynamic, ShouldBeTrue) + }) + + }) + + Convey("for specified instance which is not available - host10", func() { + mt.Namespace()[2].Value = "host10" + mts, err := newPlg.CollectMetrics([]plugin.MetricType{mt}) + + So(mts, ShouldBeNil) + So(err, ShouldNotBeNil) + So(err.Error(), ShouldStartWith, "requested hostname `host10` is not available") + + }) + }) + + }) + + Convey("without config variables", func() { + + node := cdata.NewNode() + cfg := plugin.ConfigType{ConfigDataNode: node} + + Convey("testing specific metrics", func() { + mTypes := []plugin.MetricType{ + plugin.MetricType{Namespace_: ns0, Config_: cfg.ConfigDataNode}, + plugin.MetricType{Namespace_: ns1, Config_: cfg.ConfigDataNode}, + plugin.MetricType{Namespace_: ns2, Config_: cfg.ConfigDataNode}, + } + mts, _ := newPlg.CollectMetrics(mTypes) + + Convey("returned metrics should have data type integer", func() { + for _, mt := range mts { + _, ok := mt.Data_.(int) + So(ok, ShouldBeTrue) + } + }) + }) + + Convey("testing dynamic metics", func() { + mTypes := []plugin.MetricType{ + plugin.MetricType{Namespace_: ns3, Config_: cfg.ConfigDataNode}, + } + mts, _ := newPlg.CollectMetrics(mTypes) + + Convey("returned metrics should have data type integer", func() { + for _, mt := range mts { + _, ok := mt.Data_.(int) + So(ok, ShouldBeTrue) + } + }) + + Convey("returned metrics should remain dynamic", func() { + for _, mt := range mts { + isDynamic, _ := mt.Namespace().IsDynamic() + So(isDynamic, ShouldBeTrue) + } + }) + + }) + + }) + + }) +} + +func TestGetMetricTypes(t *testing.T) { + Convey("Tesing GetMetricTypes", t, func() { + + newPlg := new(Mock) + So(newPlg, ShouldNotBeNil) + + Convey("with missing on-load plugin config entry", func() { + node := cdata.NewNode() + node.AddItem("test-fail", ctypes.ConfigValueStr{Value: ""}) + + _, err := newPlg.GetMetricTypes(plugin.ConfigType{ConfigDataNode: node}) + + So(err, ShouldNotBeNil) + }) + + Convey("with 'test' config variable", func() { + node := cdata.NewNode() + node.AddItem("test", ctypes.ConfigValueStr{Value: ""}) + + mts, err := newPlg.GetMetricTypes(plugin.ConfigType{ConfigDataNode: node}) + + So(err, ShouldBeNil) + So(len(mts), ShouldEqual, 4) + + Convey("checking namespaces", func() { + metricNames := []string{} + for _, m := range mts { + metricNames = append(metricNames, m.Namespace().String()) + } + + ns := core.NewNamespace("intel", "mock", "test") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + + ns = core.NewNamespace("intel", "mock", "foo") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + + ns = core.NewNamespace("intel", "mock", "bar") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + + ns = core.NewNamespace("intel", "mock").AddDynamicElement("host", "name of the host").AddStaticElement("baz") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + }) + }) + + Convey("without config variables", func() { + node := cdata.NewNode() + mts, err := newPlg.GetMetricTypes(plugin.ConfigType{ConfigDataNode: node}) + + So(err, ShouldBeNil) + So(len(mts), ShouldEqual, 3) + + Convey("checking namespaces", func() { + metricNames := []string{} + for _, m := range mts { + metricNames = append(metricNames, m.Namespace().String()) + } + + ns := core.NewNamespace("intel", "mock", "foo") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + + ns = core.NewNamespace("intel", "mock", "bar") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + + ns = core.NewNamespace("intel", "mock").AddDynamicElement("host", "name of the host").AddStaticElement("baz") + So(str.Contains(metricNames, ns.String()), ShouldBeTrue) + }) + }) + + }) +} + +func TestMeta(t *testing.T) { + Convey("Testing Meta", t, func() { + meta := Meta() + So(meta.Name, ShouldEqual, Name) + So(meta.Version, ShouldEqual, Version) + So(meta.Type, ShouldEqual, Type) + So(meta.AcceptedContentTypes[0], ShouldEqual, plugin.SnapGOBContentType) + So(meta.ReturnedContentTypes[0], ShouldEqual, plugin.SnapGOBContentType) + So(meta.Unsecure, ShouldEqual, false) + So(meta.RoutingStrategy, ShouldEqual, plugin.StickyRouting) + So(meta.CacheTTL, ShouldEqual, 100*time.Millisecond) + }) +} + +func TestRandInt(t *testing.T) { + Convey("Testing randInt", t, func() { + rand.Seed(time.Now().UTC().UnixNano()) + data := randInt(65, 90) + So(data, ShouldBeBetween, 64, 91) + }) +} + +func TestGetConfigPolicy(t *testing.T) { + Convey("Testing GetConfigPolicy", t, func() { + newPlg := new(Mock) + So(newPlg, ShouldNotBeNil) + + configPolicy, err := newPlg.GetConfigPolicy() + + So(err, ShouldBeNil) + So(configPolicy, ShouldNotBeNil) + }) +}