github.com/galamsiva2020/kubernetes-heapster-monitoring@v0.0.0-20210823134957-3c1baa7c1e70/metrics/sinks/hawkular/driver_test.go (about)

     1  // Copyright 2015 Google Inc. All Rights Reserved.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package hawkular
    16  
    17  import (
    18  	"encoding/json"
    19  	"fmt"
    20  	"io/ioutil"
    21  	"net/http"
    22  	"net/http/httptest"
    23  	"net/url"
    24  	"strconv"
    25  	"strings"
    26  	"sync"
    27  	"testing"
    28  	"time"
    29  
    30  	"github.com/hawkular/hawkular-client-go/metrics"
    31  	"k8s.io/heapster/metrics/core"
    32  
    33  	assert "github.com/stretchr/testify/require"
    34  )
    35  
    36  func dummySink() *hawkularSink {
    37  	return &hawkularSink{
    38  		expReg: make(map[string]*expiringItem),
    39  		models: make(map[string]*metrics.MetricDefinition),
    40  	}
    41  }
    42  
    43  func TestDescriptorTransform(t *testing.T) {
    44  
    45  	hSink := dummySink()
    46  
    47  	ld := core.LabelDescriptor{
    48  		Key:         "k1",
    49  		Description: "d1",
    50  	}
    51  	smd := core.MetricDescriptor{
    52  		Name:      "test/metric/1",
    53  		Units:     core.UnitsBytes,
    54  		ValueType: core.ValueInt64,
    55  		Type:      core.MetricGauge,
    56  		Labels:    []core.LabelDescriptor{ld},
    57  	}
    58  
    59  	md := hSink.descriptorToDefinition(&smd)
    60  
    61  	assert.Equal(t, smd.Name, md.ID)
    62  	assert.Equal(t, 3, len(md.Tags)) // descriptorTag, unitsTag, typesTag, k1
    63  
    64  	assert.Equal(t, smd.Units.String(), md.Tags[unitsTag])
    65  	assert.Equal(t, "d1", md.Tags["k1_description"])
    66  
    67  	smd.Type = core.MetricCumulative
    68  
    69  	md = hSink.descriptorToDefinition(&smd)
    70  	assert.EqualValues(t, md.Type, metrics.Counter)
    71  }
    72  
    73  func TestMetricTransform(t *testing.T) {
    74  	hSink := dummySink()
    75  
    76  	l := make(map[string]string)
    77  	l["spooky"] = "notvisible"
    78  	l[core.LabelHostname.Key] = "localhost"
    79  	l[core.LabelHostID.Key] = "localhost"
    80  	l[core.LabelContainerName.Key] = "docker"
    81  	l[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
    82  	l[core.LabelNodename.Key] = "myNode"
    83  
    84  	metricName := "test/metric/1"
    85  	labeledMetricNameA := "test/labeledmetric/A"
    86  	labeledMetricNameB := "test/labeledmetric/B"
    87  
    88  	metricSet := core.MetricSet{
    89  		Labels: l,
    90  		MetricValues: map[string]core.MetricValue{
    91  			metricName: {
    92  				ValueType:  core.ValueInt64,
    93  				MetricType: core.MetricGauge,
    94  				IntValue:   123456,
    95  			},
    96  		},
    97  		LabeledMetrics: []core.LabeledMetric{
    98  			{
    99  				Name: labeledMetricNameA,
   100  				Labels: map[string]string{
   101  					core.LabelResourceID.Key: "XYZ",
   102  				},
   103  				MetricValue: core.MetricValue{
   104  					MetricType: core.MetricGauge,
   105  					FloatValue: 124.456,
   106  				},
   107  			},
   108  			{
   109  				Name: labeledMetricNameB,
   110  				MetricValue: core.MetricValue{
   111  					MetricType: core.MetricGauge,
   112  					FloatValue: 454,
   113  				},
   114  			},
   115  		},
   116  	}
   117  
   118  	metricSet.LabeledMetrics = append(metricSet.LabeledMetrics, metricValueToLabeledMetric(metricSet.MetricValues)...)
   119  
   120  	now := time.Now()
   121  	//
   122  	m, err := hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[2], now)
   123  	assert.NoError(t, err)
   124  
   125  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key],
   126  		metricSet.Labels[core.LabelPodId.Key], metricName), m.ID)
   127  
   128  	assert.Equal(t, 1, len(m.Data))
   129  	_, ok := m.Data[0].Value.(float64)
   130  	assert.True(t, ok, "Value should have been converted to float64")
   131  
   132  	delete(l, core.LabelPodId.Key)
   133  
   134  	//
   135  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[2], now)
   136  	assert.NoError(t, err)
   137  
   138  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key], metricSet.Labels[core.LabelNodename.Key], metricName), m.ID)
   139  
   140  	//
   141  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   142  	assert.NoError(t, err)
   143  
   144  	assert.Equal(t, fmt.Sprintf("%s/%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key],
   145  		metricSet.Labels[core.LabelNodename.Key], labeledMetricNameA,
   146  		metricSet.LabeledMetrics[0].Labels[core.LabelResourceID.Key]), m.ID)
   147  
   148  	//
   149  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[1], now)
   150  	assert.NoError(t, err)
   151  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key],
   152  		metricSet.Labels[core.LabelNodename.Key], labeledMetricNameB), m.ID)
   153  }
   154  
   155  func TestMetricIds(t *testing.T) {
   156  	hSink := dummySink()
   157  
   158  	l := make(map[string]string)
   159  	l["spooky"] = "notvisible"
   160  	l[core.LabelHostname.Key] = "localhost"
   161  	l[core.LabelHostID.Key] = "localhost"
   162  	l[core.LabelContainerName.Key] = "docker"
   163  	l[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   164  	l[core.LabelNodename.Key] = "myNode"
   165  	l[core.LabelNamespaceName.Key] = "myNamespace"
   166  
   167  	metricName := "test/metric/nodeType"
   168  
   169  	metricSet := core.MetricSet{
   170  		Labels: l,
   171  		MetricValues: map[string]core.MetricValue{
   172  			metricName: {
   173  				ValueType:  core.ValueInt64,
   174  				MetricType: core.MetricGauge,
   175  				IntValue:   123456,
   176  			},
   177  		},
   178  	}
   179  	metricSet.LabeledMetrics = metricValueToLabeledMetric(metricSet.MetricValues)
   180  
   181  	now := time.Now()
   182  	//
   183  	m, err := hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   184  	assert.NoError(t, err)
   185  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key], metricSet.Labels[core.LabelPodId.Key], metricName), m.ID)
   186  
   187  	//
   188  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypeNode
   189  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   190  	assert.NoError(t, err)
   191  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", "machine", metricSet.Labels[core.LabelNodename.Key], metricName), m.ID)
   192  
   193  	//
   194  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypePod
   195  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   196  	assert.NoError(t, err)
   197  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", core.MetricSetTypePod, metricSet.Labels[core.LabelPodId.Key], metricName), m.ID)
   198  
   199  	//
   200  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypePodContainer
   201  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   202  	assert.NoError(t, err)
   203  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", metricSet.Labels[core.LabelContainerName.Key], metricSet.Labels[core.LabelPodId.Key], metricName), m.ID)
   204  
   205  	//
   206  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypeSystemContainer
   207  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   208  	assert.NoError(t, err)
   209  	assert.Equal(t, fmt.Sprintf("%s/%s/%s/%s", core.MetricSetTypeSystemContainer, metricSet.Labels[core.LabelContainerName.Key], metricSet.Labels[core.LabelPodId.Key], metricName), m.ID)
   210  
   211  	//
   212  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypeCluster
   213  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   214  	assert.NoError(t, err)
   215  	assert.Equal(t, fmt.Sprintf("%s/%s", core.MetricSetTypeCluster, metricName), m.ID)
   216  
   217  	//
   218  	metricSet.Labels[core.LabelMetricSetType.Key] = core.MetricSetTypeNamespace
   219  	m, err = hSink.pointToLabeledMetricHeader(&metricSet, metricSet.LabeledMetrics[0], now)
   220  	assert.NoError(t, err)
   221  	assert.Equal(t, fmt.Sprintf("%s/%s/%s", core.MetricSetTypeNamespace, metricSet.Labels[core.LabelNamespaceName.Key], metricName), m.ID)
   222  
   223  }
   224  
   225  func TestRecentTest(t *testing.T) {
   226  	hSink := dummySink()
   227  
   228  	modelT := make(map[string]string)
   229  
   230  	id := "test.name"
   231  	modelT[descriptorTag] = "d"
   232  	modelT[groupTag] = id
   233  	modelT["hep"+descriptionTag] = "n"
   234  
   235  	model := metrics.MetricDefinition{
   236  		ID:   id,
   237  		Tags: modelT,
   238  	}
   239  
   240  	liveT := make(map[string]string)
   241  	for k, v := range modelT {
   242  		liveT[k] = v
   243  	}
   244  
   245  	live := metrics.MetricDefinition{
   246  		ID:   "test/" + id,
   247  		Tags: liveT,
   248  	}
   249  
   250  	assert.True(t, hSink.recent(&live, &model), "Tags are equal, live is newest")
   251  
   252  	delete(liveT, "hep"+descriptionTag)
   253  	live.Tags = liveT
   254  
   255  	assert.False(t, hSink.recent(&live, &model), "Tags are not equal, live isn't recent")
   256  
   257  }
   258  
   259  func TestParseFiltersErrors(t *testing.T) {
   260  	_, err := parseFilters([]string{"(missingcommand)"})
   261  	assert.Error(t, err)
   262  
   263  	_, err = parseFilters([]string{"missingeverything"})
   264  	assert.Error(t, err)
   265  
   266  	_, err = parseFilters([]string{"labelstart:^missing$)"})
   267  	assert.Error(t, err)
   268  
   269  	_, err = parseFilters([]string{"label(endmissing"})
   270  	assert.Error(t, err)
   271  
   272  	_, err = parseFilters([]string{"label(wrongsyntax)"})
   273  	assert.Error(t, err)
   274  }
   275  
   276  // Integration tests
   277  func integSink(uri string) (*hawkularSink, error) {
   278  
   279  	u, err := url.Parse(uri)
   280  	if err != nil {
   281  		return nil, err
   282  	}
   283  
   284  	sink := &hawkularSink{
   285  		uri: u,
   286  	}
   287  	if err = sink.init(); err != nil {
   288  		return nil, err
   289  	}
   290  
   291  	return sink, nil
   292  }
   293  
   294  // Test that Definitions is called for Gauges & Counters
   295  // Test that we have single registered model
   296  // Test that the tags for metric is updated..
   297  func TestRegister(t *testing.T) {
   298  	m := &sync.Mutex{}
   299  	// definitionsCalled := make(map[string]bool)
   300  	updateTagsCalled := false
   301  	requests := 0
   302  
   303  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   304  		m.Lock()
   305  		defer m.Unlock()
   306  		w.Header().Set("Content-Type", "application/json")
   307  
   308  		if strings.Contains(r.RequestURI, "tenants") {
   309  			fmt.Fprintln(w, `[{ "id": "test-heapster"},{"id": "fgahj-fgas-basf-gegsg" }]`)
   310  		} else {
   311  			tenant := r.Header.Get("Hawkular-Tenant")
   312  			if tenant != "test-heapster" {
   313  				requests++
   314  				w.WriteHeader(http.StatusNoContent)
   315  				return
   316  			}
   317  			if strings.Contains(r.RequestURI, "metrics?tags=descriptor_name%3A%2A") || strings.Contains(r.RequestURI, "openshift") {
   318  				requests++
   319  				fmt.Fprintln(w, `[{ "id": "test.create.gauge.1", "tenantId": "test-heapster", "type": "gauge", "tags": { "descriptor_name": "test/metric/1" } }]`)
   320  			} else if strings.Contains(r.RequestURI, "/tags") && r.Method == "PUT" {
   321  				updateTagsCalled = true
   322  				defer r.Body.Close()
   323  				b, err := ioutil.ReadAll(r.Body)
   324  				assert.NoError(t, err)
   325  
   326  				tags := make(map[string]string)
   327  				err = json.Unmarshal(b, &tags)
   328  				assert.NoError(t, err)
   329  
   330  				_, kt1 := tags["k1_description"]
   331  				_, dt := tags["descriptor_name"]
   332  
   333  				assert.True(t, kt1, "k1_description tag is missing")
   334  				assert.True(t, dt, "descriptor_name is missing")
   335  
   336  				w.WriteHeader(http.StatusOK)
   337  			}
   338  		}
   339  	}))
   340  	defer s.Close()
   341  
   342  	hSink, err := integSink(s.URL + "?tenant=test-heapster")
   343  	assert.NoError(t, err)
   344  
   345  	md := make([]core.MetricDescriptor, 0, 1)
   346  	ld := core.LabelDescriptor{
   347  		Key:         "k1",
   348  		Description: "d1",
   349  	}
   350  	smd := core.MetricDescriptor{
   351  		Name:      "test/metric/1",
   352  		Units:     core.UnitsBytes,
   353  		ValueType: core.ValueInt64,
   354  		Type:      core.MetricGauge,
   355  		Labels:    []core.LabelDescriptor{ld},
   356  	}
   357  	smdg := core.MetricDescriptor{
   358  		Name:      "test/metric/2",
   359  		Units:     core.UnitsBytes,
   360  		ValueType: core.ValueFloat,
   361  		Type:      core.MetricCumulative,
   362  		Labels:    []core.LabelDescriptor{},
   363  	}
   364  
   365  	md = append(md, smd, smdg)
   366  
   367  	err = hSink.Register(md)
   368  	assert.NoError(t, err)
   369  
   370  	assert.Equal(t, 2, len(hSink.models))
   371  	assert.Equal(t, 1, len(hSink.expReg))
   372  
   373  	assert.True(t, updateTagsCalled, "Updating outdated tags was not called")
   374  	assert.Equal(t, 1, requests)
   375  
   376  	// Try without pre caching
   377  	updateTagsCalled = false
   378  
   379  	hSink, err = integSink(s.URL + "?tenant=test-heapster&disablePreCache=true")
   380  	assert.NoError(t, err)
   381  
   382  	err = hSink.Register(md)
   383  	assert.NoError(t, err)
   384  
   385  	assert.Equal(t, 2, len(hSink.models))
   386  	assert.Equal(t, 0, len(hSink.expReg))
   387  
   388  	assert.False(t, updateTagsCalled, "Updating outdated tags was called")
   389  }
   390  
   391  // Store timeseries with both gauges and cumulatives
   392  func TestStoreTimeseries(t *testing.T) {
   393  	m := &sync.Mutex{}
   394  	ids := make([]string, 0, 2)
   395  	calls := make([]string, 0, 2)
   396  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   397  		m.Lock()
   398  		defer m.Unlock()
   399  		calls = append(calls, r.RequestURI)
   400  		w.Header().Set("Content-Type", "application/json")
   401  
   402  		typ := r.RequestURI[strings.Index(r.RequestURI, "hawkular/metrics/")+17:]
   403  		typ = typ[:len(typ)-4]
   404  
   405  		switch typ {
   406  		case "counters":
   407  			assert.Equal(t, "test-label", r.Header.Get("Hawkular-Tenant"))
   408  			break
   409  		case "gauges":
   410  			assert.Equal(t, "test-heapster", r.Header.Get("Hawkular-Tenant"))
   411  			break
   412  		default:
   413  			assert.FailNow(t, "Unrecognized type "+typ)
   414  		}
   415  
   416  		defer r.Body.Close()
   417  		b, err := ioutil.ReadAll(r.Body)
   418  		assert.NoError(t, err)
   419  
   420  		mH := []metrics.MetricHeader{}
   421  		err = json.Unmarshal(b, &mH)
   422  		assert.NoError(t, err)
   423  
   424  		assert.Equal(t, 1, len(mH))
   425  
   426  		ids = append(ids, mH[0].ID)
   427  	}))
   428  	defer s.Close()
   429  
   430  	hSink, err := integSink(s.URL + "?tenant=test-heapster&labelToTenant=projectId")
   431  	assert.NoError(t, err)
   432  
   433  	l := make(map[string]string)
   434  	l["projectId"] = "test-label"
   435  	l[core.LabelContainerName.Key] = "test-container"
   436  	l[core.LabelPodId.Key] = "test-podid"
   437  
   438  	lg := make(map[string]string)
   439  	lg[core.LabelContainerName.Key] = "test-container"
   440  	lg[core.LabelPodId.Key] = "test-podid"
   441  
   442  	metricSet1 := core.MetricSet{
   443  		Labels: l,
   444  		MetricValues: map[string]core.MetricValue{
   445  			"test/metric/1": {
   446  				ValueType:  core.ValueInt64,
   447  				MetricType: core.MetricCumulative,
   448  				IntValue:   123456,
   449  			},
   450  		},
   451  	}
   452  
   453  	metricSet2 := core.MetricSet{
   454  		Labels: lg,
   455  		MetricValues: map[string]core.MetricValue{
   456  			"test/metric/2": {
   457  				ValueType:  core.ValueFloat,
   458  				MetricType: core.MetricGauge,
   459  				FloatValue: 123.456,
   460  			},
   461  		},
   462  	}
   463  
   464  	data := core.DataBatch{
   465  		Timestamp: time.Now(),
   466  		MetricSets: map[string]*core.MetricSet{
   467  			"pod1": &metricSet1,
   468  			"pod2": &metricSet2,
   469  		},
   470  	}
   471  
   472  	hSink.ExportData(&data)
   473  	assert.Equal(t, 2, len(calls))
   474  	assert.Equal(t, 2, len(ids))
   475  
   476  	assert.NotEqual(t, ids[0], ids[1])
   477  }
   478  
   479  func TestTags(t *testing.T) {
   480  	m := &sync.Mutex{}
   481  	calls := make([]string, 0, 2)
   482  	serverTags := make(map[string]string)
   483  	// how many times tags have been updated
   484  	tagsUpdated := 0
   485  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   486  		m.Lock()
   487  		defer m.Unlock()
   488  		calls = append(calls, r.RequestURI)
   489  		w.Header().Set("Content-Type", "application/json")
   490  
   491  		defer r.Body.Close()
   492  		b, err := ioutil.ReadAll(r.Body)
   493  		assert.NoError(t, err)
   494  
   495  		if strings.HasSuffix(r.RequestURI, "/tags") {
   496  			err := json.Unmarshal(b, &serverTags)
   497  			assert.NoError(t, err)
   498  			tagsUpdated++
   499  		}
   500  	}))
   501  	defer s.Close()
   502  
   503  	hSink, err := integSink(s.URL + "?tenant=test-heapster&labelToTenant=projectId")
   504  	assert.NoError(t, err)
   505  
   506  	l := make(map[string]string)
   507  	l["projectId"] = "test-label"
   508  	l[core.LabelContainerName.Key] = "test-container"
   509  	l[core.LabelPodId.Key] = "test-podid"
   510  	l[core.LabelLabels.Key] = "testLabelA:testValueA,testLabelB:testValueB"
   511  
   512  	labeledMetric := core.LabeledMetric{
   513  		Name: "test/metric/A",
   514  		Labels: map[string]string{
   515  			core.LabelResourceID.Key: "XYZ",
   516  		},
   517  		MetricValue: core.MetricValue{
   518  			MetricType: core.MetricGauge,
   519  			FloatValue: 124.456,
   520  		},
   521  	}
   522  
   523  	metricSet := core.MetricSet{
   524  		Labels:         l,
   525  		LabeledMetrics: []core.LabeledMetric{labeledMetric},
   526  		MetricValues: map[string]core.MetricValue{
   527  			"test/metric/A": {
   528  				ValueType:  core.ValueInt64,
   529  				MetricType: core.MetricCumulative,
   530  				IntValue:   123456,
   531  			},
   532  		},
   533  	}
   534  
   535  	smd := core.MetricDescriptor{
   536  		Name:      "test/metric/A",
   537  		Units:     core.UnitsBytes,
   538  		ValueType: core.ValueInt64,
   539  		Type:      core.MetricGauge,
   540  		Labels:    []core.LabelDescriptor{},
   541  	}
   542  
   543  	//register the metric definitions
   544  	hSink.Register([]core.MetricDescriptor{smd})
   545  	//register the metrics themselves
   546  	wg := &sync.WaitGroup{}
   547  	hSink.registerLabeledIfNecessaryInline(&metricSet, labeledMetric, wg)
   548  
   549  	wg.Wait()
   550  	assert.Equal(t, 1, tagsUpdated)
   551  
   552  	assert.True(t, hSink.expReg["test-container/test-podid/test/metric/A/XYZ"].hash > 0)
   553  
   554  	assert.Equal(t, 10, len(serverTags))
   555  	assert.Equal(t, "test-label", serverTags["projectId"])
   556  	assert.Equal(t, "test-container", serverTags[core.LabelContainerName.Key])
   557  	assert.Equal(t, "test-podid", serverTags[core.LabelPodId.Key])
   558  	assert.Equal(t, "test-container/test/metric/A", serverTags["group_id"])
   559  	assert.Equal(t, "test/metric/A", serverTags["descriptor_name"])
   560  	assert.Equal(t, "XYZ", serverTags[core.LabelResourceID.Key])
   561  	assert.Equal(t, "bytes", serverTags["units"])
   562  
   563  	assert.Equal(t, "testLabelA:testValueA,testLabelB:testValueB", serverTags[core.LabelLabels.Key])
   564  	assert.Equal(t, "testValueA", serverTags["labels.testLabelA"])
   565  	assert.Equal(t, "testValueB", serverTags["labels.testLabelB"])
   566  
   567  	// Make modifications to the metrics and check that they're updated correctly
   568  
   569  	// First, no changes - no update should happen
   570  	hSink.registerLabeledIfNecessaryInline(&metricSet, labeledMetric, wg)
   571  	wg.Wait()
   572  	assert.Equal(t, 1, tagsUpdated)
   573  
   574  	// Now modify the labels and expect an update
   575  	metricSet.Labels[core.LabelLabels.Key] = "testLabelA:testValueA,testLabelB:testValueB,testLabelC:testValueC"
   576  	hSink.registerLabeledIfNecessaryInline(&metricSet, labeledMetric, wg)
   577  	wg.Wait()
   578  	assert.Equal(t, 2, tagsUpdated)
   579  
   580  	assert.Equal(t, "testLabelA:testValueA,testLabelB:testValueB,testLabelC:testValueC", serverTags[core.LabelLabels.Key])
   581  	assert.Equal(t, "testValueA", serverTags["labels.testLabelA"])
   582  	assert.Equal(t, "testValueB", serverTags["labels.testLabelB"])
   583  	assert.Equal(t, "testValueC", serverTags["labels.testLabelC"])
   584  }
   585  
   586  func TestExpiringCache(t *testing.T) {
   587  	total := 10
   588  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   589  		w.WriteHeader(http.StatusOK)
   590  	}))
   591  	defer s.Close()
   592  
   593  	hSink, err := integSink(s.URL + "?tenant=test-heapster&labelToTenant=projectId&batchSize=20&concurrencyLimit=5")
   594  	assert.NoError(t, err)
   595  
   596  	l := make(map[string]string)
   597  	l["projectId"] = "test-label"
   598  	l[core.LabelContainerName.Key] = "test-container"
   599  	l[core.LabelPodId.Key] = "test-podid"
   600  
   601  	metrics := make(map[string]core.MetricValue, total)
   602  	descriptors := make([]core.MetricDescriptor, total)
   603  	for i := 0; i < total; i++ {
   604  		id := fmt.Sprintf("test/metric/%d", i)
   605  		metrics[id] = core.MetricValue{
   606  			ValueType:  core.ValueInt64,
   607  			MetricType: core.MetricCumulative,
   608  			IntValue:   123 * int64(i),
   609  		}
   610  		descriptors = append(descriptors, core.MetricDescriptor{
   611  			Name:      id,
   612  			Units:     core.UnitsBytes,
   613  			ValueType: core.ValueInt64,
   614  			Type:      core.MetricGauge,
   615  		})
   616  	}
   617  
   618  	err = hSink.Register(descriptors)
   619  	assert.NoError(t, err)
   620  
   621  	metricSet := core.MetricSet{
   622  		Labels:       l,
   623  		MetricValues: metrics,
   624  	}
   625  
   626  	data := core.DataBatch{
   627  		Timestamp: time.Now(),
   628  		MetricSets: map[string]*core.MetricSet{
   629  			"pod1": &metricSet,
   630  		},
   631  	}
   632  
   633  	hSink.ExportData(&data)
   634  	hSink.regLock.RLock()
   635  	assert.Equal(t, total, len(hSink.expReg))
   636  	assert.Equal(t, uint64(1), hSink.expReg["test-container/test-podid/test/metric/9"].ttl)
   637  	hSink.regLock.RUnlock()
   638  
   639  	// Now delete part of the metrics and then check that they're expired
   640  	delete(metrics, "test/metric/1")
   641  	delete(metrics, "test/metric/6")
   642  
   643  	data.Timestamp = time.Now()
   644  	hSink.ExportData(&data)
   645  	hSink.regLock.RLock()
   646  	assert.Equal(t, total, len(hSink.expReg))
   647  	assert.Equal(t, uint64(2), hSink.expReg["test-container/test-podid/test/metric/9"].ttl)
   648  	hSink.regLock.RUnlock()
   649  
   650  	data.Timestamp = time.Now()
   651  	hSink.ExportData(&data)
   652  	hSink.regLock.RLock()
   653  	assert.Equal(t, total-2, len(hSink.expReg))
   654  	hSink.regLock.RUnlock()
   655  }
   656  
   657  func TestUserPass(t *testing.T) {
   658  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   659  		w.Header().Set("X-Authorization", r.Header.Get("Authorization"))
   660  		auth := strings.SplitN(r.Header.Get("Authorization"), " ", 2)
   661  		if len(auth) != 2 || auth[0] != "Basic" {
   662  			assert.FailNow(t, "Could not find Basic authentication")
   663  		}
   664  		assert.True(t, len(auth[1]) > 0)
   665  		w.WriteHeader(http.StatusNoContent)
   666  	}))
   667  	defer s.Close()
   668  
   669  	hSink, err := integSink(s.URL + "?user=tester&pass=hidden")
   670  	assert.NoError(t, err)
   671  	assert.Equal(t, 1, len(hSink.modifiers))
   672  
   673  	// md := make([]core.MetricDescriptor, 0, 1)
   674  	ld := core.LabelDescriptor{
   675  		Key:         "k1",
   676  		Description: "d1",
   677  	}
   678  	smd := core.MetricDescriptor{
   679  		Name:      "test/metric/1",
   680  		Units:     core.UnitsBytes,
   681  		ValueType: core.ValueInt64,
   682  		Type:      core.MetricGauge,
   683  		Labels:    []core.LabelDescriptor{ld},
   684  	}
   685  	err = hSink.Register([]core.MetricDescriptor{smd})
   686  	assert.NoError(t, err)
   687  }
   688  
   689  func TestFiltering(t *testing.T) {
   690  	m := &sync.Mutex{}
   691  	mH := []metrics.MetricHeader{}
   692  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   693  		m.Lock()
   694  		defer m.Unlock()
   695  		if strings.Contains(r.RequestURI, "raw") {
   696  			defer r.Body.Close()
   697  			b, err := ioutil.ReadAll(r.Body)
   698  			assert.NoError(t, err)
   699  
   700  			err = json.Unmarshal(b, &mH)
   701  			assert.NoError(t, err)
   702  		}
   703  	}))
   704  	defer s.Close()
   705  
   706  	hSink, err := integSink(s.URL + "?filter=label(namespace_id:^$)&filter=label(container_name:^[/system.slice/|/user.slice].*)&filter=name(remove*)")
   707  	assert.NoError(t, err)
   708  
   709  	l := make(map[string]string)
   710  	l["namespace_id"] = "123"
   711  	l["container_name"] = "/system.slice/-.mount"
   712  	l[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   713  
   714  	l2 := make(map[string]string)
   715  	l2["namespace_id"] = "123"
   716  	l2["container_name"] = "/system.slice/dbus.service"
   717  	l2[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   718  
   719  	l3 := make(map[string]string)
   720  	l3["namespace_id"] = "123"
   721  	l3[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   722  
   723  	l4 := make(map[string]string)
   724  	l4["namespace_id"] = ""
   725  	l4[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   726  
   727  	l5 := make(map[string]string)
   728  	l5["namespace_id"] = "123"
   729  	l5[core.LabelPodId.Key] = "aaaa-bbbb-cccc-dddd"
   730  
   731  	metricSet1 := core.MetricSet{
   732  		Labels: l,
   733  		MetricValues: map[string]core.MetricValue{
   734  			"/system.slice/-.mount//cpu/limit": {
   735  				ValueType:  core.ValueInt64,
   736  				MetricType: core.MetricCumulative,
   737  				IntValue:   123456,
   738  			},
   739  		},
   740  	}
   741  
   742  	metricSet2 := core.MetricSet{
   743  		Labels: l2,
   744  		MetricValues: map[string]core.MetricValue{
   745  			"/system.slice/dbus.service//cpu/usage": {
   746  				ValueType:  core.ValueInt64,
   747  				MetricType: core.MetricCumulative,
   748  				IntValue:   123456,
   749  			},
   750  		},
   751  	}
   752  
   753  	metricSet3 := core.MetricSet{
   754  		Labels: l3,
   755  		MetricValues: map[string]core.MetricValue{
   756  			"test/metric/1": {
   757  				ValueType:  core.ValueInt64,
   758  				MetricType: core.MetricCumulative,
   759  				IntValue:   123456,
   760  			},
   761  		},
   762  	}
   763  
   764  	metricSet4 := core.MetricSet{
   765  		Labels: l4,
   766  		MetricValues: map[string]core.MetricValue{
   767  			"test/metric/1": {
   768  				ValueType:  core.ValueInt64,
   769  				MetricType: core.MetricCumulative,
   770  				IntValue:   123456,
   771  			},
   772  		},
   773  	}
   774  
   775  	metricSet5 := core.MetricSet{
   776  		Labels: l5,
   777  		MetricValues: map[string]core.MetricValue{
   778  			"removeme": {
   779  				ValueType:  core.ValueInt64,
   780  				MetricType: core.MetricCumulative,
   781  				IntValue:   123456,
   782  			},
   783  		},
   784  	}
   785  
   786  	data := core.DataBatch{
   787  		Timestamp: time.Now(),
   788  		MetricSets: map[string]*core.MetricSet{
   789  			"pod1": &metricSet1,
   790  			"pod2": &metricSet2,
   791  			"pod3": &metricSet3,
   792  			"pod4": &metricSet4,
   793  			"pod5": &metricSet5,
   794  		},
   795  	}
   796  	hSink.ExportData(&data)
   797  
   798  	assert.Equal(t, 1, len(mH))
   799  }
   800  func TestBatchingTimeseries(t *testing.T) {
   801  	total := 1000
   802  	m := &sync.Mutex{}
   803  	ids := make([]string, 0, total)
   804  	calls := 0
   805  
   806  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   807  		m.Lock()
   808  		defer m.Unlock()
   809  
   810  		w.Header().Set("Content-Type", "application/json")
   811  
   812  		defer r.Body.Close()
   813  		b, err := ioutil.ReadAll(r.Body)
   814  		assert.NoError(t, err)
   815  
   816  		mH := []metrics.MetricHeader{}
   817  		err = json.Unmarshal(b, &mH)
   818  		assert.NoError(t, err)
   819  
   820  		for _, v := range mH {
   821  			ids = append(ids, v.ID)
   822  		}
   823  
   824  		calls++
   825  	}))
   826  	defer s.Close()
   827  
   828  	hSink, err := integSink(s.URL + "?tenant=test-heapster&labelToTenant=projectId&batchSize=20&concurrencyLimit=5")
   829  	assert.NoError(t, err)
   830  
   831  	l := make(map[string]string)
   832  	l["projectId"] = "test-label"
   833  	l[core.LabelContainerName.Key] = "test-container"
   834  	l[core.LabelPodId.Key] = "test-podid"
   835  
   836  	metrics := make(map[string]core.MetricValue)
   837  	for i := 0; i < total; i++ {
   838  		id := fmt.Sprintf("test/metric/%d", i)
   839  		metrics[id] = core.MetricValue{
   840  			ValueType:  core.ValueInt64,
   841  			MetricType: core.MetricCumulative,
   842  			IntValue:   123 * int64(i),
   843  		}
   844  	}
   845  
   846  	metricSet := core.MetricSet{
   847  		Labels:       l,
   848  		MetricValues: metrics,
   849  	}
   850  
   851  	data := core.DataBatch{
   852  		Timestamp: time.Now(),
   853  		MetricSets: map[string]*core.MetricSet{
   854  			"pod1": &metricSet,
   855  		},
   856  	}
   857  
   858  	hSink.ExportData(&data)
   859  	assert.Equal(t, total, len(ids))
   860  	assert.Equal(t, calls, 50)
   861  
   862  	// Verify that all ids are unique
   863  	newIds := make(map[string]bool)
   864  	for _, v := range ids {
   865  		if newIds[v] {
   866  			t.Errorf("Key %s was duplicate", v)
   867  		}
   868  		newIds[v] = true
   869  	}
   870  }
   871  
   872  func BenchmarkTagsUpdates(b *testing.B) {
   873  	http.DefaultTransport.(*http.Transport).MaxIdleConnsPerHost = 100
   874  	s := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
   875  		w.WriteHeader(http.StatusOK)
   876  	}))
   877  	defer s.Close()
   878  	hSink, err := integSink(s.URL + "?tenant=test-heapster&labelToTenant=projectId&batchSize=1000&concurrencyLimit=16")
   879  	if err != nil {
   880  		b.FailNow()
   881  	}
   882  
   883  	smd := core.MetricDescriptor{
   884  		Name:      "test/metric/A",
   885  		Units:     core.UnitsBytes,
   886  		ValueType: core.ValueInt64,
   887  		Type:      core.MetricGauge,
   888  		Labels:    []core.LabelDescriptor{},
   889  	}
   890  
   891  	//register the metric definitions
   892  	hSink.Register([]core.MetricDescriptor{smd})
   893  	total := 10000
   894  
   895  	mset := make(map[string]*core.MetricSet)
   896  	for i := 0; i < total; i++ {
   897  		id := fmt.Sprintf("pod-%d", i)
   898  
   899  		l := make(map[string]string)
   900  		l["projectId"] = strconv.Itoa(i)
   901  		for i := 0; i < 32; i++ {
   902  			tagName := fmt.Sprintf("tag_name_%d", i)
   903  			tagValue := fmt.Sprintf("tag_value_%d", i)
   904  			l[tagName] = tagValue
   905  			l[core.LabelPodId.Key] = id
   906  		}
   907  
   908  		metrics := make(map[string]core.MetricValue)
   909  		metrics["test/metric/A"] = core.MetricValue{
   910  			ValueType:  core.ValueInt64,
   911  			MetricType: core.MetricCumulative,
   912  			IntValue:   123,
   913  		}
   914  
   915  		metricSet := core.MetricSet{
   916  			Labels:       l,
   917  			MetricValues: metrics,
   918  		}
   919  		mset[id] = &metricSet
   920  	}
   921  
   922  	data := core.DataBatch{
   923  		Timestamp:  time.Now(),
   924  		MetricSets: mset,
   925  	}
   926  
   927  	fmt.Printf("Generated data with %d metricSets\n", len(data.MetricSets))
   928  	hSink.init()
   929  	hSink.Register([]core.MetricDescriptor{smd})
   930  	b.ResetTimer()
   931  	for j := 0; j < b.N; j++ {
   932  		for a := 0; a < 10; a++ {
   933  			data.Timestamp = time.Now()
   934  			hSink.ExportData(&data)
   935  		}
   936  	}
   937  
   938  	fmt.Printf("Amount of unique definitions: %d\n", len(hSink.expReg))
   939  }