mirror of
https://github.com/gitpod-io/gitpod.git
synced 2025-12-08 17:36:30 +00:00
* [installer] make sure dashboard is deployed after server and papi-server * fix build * Add unit tests * address feedback * wait feature flag until get actual value of timed out * default config cat client nil * log avg fetch time * 1 * mock feature flag hang * Add metric * fixup
221 lines
6.1 KiB
Go
221 lines
6.1 KiB
Go
// Copyright (c) 2023 Gitpod GmbH. All rights reserved.
|
|
// Licensed under the GNU Affero General Public License (AGPL).
|
|
// See License.AGPL.txt in the project root for license information.
|
|
|
|
package cmd_test
|
|
|
|
import (
|
|
"context"
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/gitpod-io/gitpod/common-go/experiments"
|
|
"github.com/gitpod-io/gitpod/service-waiter/cmd"
|
|
)
|
|
|
|
var trueValue = "true"
|
|
var falseValue = "false"
|
|
var unknownValue = "unknown"
|
|
|
|
func Test_actualWaitFeatureFlag(t *testing.T) {
|
|
baseDuration := time.Millisecond
|
|
// use longer time if you want to debug
|
|
// baseDuration := time.Second * 10
|
|
cmd.FeatureSleepDuration = baseDuration * 20
|
|
type args struct {
|
|
timeoutDuration time.Duration
|
|
values []*string
|
|
defaultValue bool
|
|
nilClient bool
|
|
clientHanging time.Duration
|
|
}
|
|
tests := []struct {
|
|
name string
|
|
args args
|
|
wantFlagValue bool
|
|
wantOk bool
|
|
fetchTimes int
|
|
}{
|
|
{
|
|
name: "happy path",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, &trueValue},
|
|
defaultValue: false,
|
|
nilClient: false,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: true,
|
|
wantOk: true,
|
|
fetchTimes: 3,
|
|
},
|
|
{
|
|
name: "happy path 2",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, nil, &falseValue},
|
|
defaultValue: false,
|
|
nilClient: false,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: false,
|
|
wantOk: true,
|
|
fetchTimes: 4,
|
|
},
|
|
{
|
|
name: "happy path 3",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, nil, &falseValue},
|
|
defaultValue: false,
|
|
nilClient: false,
|
|
clientHanging: baseDuration * 10,
|
|
},
|
|
wantFlagValue: false,
|
|
wantOk: true,
|
|
fetchTimes: 4,
|
|
},
|
|
{
|
|
name: "should keep wait even with unknown value",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: false,
|
|
nilClient: false,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: false,
|
|
wantOk: true,
|
|
fetchTimes: 5,
|
|
},
|
|
{
|
|
name: "nil client goes to default value: false",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: false,
|
|
nilClient: true,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: false,
|
|
wantOk: false,
|
|
fetchTimes: 0,
|
|
},
|
|
{
|
|
name: "nil client goes to default value: true",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 1000,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: true,
|
|
nilClient: true,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: true,
|
|
wantOk: false,
|
|
fetchTimes: 0,
|
|
},
|
|
{
|
|
name: "ctx timed out should get default value: true",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 30,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: true,
|
|
nilClient: false,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: true,
|
|
wantOk: false,
|
|
fetchTimes: 2,
|
|
},
|
|
{
|
|
name: "ctx timed out should get default value: false",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 30,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: false,
|
|
nilClient: false,
|
|
clientHanging: time.Second * 0,
|
|
},
|
|
wantFlagValue: false,
|
|
wantOk: false,
|
|
fetchTimes: 2,
|
|
},
|
|
{
|
|
name: "client hanging should get default value",
|
|
args: args{
|
|
timeoutDuration: baseDuration * 30,
|
|
values: []*string{nil, nil, nil, &unknownValue, &falseValue},
|
|
defaultValue: true,
|
|
nilClient: false,
|
|
clientHanging: baseDuration * 60,
|
|
},
|
|
wantFlagValue: true,
|
|
wantOk: false,
|
|
fetchTimes: 1,
|
|
},
|
|
}
|
|
for _, tt := range tests {
|
|
t.Run(tt.name, func(t *testing.T) {
|
|
ctx, cancel := context.WithTimeout(context.Background(), tt.args.timeoutDuration)
|
|
defer cancel()
|
|
client := newMockClient(tt.args.values, tt.args.nilClient, tt.args.clientHanging)
|
|
gotFlagValue, gotOk, gotFetchTimes := cmd.ActualWaitFeatureFlag(ctx, client, tt.args.defaultValue)
|
|
if gotFlagValue != tt.wantFlagValue {
|
|
t.Errorf("actualWaitFeatureFlag() gotFlagValue = %v, want %v", gotFlagValue, tt.wantFlagValue)
|
|
}
|
|
if gotOk != tt.wantOk {
|
|
t.Errorf("actualWaitFeatureFlag() gotOk = %v, want %v", gotOk, tt.wantOk)
|
|
}
|
|
if gotFetchTimes != tt.fetchTimes {
|
|
t.Errorf("actualWaitFeatureFlag() gotFetchTimes = %v, want %v", gotFetchTimes, tt.fetchTimes)
|
|
}
|
|
})
|
|
}
|
|
}
|
|
|
|
type mockClient struct {
|
|
values []*string
|
|
i int
|
|
hangingDuration time.Duration
|
|
}
|
|
|
|
// GetBoolValue implements experiments.Client.
|
|
func (*mockClient) GetBoolValue(ctx context.Context, experimentName string, defaultValue bool, attributes experiments.Attributes) bool {
|
|
panic("unimplemented")
|
|
}
|
|
|
|
// GetFloatValue implements experiments.Client.
|
|
func (*mockClient) GetFloatValue(ctx context.Context, experimentName string, defaultValue float64, attributes experiments.Attributes) float64 {
|
|
panic("unimplemented")
|
|
}
|
|
|
|
// GetIntValue implements experiments.Client.
|
|
func (*mockClient) GetIntValue(ctx context.Context, experimentName string, defaultValue int, attributes experiments.Attributes) int {
|
|
panic("unimplemented")
|
|
}
|
|
|
|
func newMockClient(values []*string, isNil bool, hangingDuration time.Duration) experiments.Client {
|
|
if isNil {
|
|
return nil
|
|
}
|
|
return &mockClient{values: values, i: 0, hangingDuration: hangingDuration}
|
|
}
|
|
|
|
// GetStringValue implements experiments.Client.
|
|
func (c *mockClient) GetStringValue(ctx context.Context, experimentName string, defaultValue string, attributes experiments.Attributes) string {
|
|
defer func() {
|
|
c.i += 1
|
|
}()
|
|
time.Sleep(c.hangingDuration)
|
|
if c.i >= len(c.values) {
|
|
return defaultValue
|
|
}
|
|
value := c.values[c.i]
|
|
if value == nil {
|
|
return defaultValue
|
|
}
|
|
return *value
|
|
}
|
|
|
|
var _ experiments.Client = &mockClient{}
|