github.com/m3db/m3@v1.5.0/src/aggregator/integration/one_client_passthru_test.go (about) 1 // +build integration 2 3 // Copyright (c) 2020 Uber Technologies, Inc. 4 // 5 // Permission is hereby granted, free of charge, to any person obtaining a copy 6 // of this software and associated documentation files (the "Software"), to deal 7 // in the Software without restriction, including without limitation the rights 8 // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 // copies of the Software, and to permit persons to whom the Software is 10 // furnished to do so, subject to the following conditions: 11 // 12 // The above copyright notice and this permission notice shall be included in 13 // all copies or substantial portions of the Software. 14 // 15 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 // THE SOFTWARE. 22 23 package integration 24 25 import ( 26 "reflect" 27 "sort" 28 "testing" 29 "time" 30 31 aggclient "github.com/m3db/m3/src/aggregator/client" 32 "github.com/m3db/m3/src/cluster/placement" 33 "github.com/m3db/m3/src/metrics/metric" 34 "github.com/m3db/m3/src/metrics/metric/aggregated" 35 "github.com/m3db/m3/src/metrics/policy" 36 xtime "github.com/m3db/m3/src/x/time" 37 38 "github.com/stretchr/testify/require" 39 ) 40 41 func TestOneClientPassthroughMetrics(t *testing.T) { 42 if testing.Short() { 43 t.SkipNow() 44 } 45 46 aggregatorClientType, err := getAggregatorClientTypeFromEnv() 47 require.NoError(t, err) 48 if aggregatorClientType == aggclient.M3MsgAggregatorClient { 49 // m3msg client doesn't support passthrough messages 50 t.SkipNow() 51 } 52 53 serverOpts := newTestServerOptions(t) 54 55 // Clock setup. 56 clock := newTestClock(time.Now().Truncate(time.Hour)) 57 serverOpts = serverOpts.SetClockOptions(clock.Options()) 58 59 // Placement setup. 60 numShards := 1024 61 cfg := placementInstanceConfig{ 62 instanceID: serverOpts.InstanceID(), 63 shardSetID: serverOpts.ShardSetID(), 64 shardStartInclusive: 0, 65 shardEndExclusive: uint32(numShards), 66 } 67 instance := cfg.newPlacementInstance() 68 placement := newPlacement(numShards, []placement.Instance{instance}) 69 placementKey := serverOpts.PlacementKVKey() 70 setPlacement(t, placementKey, serverOpts.ClusterClient(), placement) 71 72 // Create server. 73 testServer := newTestServerSetup(t, serverOpts) 74 defer testServer.close() 75 76 // Start the server. 77 log := testServer.aggregatorOpts.InstrumentOptions().Logger() 78 log.Info("test one client sending of passthrough metrics") 79 require.NoError(t, testServer.startServer()) 80 log.Info("server is now up") 81 require.NoError(t, testServer.waitUntilLeader()) 82 log.Info("server is now the leader") 83 84 var ( 85 idPrefix = "full.passthru.id" 86 numIDs = 10 87 start = clock.Now() 88 stop = start.Add(10 * time.Second) 89 interval = 2 * time.Second 90 ) 91 client := testServer.newClient(t) 92 require.NoError(t, client.connect()) 93 94 ids := generateTestIDs(idPrefix, numIDs) 95 metadataFn := func(idx int) metadataUnion { 96 return metadataUnion{ 97 mType: passthroughMetadataType, 98 passthroughMetadata: policy.NewStoragePolicy(2*time.Second, xtime.Second, time.Hour), 99 } 100 } 101 dataset := mustGenerateTestDataset(t, datasetGenOpts{ 102 start: start, 103 stop: stop, 104 interval: interval, 105 ids: ids, 106 category: passthroughMetric, 107 typeFn: constantMetricTypeFnFactory(metric.GaugeType), 108 valueGenOpts: defaultValueGenOpts, 109 metadataFn: metadataFn, 110 }) 111 112 for _, data := range dataset { 113 clock.SetNow(data.timestamp) 114 for _, mm := range data.metricWithMetadatas { 115 require.NoError(t, client.writePassthroughMetricWithMetadata(mm.metric.passthrough, mm.metadata.passthroughMetadata)) 116 } 117 require.NoError(t, client.flush()) 118 119 // Give server some time to process the incoming packets. 120 time.Sleep(100 * time.Millisecond) 121 } 122 123 // Move time forward and wait for flushing to happen. 124 finalTime := stop.Add(time.Minute + 2*time.Second) 125 clock.SetNow(finalTime) 126 time.Sleep(2 * time.Second) 127 128 require.NoError(t, client.close()) 129 130 // Stop the server. 131 require.NoError(t, testServer.stopServer()) 132 log.Info("server is now down") 133 134 // Validate results. 135 expected := computeExpectedPassthroughResults(t, dataset) 136 actual := testServer.sortedResults() 137 require.Equal(t, dedupResults(expected), dedupResults(actual)) 138 } 139 140 func computeExpectedPassthroughResults( 141 t *testing.T, 142 dataset testDataset, 143 ) []aggregated.MetricWithStoragePolicy { 144 var expected []aggregated.MetricWithStoragePolicy 145 for _, testData := range dataset { 146 for _, metricWithMetadata := range testData.metricWithMetadatas { 147 require.Equal(t, passthroughMetric, metricWithMetadata.metric.category) 148 149 expectedPassthrough := aggregated.MetricWithStoragePolicy{ 150 Metric: metricWithMetadata.metric.passthrough, 151 StoragePolicy: metricWithMetadata.metadata.passthroughMetadata, 152 } 153 154 // The capturingWriter writes ChunkedMetricWithStoragePolicy which has no metric type defined. 155 expectedPassthrough.Metric.Type = metric.UnknownType 156 expected = append(expected, expectedPassthrough) 157 } 158 } 159 // Sort the aggregated metrics. 160 sort.Sort(byTimeIDPolicyAscending(expected)) 161 return expected 162 } 163 164 func dedupResults( 165 results []aggregated.MetricWithStoragePolicy, 166 ) []aggregated.MetricWithStoragePolicy { 167 var deduped []aggregated.MetricWithStoragePolicy 168 lenDeduped := 0 169 for _, m := range results { 170 if lenDeduped == 0 || !reflect.DeepEqual(deduped[lenDeduped-1], m) { 171 deduped = append(deduped, m) 172 lenDeduped++ 173 } 174 } 175 return deduped 176 }