-
Notifications
You must be signed in to change notification settings - Fork 382
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Refactor processFilteredNodes for testing (#968)
* Refactor processFilteredNodes for testing I was digging into the intermittent failures of Test_processFilteredNodes and had trouble really understanding what the function, and the complimenting filterNodes were doing so I broke some of the logic out into smaller functions to encapsulate the logic and make testing of each portion easier. I added unit tests for these smaller functions to help catch potential issues with each. I left Test_processFilteredNodes as it serves well as a higher level test of all the other funtions. This adjusts the thresholds for the even distribution of picking nodes when the cardinality is lower than the possible nodes. Due to the randomness, it is quite hard to test how evenly distributed the values are within the original thresholds. This would cause many intermittent test failures when the values were just over or under the thresholds. This also moves the seed of math.Rand into the agent startup. Reseeding the randomness every function call seems like extra overhead for no value. I do not believe that constantly reseeding the randomness increases randomness in anyway.
- Loading branch information
Showing
4 changed files
with
274 additions
and
44 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,54 @@ | ||
package dkron | ||
|
||
import ( | ||
"fmt" | ||
"strconv" | ||
"strings" | ||
|
||
"github.com/hashicorp/serf/serf" | ||
) | ||
|
||
// cleanTags takes the tag spec and returns strictly key:value pairs | ||
// along with the lowest cardinality specified | ||
func cleanTags(tags map[string]string) (map[string]string, int, error) { | ||
cardinality := int(^uint(0) >> 1) // MaxInt | ||
|
||
cleanTags := make(map[string]string, len(tags)) | ||
|
||
for k, v := range tags { | ||
vparts := strings.Split(v, ":") | ||
|
||
cleanTags[k] = vparts[0] | ||
|
||
// If a cardinality is specified (i.e. "value:3") and it is lower than our | ||
// max cardinality, lower the max | ||
if len(vparts) == 2 { | ||
tagCard, err := strconv.Atoi(vparts[1]) | ||
if err != nil { | ||
// Tag value is malformed | ||
return nil, 0, fmt.Errorf("improper cardinality specified for tag %s: %v", k, vparts[1]) | ||
} | ||
|
||
if tagCard < cardinality { | ||
cardinality = tagCard | ||
} | ||
} | ||
} | ||
|
||
return cleanTags, cardinality, nil | ||
} | ||
|
||
// nodeMatchesTags encapsulates the logic of testing if a node matches all of the provided tags | ||
func nodeMatchesTags(node serf.Member, tags map[string]string) bool { | ||
for k, v := range tags { | ||
nodeVal, present := node.Tags[k] | ||
if !present { | ||
return false | ||
} | ||
if nodeVal != v { | ||
return false | ||
} | ||
} | ||
// If we matched all key:value pairs, the node matches the tags | ||
return true | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package dkron | ||
|
||
import ( | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
func Test_cleanTags(t *testing.T) { | ||
maxInt := int(^uint(0) >> 1) | ||
type args struct { | ||
tags map[string]string | ||
} | ||
tests := []struct { | ||
name string | ||
args args | ||
want map[string]string | ||
want1 int | ||
wantErr bool | ||
}{ | ||
{ | ||
name: "Clean Tags", | ||
args: args{map[string]string{"key1": "value1", "key2": "value2"}}, | ||
want: map[string]string{"key1": "value1", "key2": "value2"}, | ||
want1: maxInt, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "With Cardinality", | ||
args: args{map[string]string{"key1": "value1", "key2": "value2:5"}}, | ||
want: map[string]string{"key1": "value1", "key2": "value2"}, | ||
want1: 5, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "With Multiple Cardinalities", | ||
args: args{map[string]string{"key1": "value1:2", "key2": "value2:5"}}, | ||
want: map[string]string{"key1": "value1", "key2": "value2"}, | ||
want1: 2, | ||
wantErr: false, | ||
}, | ||
{ | ||
name: "With String Cardinality", | ||
args: args{map[string]string{"key1": "value1", "key2": "value2:cardinality"}}, | ||
want: nil, | ||
want1: 0, | ||
wantErr: true, | ||
}, | ||
} | ||
for _, tt := range tests { | ||
t.Run(tt.name, func(t *testing.T) { | ||
got, got1, err := cleanTags(tt.args.tags) | ||
if (err != nil) != tt.wantErr { | ||
t.Errorf("cleanTags() error = %v, wantErr %v", err, tt.wantErr) | ||
return | ||
} | ||
if !reflect.DeepEqual(got, tt.want) { | ||
t.Logf("got map: %#v", got) | ||
t.Logf("want map: %#v", tt.want) | ||
t.Errorf("cleanTags() got = %v, want %v", got, tt.want) | ||
} | ||
if got1 != tt.want1 { | ||
t.Errorf("cleanTags() got1 = %v, want %v", got1, tt.want1) | ||
} | ||
}) | ||
} | ||
} |