Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix(api/rollouts): ensure tx rollback #1805

Merged
merged 9 commits into from
Jul 4, 2023
7 changes: 5 additions & 2 deletions build/internal/flipt.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ func Base(ctx context.Context, client *dagger.Client, req FliptRequest) (*dagger
golang := client.Container(dagger.ContainerOpts{
Platform: dagger.Platform(platforms.Format(req.BuildTarget)),
}).
From("golang:1.20-alpine3.16").
From("golang:1.20-alpine3.18").
WithEnvVariable("GOCACHE", goBuildCachePath).
WithEnvVariable("GOMODCACHE", goModCachePath).
WithExec([]string{"apk", "add", "bash", "gcc", "binutils-gold", "build-base", "git"})
Expand Down Expand Up @@ -168,6 +168,9 @@ func Base(ctx context.Context, client *dagger.Client, req FliptRequest) (*dagger
return golang.
WithMountedDirectory("./ui", embed.Directory("./ui")).
WithMountedDirectory("./ui/dist", req.UI.Directory("./dist")).
// see: https://github.com/golang/go/issues/60825
// should be fixed in go 1.20.6
WithEnvVariable("GOEXPERIMENT", "nocoverageredesign").
WithExec([]string{"mkdir", "-p", req.binary()}).
WithExec([]string{"sh", "-c", goBuildCmd}), nil
}
Expand All @@ -176,7 +179,7 @@ func Base(ctx context.Context, client *dagger.Client, req FliptRequest) (*dagger
// into a thinner alpine distribution.
func Package(ctx context.Context, client *dagger.Client, flipt *dagger.Container, req FliptRequest) (*dagger.Container, error) {
// build container with just Flipt + config
return client.Container().From("alpine:3.16").
return client.Container().From("alpine:3.18").
WithExec([]string{"apk", "add", "--no-cache", "postgresql-client", "openssl", "ca-certificates"}).
WithExec([]string{"mkdir", "-p", "/var/opt/flipt"}).
WithExec([]string{"mkdir", "-p", "/var/log/flipt"}).
Expand Down
2 changes: 1 addition & 1 deletion build/testing/integration.go
Original file line number Diff line number Diff line change
Expand Up @@ -296,7 +296,7 @@ func suite(ctx context.Context, dir string, base, flipt *dagger.Container, conf
WithServiceBinding("flipt", flipt).
WithWorkdir(path.Join("build/testing/integration", dir)).
WithEnvVariable("UNIQUE", uuid.New().String()).
WithExec(append([]string{"go", "test", "-v", "-race"}, append(flags, ".")...)).
WithExec(append([]string{"go", "test", "-v", "-timeout=1m", "-race"}, append(flags, ".")...)).
ExitCode(ctx)

return err
Expand Down
182 changes: 157 additions & 25 deletions build/testing/integration/api/api.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,13 @@ import (
"testing"

"github.com/gofrs/uuid"
"github.com/google/go-cmp/cmp"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
"go.flipt.io/flipt/rpc/flipt"
"go.flipt.io/flipt/rpc/flipt/evaluation"
sdk "go.flipt.io/flipt/sdk/go"
"google.golang.org/protobuf/testing/protocmp"
)

func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, authenticated bool) {
Expand Down Expand Up @@ -92,9 +94,9 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
})

t.Run("Flags and Variants", func(t *testing.T) {
t.Log("Create a new flag with key \"test\".")
t.Log("Create a new enabled flag with key \"test\".")

created, err := client.Flipt().CreateFlag(ctx, &flipt.CreateFlagRequest{
enabled, err := client.Flipt().CreateFlag(ctx, &flipt.CreateFlagRequest{
NamespaceKey: namespace,
Key: "test",
Name: "Test",
Expand All @@ -103,10 +105,10 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
})
require.NoError(t, err)

assert.Equal(t, "test", created.Key)
assert.Equal(t, "Test", created.Name)
assert.Equal(t, "This is a test flag", created.Description)
assert.True(t, created.Enabled, "Flag should be enabled")
assert.Equal(t, "test", enabled.Key)
assert.Equal(t, "Test", enabled.Name)
assert.Equal(t, "This is a test flag", enabled.Description)
assert.True(t, enabled.Enabled, "Flag should be enabled")

t.Log("Create a new flag in a disabled state.")

Expand All @@ -124,6 +126,40 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
assert.Equal(t, "This is a disabled test flag", disabled.Description)
assert.False(t, disabled.Enabled, "Flag should be disabled")

t.Log("Create a new enabled boolean flag with key \"boolean_enabled\".")

booleanEnabled, err := client.Flipt().CreateFlag(ctx, &flipt.CreateFlagRequest{
Type: flipt.FlagType_BOOLEAN_FLAG_TYPE,
NamespaceKey: namespace,
Key: "boolean_enabled",
Name: "Boolean Enabled",
Description: "This is an enabled boolean test flag",
Enabled: true,
})
require.NoError(t, err)

assert.Equal(t, "boolean_enabled", booleanEnabled.Key)
assert.Equal(t, "Boolean Enabled", booleanEnabled.Name)
assert.Equal(t, "This is an enabled boolean test flag", booleanEnabled.Description)
assert.True(t, booleanEnabled.Enabled, "Flag should be enabled")

t.Log("Create a new flag in a disabled state.")

booleanDisabled, err := client.Flipt().CreateFlag(ctx, &flipt.CreateFlagRequest{
Type: flipt.FlagType_BOOLEAN_FLAG_TYPE,
NamespaceKey: namespace,
Key: "boolean_disabled",
Name: "Boolean Disabled",
Description: "This is a disabled boolean test flag",
Enabled: false,
})
require.NoError(t, err)

assert.Equal(t, "boolean_disabled", booleanDisabled.Key)
assert.Equal(t, "Boolean Disabled", booleanDisabled.Name)
assert.Equal(t, "This is a disabled boolean test flag", booleanDisabled.Description)
assert.False(t, booleanDisabled.Enabled, "Flag should be disabled")

t.Log("Retrieve flag with key \"test\".")

flag, err := client.Flipt().GetFlag(ctx, &flipt.GetFlagRequest{
Expand All @@ -132,15 +168,15 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
})
require.NoError(t, err)

assert.Equal(t, created, flag)
assert.Equal(t, enabled, flag)

t.Log("Update flag with key \"test\".")

updated, err := client.Flipt().UpdateFlag(ctx, &flipt.UpdateFlagRequest{
NamespaceKey: namespace,
Key: created.Key,
Key: enabled.Key,
Name: "Test 2",
Description: created.Description,
Description: enabled.Description,
Enabled: true,
})
require.NoError(t, err)
Expand All @@ -163,14 +199,18 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
})
require.NoError(t, err)

assert.Len(t, flags.Flags, 2)
assert.Equal(t, updated.Key, flags.Flags[0].Key)
assert.Equal(t, updated.Name, flags.Flags[0].Name)
assert.Equal(t, updated.Description, flags.Flags[0].Description)

assert.Equal(t, disabled.Key, flags.Flags[1].Key)
assert.Equal(t, disabled.Name, flags.Flags[1].Name)
assert.Equal(t, disabled.Description, flags.Flags[1].Description)
assert.Len(t, flags.Flags, 4)
for i, flag := range []*flipt.Flag{
updated,
disabled,
booleanEnabled,
booleanDisabled,
} {
assert.Equal(t, flag.Key, flags.Flags[i].Key)
assert.Equal(t, flag.Name, flags.Flags[i].Name)
assert.Equal(t, flag.Description, flags.Flags[i].Description)
assert.Equal(t, flag.Enabled, flags.Flags[i].Enabled)
}

for _, key := range []string{"one", "two"} {
t.Logf("Create variant with key %q.", key)
Expand Down Expand Up @@ -494,6 +534,98 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
assert.Equal(t, float32(100), distribution.Rollout)
})

t.Run("Boolean Rollouts", func(t *testing.T) {
rolloutSegment, err := client.Flipt().CreateRollout(ctx, &flipt.CreateRolloutRequest{
NamespaceKey: namespace,
FlagKey: "boolean_disabled",
Description: "matches a segment",
Rank: 1,
Rule: &flipt.CreateRolloutRequest_Segment{
Segment: &flipt.RolloutSegment{
SegmentKey: "everyone",
Value: true,
},
},
})
require.NoError(t, err)

assert.Equal(t, namespace, rolloutSegment.NamespaceKey)
assert.Equal(t, "boolean_disabled", rolloutSegment.FlagKey)
assert.Equal(t, int32(1), rolloutSegment.Rank)
assert.Equal(t, "everyone", rolloutSegment.Rule.(*flipt.Rollout_Segment).Segment.SegmentKey)
assert.Equal(t, true, rolloutSegment.Rule.(*flipt.Rollout_Segment).Segment.Value)

rolloutPercentage, err := client.Flipt().CreateRollout(ctx, &flipt.CreateRolloutRequest{
NamespaceKey: namespace,
FlagKey: "boolean_disabled",
Description: "50% disabled",
Rank: 2,
Rule: &flipt.CreateRolloutRequest_Percentage{
Percentage: &flipt.RolloutPercentage{
Percentage: 50,
Value: false,
},
},
})
require.NoError(t, err)

assert.Equal(t, namespace, rolloutPercentage.NamespaceKey)
assert.Equal(t, "boolean_disabled", rolloutPercentage.FlagKey)
assert.Equal(t, "50% disabled", rolloutPercentage.Description)
assert.Equal(t, int32(2), rolloutPercentage.Rank)
assert.Equal(t, float32(50.0), rolloutPercentage.Rule.(*flipt.Rollout_Percentage).Percentage.Percentage)
assert.Equal(t, false, rolloutPercentage.Rule.(*flipt.Rollout_Percentage).Percentage.Value)

rollouts, err := client.Flipt().ListRollouts(ctx, &flipt.ListRolloutRequest{
NamespaceKey: namespace,
FlagKey: "boolean_disabled",
})
require.NoError(t, err)

assert.Empty(t, cmp.Diff([]*flipt.Rollout{
rolloutSegment,
rolloutPercentage,
}, rollouts.Rules, protocmp.Transform()))

updatedRollout, err := client.Flipt().UpdateRollout(ctx, &flipt.UpdateRolloutRequest{
NamespaceKey: namespace,
FlagKey: "boolean_disabled",
Id: rolloutPercentage.Id,
Description: "50% enabled",
Rule: &flipt.UpdateRolloutRequest_Percentage{
Percentage: &flipt.RolloutPercentage{
Percentage: 50,
Value: true,
},
},
})
require.NoError(t, err)

assert.Equal(t, namespace, updatedRollout.NamespaceKey)
assert.Equal(t, "boolean_disabled", updatedRollout.FlagKey)
assert.Equal(t, "50% enabled", updatedRollout.Description)
assert.Equal(t, int32(2), updatedRollout.Rank)
assert.Equal(t, float32(50.0), updatedRollout.Rule.(*flipt.Rollout_Percentage).Percentage.Percentage)
assert.Equal(t, true, updatedRollout.Rule.(*flipt.Rollout_Percentage).Percentage.Value)

t.Run("Cannot change rollout type", func(t *testing.T) {
_, err := client.Flipt().UpdateRollout(ctx, &flipt.UpdateRolloutRequest{
NamespaceKey: namespace,
FlagKey: "boolean_disabled",
Id: rolloutPercentage.Id,
Description: "50% enabled",
Rule: &flipt.UpdateRolloutRequest_Segment{
Segment: &flipt.RolloutSegment{
SegmentKey: "everyone",
Value: true,
},
},
})

require.EqualError(t, err, "rpc error: code = InvalidArgument desc = cannot change type of rollout: have \"PERCENTAGE_ROLLOUT_TYPE\" attempted \"SEGMENT_ROLLOUT_TYPE\"")
})
})

t.Run("Legacy", func(t *testing.T) {
t.Run("Evaluation", func(t *testing.T) {
t.Log(`Successful match.`)
Expand Down Expand Up @@ -674,17 +806,17 @@ func API(t *testing.T, ctx context.Context, client sdk.SDK, namespace string, au
}

t.Log(`Flag.`)
err = client.Flipt().DeleteFlag(ctx, &flipt.DeleteFlagRequest{
NamespaceKey: namespace,
Key: "test",
})
require.NoError(t, err)

err = client.Flipt().DeleteFlag(ctx, &flipt.DeleteFlagRequest{
flags, err := client.Flipt().ListFlags(ctx, &flipt.ListFlagRequest{
NamespaceKey: namespace,
Key: "disabled",
})
require.NoError(t, err)
for _, flag := range flags.Flags {
err = client.Flipt().DeleteFlag(ctx, &flipt.DeleteFlagRequest{
NamespaceKey: namespace,
Key: flag.Key,
})
require.NoError(t, err)
}

t.Log(`Segment.`)
err = client.Flipt().DeleteSegment(ctx, &flipt.DeleteSegmentRequest{
Expand Down
Loading
Loading