2016-11-22 03:48:30 -08:00
// Copyright 2016 The Prometheus Authors
// 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 discovery
import (
2017-10-24 21:21:42 -07:00
"context"
2017-11-11 18:39:08 -08:00
"reflect"
2017-11-06 08:14:15 -08:00
"sync"
"sync/atomic"
2016-11-22 03:48:30 -08:00
"testing"
2017-11-06 09:33:52 -08:00
"time"
2016-11-22 03:48:30 -08:00
2017-11-11 18:39:08 -08:00
"github.com/prometheus/common/model"
2016-11-22 03:48:30 -08:00
"github.com/prometheus/prometheus/config"
yaml "gopkg.in/yaml.v2"
)
2017-11-11 18:39:08 -08:00
func TestTargetSetThrottlesTheSyncCalls ( t * testing . T ) {
testCases := [ ] struct {
title string
updates map [ string ] [ ] update
expectedSyncCalls [ ] [ ] string
} {
{
title : "Single TP no updates" ,
updates : map [ string ] [ ] update {
"tp1" : { } ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
} ,
2017-11-06 09:33:52 -08:00
} ,
2017-11-11 18:39:08 -08:00
{
title : "Multips TPs no updates" ,
updates : map [ string ] [ ] update {
"tp1" : { } ,
"tp2" : { } ,
"tp3" : { } ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
} ,
2017-11-06 09:33:52 -08:00
} ,
2017-11-11 18:39:08 -08:00
{
title : "Single TP empty initials" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 5 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
} ,
2017-11-06 09:33:52 -08:00
} ,
2017-11-11 18:39:08 -08:00
{
title : "Multiple TPs empty initials" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 5 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 500 ,
} ,
} ,
"tp3" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 100 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
} ,
2017-11-06 09:33:52 -08:00
} ,
2017-11-11 18:39:08 -08:00
{
title : "Multiple TPs empty initials with a delay" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 6000 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 6500 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
} ,
} ,
{
title : "Single TP initials only" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 0 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" , "initial2" } ,
} ,
} ,
{
title : "Multiple TPs initials only" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } , { Source : "tp1-initial2" } } ,
interval : 0 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } } ,
interval : 0 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-initial2" , "tp2-initial1" } ,
} ,
} ,
{
title : "Single TP delayed initials only" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 6000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
{ "initial1" , "initial2" } ,
} ,
} ,
{
title : "Multiple TPs with some delayed initials" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } , { Source : "tp1-initial2" } } ,
interval : 100 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } , { Source : "tp2-initial2" } , { Source : "tp2-initial3" } } ,
interval : 6000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-initial2" } ,
{ "tp1-initial1" , "tp1-initial2" , "tp2-initial1" , "tp2-initial2" , "tp2-initial3" } ,
} ,
} ,
{
title : "Single TP initials followed by empty updates" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 0 ,
} ,
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 10 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" , "initial2" } ,
} ,
} ,
{
title : "Single TP initials and new groups" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 0 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update1" } , { Source : "update2" } } ,
interval : 10 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" , "initial2" } ,
{ "initial1" , "initial2" , "update1" , "update2" } ,
} ,
} ,
{
title : "Multiple TPs initials and new groups" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } , { Source : "tp1-initial2" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update1" } , { Source : "tp1-update2" } } ,
interval : 1500 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } , { Source : "tp2-initial2" } } ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-update1" } , { Source : "tp2-update2" } } ,
interval : 10 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-initial2" , "tp2-initial1" , "tp2-initial2" } ,
{ "tp1-initial1" , "tp1-initial2" , "tp2-initial1" , "tp2-initial2" , "tp1-update1" , "tp1-update2" , "tp2-update1" , "tp2-update2" } ,
} ,
} ,
{
title : "One tp initials arrive after other tp updates but still within 5 seconds" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } , { Source : "tp1-initial2" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update1" } , { Source : "tp1-update2" } } ,
interval : 1500 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } , { Source : "tp2-initial2" } } ,
interval : 2000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-update1" } , { Source : "tp2-update2" } } ,
interval : 1000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-initial2" , "tp1-update1" , "tp1-update2" , "tp2-initial1" , "tp2-initial2" } ,
{ "tp1-initial1" , "tp1-initial2" , "tp1-update1" , "tp1-update2" , "tp2-initial1" , "tp2-initial2" , "tp2-update1" , "tp2-update2" } ,
} ,
} ,
{
title : "One tp initials arrive after other tp updates and after 5 seconds" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } , { Source : "tp1-initial2" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update1" } , { Source : "tp1-update2" } } ,
interval : 1500 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update3" } } ,
interval : 5000 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } , { Source : "tp2-initial2" } } ,
interval : 6000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-initial2" , "tp1-update1" , "tp1-update2" } ,
{ "tp1-initial1" , "tp1-initial2" , "tp1-update1" , "tp1-update2" , "tp2-initial1" , "tp2-initial2" , "tp1-update3" } ,
} ,
} ,
{
title : "Single TP initials and new groups after a delay" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 6000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update1" } , { Source : "update2" } } ,
interval : 10 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ } ,
{ "initial1" , "initial2" , "update1" , "update2" } ,
} ,
} ,
{
title : "Single TP initial and successive updates" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } } ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update1" } } ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update2" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update3" } } ,
interval : 10 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" } ,
{ "initial1" , "update1" , "update2" , "update3" } ,
} ,
} ,
{
title : "Multiple TPs initials and successive updates" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-initial1" } } ,
interval : 1000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update1" } } ,
interval : 1000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update2" } } ,
interval : 2000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp1-update3" } } ,
interval : 2000 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-initial1" } } ,
interval : 3000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-update1" } } ,
interval : 1000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-update2" } } ,
interval : 3000 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "tp2-update3" } } ,
interval : 2000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "tp1-initial1" , "tp1-update1" , "tp2-initial1" } ,
{ "tp1-initial1" , "tp1-update1" , "tp2-initial1" , "tp1-update2" , "tp1-update3" , "tp2-update1" , "tp2-update2" } ,
{ "tp1-initial1" , "tp1-update1" , "tp2-initial1" , "tp1-update2" , "tp1-update3" , "tp2-update1" , "tp2-update2" , "tp2-update3" } ,
} ,
} ,
{
title : "Single TP Multiple updates 5 second window" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update1" } } ,
interval : 25 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update2" } , { Source : "update3" } , { Source : "update4" } } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update5" } } ,
interval : 0 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update6" } , { Source : "update7" } , { Source : "update8" } } ,
interval : 70 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" } ,
{ "initial1" , "update1" , "update2" , "update3" , "update4" , "update5" , "update6" , "update7" , "update8" } ,
} ,
} ,
{
title : "Single TP Single provider empty update in between" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 30 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update1" } , { Source : "update2" } } ,
interval : 300 ,
} ,
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup { { Source : "update3" } , { Source : "update4" } , { Source : "update5" } , { Source : "update6" } } ,
interval : 6000 ,
} ,
} ,
} ,
expectedSyncCalls : [ ] [ ] string {
{ "initial1" , "initial2" } ,
{ "initial1" , "initial2" , "update1" , "update2" } ,
{ "initial1" , "initial2" , "update1" , "update2" , "update3" , "update4" , "update5" , "update6" } ,
} ,
2017-11-06 09:33:52 -08:00
} ,
}
2017-11-11 18:39:08 -08:00
for i , testCase := range testCases {
finalize := make ( chan bool )
2017-11-06 09:33:52 -08:00
2017-11-11 18:39:08 -08:00
syncCallCount := 0
syncedGroups := make ( [ ] [ ] string , 0 )
2017-11-06 09:33:52 -08:00
targetSet := NewTargetSet ( & mockSyncer {
sync : func ( tgs [ ] * config . TargetGroup ) {
2017-11-11 18:39:08 -08:00
currentCallGroup := make ( [ ] string , len ( tgs ) )
for i , tg := range tgs {
currentCallGroup [ i ] = tg . Source
2017-11-06 09:33:52 -08:00
}
2017-11-11 18:39:08 -08:00
syncedGroups = append ( syncedGroups , currentCallGroup )
2017-11-06 09:33:52 -08:00
2017-11-11 18:39:08 -08:00
syncCallCount ++
if syncCallCount == len ( testCase . expectedSyncCalls ) {
2017-11-06 09:33:52 -08:00
// All the groups are sent, we can start asserting.
2017-11-11 18:39:08 -08:00
close ( finalize )
2017-11-06 09:33:52 -08:00
}
} ,
} )
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
targetProviders := map [ string ] TargetProvider { }
2017-11-11 18:39:08 -08:00
for tpName , tpUpdates := range testCase . updates {
tp := newMockTargetProvider ( tpUpdates )
targetProviders [ tpName ] = tp
}
2017-11-06 09:33:52 -08:00
go targetSet . Run ( ctx )
targetSet . UpdateProviders ( targetProviders )
select {
2017-11-11 18:39:08 -08:00
case <- time . After ( 20 * time . Second ) :
t . Errorf ( "%d. %q: Test timed out after 20 seconds. All targets should be sent within the timeout" , i , testCase . title )
2017-11-06 09:33:52 -08:00
case <- finalize :
2017-11-11 18:39:08 -08:00
for name , tp := range targetProviders {
2017-11-12 08:47:30 -08:00
runCallCount := tp . ( mockTargetProvider ) . callCount ( )
2017-11-11 18:39:08 -08:00
if runCallCount != 1 {
t . Errorf ( "%d. %q: TargetProvider Run should be called once for each target provider. For %q was called %d times" , i , testCase . title , name , runCallCount )
}
}
2017-11-06 09:33:52 -08:00
2017-11-11 18:39:08 -08:00
if len ( syncedGroups ) != len ( testCase . expectedSyncCalls ) {
t . Errorf ( "%d. %q: received sync calls: \n %v \n do not match expected calls: \n %v \n" , i , testCase . title , syncedGroups , testCase . expectedSyncCalls )
2017-11-06 09:33:52 -08:00
}
2017-11-11 18:39:08 -08:00
for j := range syncedGroups {
if len ( syncedGroups [ j ] ) != len ( testCase . expectedSyncCalls [ j ] ) {
t . Errorf ( "%d. %q: received sync calls in call [%v]: \n %v \n do not match expected calls: \n %v \n" , i , testCase . title , j , syncedGroups [ j ] , testCase . expectedSyncCalls [ j ] )
2017-11-06 09:33:52 -08:00
}
2017-11-11 18:39:08 -08:00
expectedGroupsMap := make ( map [ string ] struct { } )
for _ , expectedGroup := range testCase . expectedSyncCalls [ j ] {
expectedGroupsMap [ expectedGroup ] = struct { } { }
}
for _ , syncedGroup := range syncedGroups [ j ] {
if _ , ok := expectedGroupsMap [ syncedGroup ] ; ! ok {
t . Errorf ( "%d. %q: '%s' does not exist in expected target groups: %s" , i , testCase . title , syncedGroup , testCase . expectedSyncCalls [ j ] )
} else {
delete ( expectedGroupsMap , syncedGroup ) // Remove used targets from the map.
}
}
}
}
}
}
func TestTargetSetConsolidatesToTheLatestState ( t * testing . T ) {
testCases := [ ] struct {
title string
updates map [ string ] [ ] update
} {
{
title : "Single TP update same initial group multiple times" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } } ,
} ,
} ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } , { "__instance__" : "10.11.122.12:6003" } } ,
} ,
} ,
interval : 250 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.12:6003" } } ,
} ,
} ,
interval : 250 ,
} ,
} ,
} ,
} ,
{
title : "Multiple TPs update" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } } ,
} ,
} ,
interval : 3 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.12:6003" } } ,
} ,
} ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.12:6003" } ,
{ "__instance__" : "10.11.122.13:6003" } ,
{ "__instance__" : "10.11.122.14:6003" } ,
} ,
} ,
} ,
interval : 10 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } } ,
} ,
} ,
interval : 3 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.12:6003" } } ,
} ,
} ,
interval : 10 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-update1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.12:6003" } ,
{ "__instance__" : "10.11.122.13:6003" } ,
{ "__instance__" : "10.11.122.14:6003" } ,
} ,
} ,
} ,
interval : 10 ,
} ,
} ,
} ,
} ,
{
title : "Multiple TPs update II" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } } ,
} ,
{
Source : "tp1-initial2" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.12:6003" } } ,
} ,
} ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.13:6003" } } ,
} ,
{
Source : "tp1-initial2" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.12:6003" } ,
{ "__instance__" : "10.11.122.14:6003" } ,
} ,
} ,
} ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-update2" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.15:6003" } } ,
} ,
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet { } ,
} ,
} ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.16:6003" } ,
{ "__instance__" : "10.11.122.17:6003" } ,
{ "__instance__" : "10.11.122.18:6003" } ,
} ,
} ,
} ,
interval : 100 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup { } ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-update1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.13:6003" } } ,
} ,
} ,
interval : 100 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-update2" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.15:6003" } } ,
} ,
{
Source : "tp2-update1" ,
Targets : [ ] model . LabelSet { } ,
} ,
} ,
interval : 300 ,
} ,
} ,
} ,
} ,
{
title : "Three rounds of sync call" ,
updates : map [ string ] [ ] update {
"tp1" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.11:6003" } ,
{ "__instance__" : "10.11.122.12:6003" } ,
{ "__instance__" : "10.11.122.13:6003" } ,
} ,
} ,
{
Source : "tp1-initial2" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.14:6003" } } ,
} ,
} ,
interval : 1000 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.12:6003" } } ,
} ,
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.15:6003" } } ,
} ,
} ,
interval : 3000 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp1-initial1" ,
Targets : [ ] model . LabelSet { } ,
} ,
{
Source : "tp1-update1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.15:6003" } ,
{ "__instance__" : "10.11.122.16:6003" } ,
} ,
} ,
} ,
interval : 3000 ,
} ,
} ,
"tp2" : {
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-initial1" ,
Targets : [ ] model . LabelSet {
{ "__instance__" : "10.11.122.11:6003" } ,
} ,
} ,
{
Source : "tp2-initial2" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.14:6003" } } ,
} ,
{
Source : "tp2-initial3" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.15:6003" } } ,
} ,
} ,
interval : 6000 ,
} ,
{
targetGroups : [ ] config . TargetGroup {
{
Source : "tp2-initial1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.11:6003" } , { "__instance__" : "10.11.122.12:6003" } } ,
} ,
{
Source : "tp2-update1" ,
Targets : [ ] model . LabelSet { { "__instance__" : "10.11.122.15:6003" } } ,
} ,
} ,
interval : 3000 ,
} ,
} ,
} ,
} ,
}
// Function to determine if the sync call received the latest state of
// all the target groups that came out of the target provider.
endStateAchieved := func ( groupsSentToSyc [ ] * config . TargetGroup , endState map [ string ] config . TargetGroup ) bool {
if len ( groupsSentToSyc ) != len ( endState ) {
return false
}
for _ , tg := range groupsSentToSyc {
if _ , ok := endState [ tg . Source ] ; ok == false {
// The target group does not exist in the end state.
return false
2017-11-06 09:33:52 -08:00
}
2017-11-11 18:39:08 -08:00
if reflect . DeepEqual ( endState [ tg . Source ] , * tg ) == false {
// The target group has not reached its final state yet.
return false
2017-11-06 09:33:52 -08:00
}
2017-11-11 18:39:08 -08:00
delete ( endState , tg . Source ) // Remove used target groups.
}
return true
}
for i , testCase := range testCases {
expectedGroups := make ( map [ string ] config . TargetGroup )
for _ , tpUpdates := range testCase . updates {
for _ , update := range tpUpdates {
for _ , targetGroup := range update . targetGroups {
expectedGroups [ targetGroup . Source ] = targetGroup
2017-11-06 09:33:52 -08:00
}
}
}
2017-11-11 18:39:08 -08:00
finalize := make ( chan bool )
targetSet := NewTargetSet ( & mockSyncer {
sync : func ( tgs [ ] * config . TargetGroup ) {
endState := make ( map [ string ] config . TargetGroup )
for k , v := range expectedGroups {
endState [ k ] = v
}
if endStateAchieved ( tgs , endState ) == false {
return
}
close ( finalize )
} ,
} )
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
targetProviders := map [ string ] TargetProvider { }
for tpName , tpUpdates := range testCase . updates {
tp := newMockTargetProvider ( tpUpdates )
targetProviders [ tpName ] = tp
}
go targetSet . Run ( ctx )
targetSet . UpdateProviders ( targetProviders )
select {
case <- time . After ( 20 * time . Second ) :
t . Errorf ( "%d. %q: Test timed out after 20 seconds. All targets should be sent within the timeout" , i , testCase . title )
case <- finalize :
// System successfully reached to the end state.
}
2017-11-06 09:33:52 -08:00
}
}
2016-11-22 03:48:30 -08:00
func TestTargetSetRecreatesTargetGroupsEveryRun ( t * testing . T ) {
verifyPresence := func ( tgroups map [ string ] * config . TargetGroup , name string , present bool ) {
if _ , ok := tgroups [ name ] ; ok != present {
msg := ""
if ! present {
msg = "not "
}
t . Fatalf ( "'%s' should %sbe present in TargetSet.tgroups: %s" , name , msg , tgroups )
}
}
2016-11-23 03:41:19 -08:00
cfg := & config . ServiceDiscoveryConfig { }
2016-11-22 03:48:30 -08:00
sOne := `
static_configs :
- targets : [ "foo:9090" ]
- targets : [ "bar:9090" ]
`
2016-11-23 03:41:19 -08:00
if err := yaml . Unmarshal ( [ ] byte ( sOne ) , cfg ) ; err != nil {
2016-11-22 03:48:30 -08:00
t . Fatalf ( "Unable to load YAML config sOne: %s" , err )
}
called := make ( chan struct { } )
ts := NewTargetSet ( & mockSyncer {
sync : func ( [ ] * config . TargetGroup ) { called <- struct { } { } } ,
} )
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
go ts . Run ( ctx )
2017-08-11 11:45:52 -07:00
ts . UpdateProviders ( ProvidersFromConfig ( * cfg , nil ) )
2016-11-22 03:48:30 -08:00
<- called
verifyPresence ( ts . tgroups , "static/0/0" , true )
verifyPresence ( ts . tgroups , "static/0/1" , true )
sTwo := `
static_configs :
- targets : [ "foo:9090" ]
`
2016-11-23 03:41:19 -08:00
if err := yaml . Unmarshal ( [ ] byte ( sTwo ) , cfg ) ; err != nil {
2016-11-22 03:48:30 -08:00
t . Fatalf ( "Unable to load YAML config sTwo: %s" , err )
}
2017-08-11 11:45:52 -07:00
ts . UpdateProviders ( ProvidersFromConfig ( * cfg , nil ) )
2016-11-22 03:48:30 -08:00
<- called
verifyPresence ( ts . tgroups , "static/0/0" , true )
verifyPresence ( ts . tgroups , "static/0/1" , false )
}
2017-11-06 08:14:15 -08:00
func TestTargetSetRunsSameTargetProviderMultipleTimes ( t * testing . T ) {
var wg sync . WaitGroup
wg . Add ( 2 )
ts1 := NewTargetSet ( & mockSyncer {
sync : func ( [ ] * config . TargetGroup ) { wg . Done ( ) } ,
} )
ts2 := NewTargetSet ( & mockSyncer {
sync : func ( [ ] * config . TargetGroup ) { wg . Done ( ) } ,
} )
ctx , cancel := context . WithCancel ( context . Background ( ) )
defer cancel ( )
2017-11-11 18:39:08 -08:00
updates := [ ] update {
{
targetGroups : [ ] config . TargetGroup { { Source : "initial1" } , { Source : "initial2" } } ,
interval : 10 ,
} ,
}
tp := newMockTargetProvider ( updates )
2017-11-06 08:14:15 -08:00
targetProviders := map [ string ] TargetProvider { }
targetProviders [ "testProvider" ] = tp
go ts1 . Run ( ctx )
go ts2 . Run ( ctx )
ts1 . UpdateProviders ( targetProviders )
ts2 . UpdateProviders ( targetProviders )
2017-11-11 18:39:08 -08:00
finalize := make ( chan struct { } )
go func ( ) {
defer close ( finalize )
wg . Wait ( )
} ( )
select {
case <- time . After ( 20 * time . Second ) :
t . Error ( "Test timed out after 20 seconds. All targets should be sent within the timeout" )
case <- finalize :
2017-11-12 08:47:30 -08:00
if tp . callCount ( ) != 2 {
t . Errorf ( "Was expecting 2 calls, received %d" , tp . callCount ( ) )
2017-11-11 18:39:08 -08:00
}
2017-11-06 09:33:52 -08:00
}
}
type mockSyncer struct {
sync func ( tgs [ ] * config . TargetGroup )
}
func ( s * mockSyncer ) Sync ( tgs [ ] * config . TargetGroup ) {
if s . sync != nil {
s . sync ( tgs )
}
}
2017-11-11 18:39:08 -08:00
type update struct {
targetGroups [ ] config . TargetGroup
interval time . Duration
}
2017-11-06 09:33:52 -08:00
type mockTargetProvider struct {
2017-11-12 08:47:30 -08:00
_callCount * int32
updates [ ] update
up chan <- [ ] * config . TargetGroup
2017-11-06 09:33:52 -08:00
}
func newMockTargetProvider ( updates [ ] update ) mockTargetProvider {
2017-11-12 08:47:30 -08:00
var callCount int32
2017-11-06 09:33:52 -08:00
tp := mockTargetProvider {
2017-11-12 08:47:30 -08:00
_callCount : & callCount ,
updates : updates ,
2017-11-06 09:33:52 -08:00
}
return tp
}
func ( tp mockTargetProvider ) Run ( ctx context . Context , up chan <- [ ] * config . TargetGroup ) {
2017-11-12 08:47:30 -08:00
atomic . AddInt32 ( tp . _callCount , 1 )
2017-11-06 09:33:52 -08:00
tp . up = up
tp . sendUpdates ( )
}
func ( tp mockTargetProvider ) sendUpdates ( ) {
for _ , update := range tp . updates {
time . Sleep ( update . interval * time . Millisecond )
2017-11-11 18:39:08 -08:00
tgs := make ( [ ] * config . TargetGroup , len ( update . targetGroups ) )
for i := range update . targetGroups {
tgs [ i ] = & update . targetGroups [ i ]
2017-11-06 09:33:52 -08:00
}
tp . up <- tgs
2017-11-06 08:14:15 -08:00
}
}
2017-11-12 08:47:30 -08:00
func ( tp mockTargetProvider ) callCount ( ) int {
return int ( atomic . LoadInt32 ( tp . _callCount ) )
}