Skip to content

Commit

Permalink
fix(api/rollouts): ensure tx rollback and drop create rollout type
Browse files Browse the repository at this point in the history
  • Loading branch information
GeorgeMac committed Jun 30, 2023
1 parent b9a63a4 commit 5b767c4
Show file tree
Hide file tree
Showing 5 changed files with 524 additions and 467 deletions.
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
55 changes: 55 additions & 0 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 @@ -532,6 +534,59 @@ 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% enabled",
Rank: 2,
Rule: &flipt.CreateRolloutRequest_Percentage{
Percentage: &flipt.RolloutPercentage{
Percentage: 50,
Value: true,
},
},
})
require.NoError(t, err)

assert.Equal(t, namespace, rolloutPercentage.NamespaceKey)
assert.Equal(t, "boolean_disabled", rolloutPercentage.FlagKey)
assert.Equal(t, int32(2), rolloutPercentage.Rank)
assert.Equal(t, float32(50.0), rolloutPercentage.Rule.(*flipt.Rollout_Percentage).Percentage.Percentage)
assert.Equal(t, true, 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()))
})

t.Run("Legacy", func(t *testing.T) {
t.Run("Evaluation", func(t *testing.T) {
t.Log(`Successful match.`)
Expand Down
34 changes: 24 additions & 10 deletions internal/storage/sql/common/rollout.go
Original file line number Diff line number Diff line change
Expand Up @@ -312,7 +312,7 @@ func (s *Store) CountRollouts(ctx context.Context, namespaceKey, flagKey string)
return count, nil
}

func (s *Store) CreateRollout(ctx context.Context, r *flipt.CreateRolloutRequest) (*flipt.Rollout, error) {
func (s *Store) CreateRollout(ctx context.Context, r *flipt.CreateRolloutRequest) (_ *flipt.Rollout, err error) {
if r.NamespaceKey == "" {
r.NamespaceKey = storage.DefaultNamespace
}
Expand All @@ -323,64 +323,78 @@ func (s *Store) CreateRollout(ctx context.Context, r *flipt.CreateRolloutRequest
Id: uuid.Must(uuid.NewV4()).String(),
NamespaceKey: r.NamespaceKey,
FlagKey: r.FlagKey,
Type: r.Type,
Rank: r.Rank,
Description: r.Description,
CreatedAt: now,
UpdatedAt: now,
}
)

switch r.GetRule().(type) {
case *flipt.CreateRolloutRequest_Segment:
rollout.Type = flipt.RolloutType_SEGMENT_ROLLOUT_TYPE
case *flipt.CreateRolloutRequest_Percentage:
rollout.Type = flipt.RolloutType_PERCENTAGE_ROLLOUT_TYPE
default:
return nil, fmt.Errorf("invalid rollout rule type %T", r.GetRule())
}

tx, err := s.db.Begin()
if err != nil {
return nil, err
}

defer func() {
if err != nil {
_ = tx.Rollback()
}
}()

if _, err := s.builder.Insert(tableRollouts).
RunWith(tx).
Columns("id", "namespace_key", "flag_key", "\"type\"", "rank", "description", "created_at", "updated_at").
Values(rollout.Id, rollout.NamespaceKey, rollout.FlagKey, rollout.Type, rollout.Rank, rollout.Description,
&fliptsql.Timestamp{Timestamp: rollout.CreatedAt},
&fliptsql.Timestamp{Timestamp: rollout.UpdatedAt},
).ExecContext(ctx); err != nil {
_ = tx.Rollback()
return nil, err
}

switch r.GetType() {
case flipt.RolloutType_SEGMENT_ROLLOUT_TYPE:
switch r.GetRule().(type) {
case *flipt.CreateRolloutRequest_Segment:
rollout.Type = flipt.RolloutType_SEGMENT_ROLLOUT_TYPE

var segmentRule = r.GetSegment()

if _, err := s.builder.Insert(tableRolloutSegments).
RunWith(tx).
Columns("id", "rollout_id", "namespace_key", "segment_key", "\"value\"").
Values(uuid.Must(uuid.NewV4()).String(), rollout.Id, rollout.NamespaceKey, segmentRule.SegmentKey, segmentRule.Value).
ExecContext(ctx); err != nil {
_ = tx.Rollback()
return nil, err
}

rollout.Rule = &flipt.Rollout_Segment{
Segment: segmentRule,
}
case flipt.RolloutType_PERCENTAGE_ROLLOUT_TYPE:
case *flipt.CreateRolloutRequest_Percentage:
rollout.Type = flipt.RolloutType_PERCENTAGE_ROLLOUT_TYPE

var percentageRule = r.GetPercentage()

if _, err := s.builder.Insert(tableRolloutPercentages).
RunWith(tx).
Columns("id", "rollout_id", "namespace_key", "percentage", "\"value\"").
Values(uuid.Must(uuid.NewV4()).String(), rollout.Id, rollout.NamespaceKey, percentageRule.Percentage, percentageRule.Value).
ExecContext(ctx); err != nil {
_ = tx.Rollback()
return nil, err
}

rollout.Rule = &flipt.Rollout_Percentage{
Percentage: percentageRule,
}
default:
_ = tx.Rollback()
return nil, fmt.Errorf("invalid rollout rule type %v", r.GetType())
return nil, fmt.Errorf("invalid rollout rule type %v", rollout.Type)
}

return rollout, tx.Commit()
Expand Down
Loading

0 comments on commit 5b767c4

Please sign in to comment.