Skip to content

Commit

Permalink
syncing up to 1ee5e7e70788927381a5077476b391cbad9eb27a
Browse files Browse the repository at this point in the history
Co-authored-by: Joey Greco <57115019+joeyagreco@users.noreply.github.com>
Co-authored-by: Bruce Yu <bruce@superblockshq.com>
  • Loading branch information
3 people committed Oct 31, 2024
1 parent 41a3cae commit e7efa92
Show file tree
Hide file tree
Showing 7 changed files with 384 additions and 6 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Include signing algorithm and public key in response from Sign endpoint (`/v1/signature/sign`)
- Set errors on responses for all resources that fail to get re-signed during a signature rotation job
- Improved error messages in Email Plugin
- Allow branch name to be given in workflow URLs as a query param: `fetch.branch_name`

## v1.15.1

Expand Down
6 changes: 6 additions & 0 deletions internal/transport/http.go
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ import (
const (
TransformedTokenQueryParam = "fetch.token"
TransformedTestQueryParam = "fetch.test"
TransformedBranchNameQueryParam = "fetch.branch_name"
TransformedEnvironmentQueryParam = "fetch.profile.environment"
TransformedProfileNameQueryParam = "fetch.profile.name"
TransformedProfileIdQueryParam = "fetch.profile.id"
Expand All @@ -33,6 +34,7 @@ var (
knownQueryParams = map[string]bool{
TransformedTokenQueryParam: true,
TransformedTestQueryParam: true,
TransformedBranchNameQueryParam: true,
TransformedEnvironmentQueryParam: true,
TransformedOptionsAsync: true,
TransformedProfileNameQueryParam: true,
Expand Down Expand Up @@ -260,6 +262,10 @@ func transformWorkflowRequest(r *http.Request, version string) (err error) {
request.Request.(*apiv1.ExecuteRequest_Fetch_).Fetch.Profile.Id = &profileID
}

if branchName := r.URL.Query().Get(TransformedBranchNameQueryParam); branchName != "" {
request.Request.(*apiv1.ExecuteRequest_Fetch_).Fetch.BranchName = &branchName
}

if include := r.URL.Query().Get(TransformedOptionsIncludeEventOutputsParam); include != "" {
includeBool, err := strconv.ParseBool(include)
if err != nil {
Expand Down
149 changes: 149 additions & 0 deletions internal/transport/http_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,21 @@ import (
"io"
"net/http"
"net/http/httptest"
"net/url"
"strings"
"testing"

"google.golang.org/protobuf/encoding/protojson"
"google.golang.org/protobuf/proto"

"github.com/stretchr/testify/require"

"google.golang.org/protobuf/types/known/structpb"

"github.com/stretchr/testify/assert"
utils "github.com/superblocksteam/agent/pkg/utils"
apiv1 "github.com/superblocksteam/agent/types/gen/go/api/v1"
commonv1 "github.com/superblocksteam/agent/types/gen/go/common/v1"
)

func TestHackUntilWeHaveGoKit(t *testing.T) {
Expand Down Expand Up @@ -334,3 +345,141 @@ func TestHackUntilWeHaveGoKit(t *testing.T) {
})
}
}

func TestTransformWorkflowRequest(t *testing.T) {
for _, tc := range []struct {
name string
httpRequest *http.Request
version string
expectedExecuteRequest *apiv1.ExecuteRequest
expectError bool
}{
{
name: "happy path",
httpRequest: &http.Request{
Method: http.MethodPost,
URL: &url.URL{Path: "/foo/bar", RawQuery: ""},
},
version: "v2",
expectedExecuteRequest: &apiv1.ExecuteRequest{
Options: &apiv1.ExecuteRequest_Options{},
Inputs: map[string]*structpb.Value{
"body": structpb.NewStructValue(&structpb.Struct{}),
"params": structpb.NewStructValue(&structpb.Struct{}),
},
Request: &apiv1.ExecuteRequest_Fetch_{
Fetch: &apiv1.ExecuteRequest_Fetch{
ViewMode: apiv1.ViewMode_VIEW_MODE_DEPLOYED,
Profile: &commonv1.Profile{},
},
},
},
},
{
name: "with query param fetch.token",
httpRequest: &http.Request{
Method: http.MethodPost,
URL: &url.URL{Path: "/foo/bar", RawQuery: "fetch.token=foo"},
},
version: "v2",
expectedExecuteRequest: &apiv1.ExecuteRequest{
Options: &apiv1.ExecuteRequest_Options{},
Inputs: map[string]*structpb.Value{
"body": structpb.NewStructValue(&structpb.Struct{}),
"params": structpb.NewStructValue(&structpb.Struct{}),
},
Request: &apiv1.ExecuteRequest_Fetch_{
Fetch: &apiv1.ExecuteRequest_Fetch{
Token: proto.String("foo"),
ViewMode: apiv1.ViewMode_VIEW_MODE_DEPLOYED,
Profile: &commonv1.Profile{},
},
},
},
},
{
name: "with query param fetch.profile.environment",
httpRequest: &http.Request{
Method: http.MethodPost,
URL: &url.URL{Path: "/foo/bar", RawQuery: "fetch.profile.environment=foo"},
},
version: "v2",
expectedExecuteRequest: &apiv1.ExecuteRequest{
Options: &apiv1.ExecuteRequest_Options{},
Inputs: map[string]*structpb.Value{
"body": structpb.NewStructValue(&structpb.Struct{}),
"params": structpb.NewStructValue(&structpb.Struct{}),
},
Request: &apiv1.ExecuteRequest_Fetch_{
Fetch: &apiv1.ExecuteRequest_Fetch{
ViewMode: apiv1.ViewMode_VIEW_MODE_DEPLOYED,
Profile: &commonv1.Profile{
Environment: proto.String("foo"),
},
},
},
},
},
{
name: "with query param fetch.branch_name",
httpRequest: &http.Request{
Method: http.MethodPost,
URL: &url.URL{Path: "/foo/bar", RawQuery: "fetch.branch_name=foo"},
},
version: "v2",
expectedExecuteRequest: &apiv1.ExecuteRequest{
Options: &apiv1.ExecuteRequest_Options{},
Inputs: map[string]*structpb.Value{
"body": structpb.NewStructValue(&structpb.Struct{}),
"params": structpb.NewStructValue(&structpb.Struct{}),
},
Request: &apiv1.ExecuteRequest_Fetch_{
Fetch: &apiv1.ExecuteRequest_Fetch{
ViewMode: apiv1.ViewMode_VIEW_MODE_DEPLOYED,
Profile: &commonv1.Profile{},
BranchName: proto.String("foo"),
},
},
},
},
{
name: "with multiple query params",
httpRequest: &http.Request{
Method: http.MethodPost,
URL: &url.URL{Path: "/foo/bar", RawQuery: "fetch.profile.environment=foo&fetch.branch_name=bar"},
},
version: "v2",
expectedExecuteRequest: &apiv1.ExecuteRequest{
Options: &apiv1.ExecuteRequest_Options{},
Inputs: map[string]*structpb.Value{
"body": structpb.NewStructValue(&structpb.Struct{}),
"params": structpb.NewStructValue(&structpb.Struct{}),
},
Request: &apiv1.ExecuteRequest_Fetch_{
Fetch: &apiv1.ExecuteRequest_Fetch{
ViewMode: apiv1.ViewMode_VIEW_MODE_DEPLOYED,
Profile: &commonv1.Profile{
Environment: proto.String("foo"),
},
BranchName: proto.String("bar"),
},
},
},
},
} {
t.Run(tc.name, func(t *testing.T) {
err := transformWorkflowRequest(tc.httpRequest, tc.version)
require.NoError(t, err)

bodyBytes, err := io.ReadAll(tc.httpRequest.Body)
require.NoError(t, err)
defer tc.httpRequest.Body.Close()

actualExecuteRequest := &apiv1.ExecuteRequest{}
err = protojson.Unmarshal(bodyBytes, actualExecuteRequest)
require.NoError(t, err)

utils.ProtoEquals(t, tc.expectedExecuteRequest, actualExecuteRequest)
})
}
}
17 changes: 17 additions & 0 deletions pkg/utils/test_utils.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package utils

import (
"github.com/google/go-cmp/cmp"
"google.golang.org/protobuf/proto"
"google.golang.org/protobuf/testing/protocmp"
)

/*
QOL function to compare 2 proto objects in a unit test.
Will compare the given proto messages and print out a nice message showing the diff.
*/
func ProtoEquals(tb FatalTB, expected proto.Message, actual proto.Message) {
if d := cmp.Diff(expected, actual, protocmp.Transform()); d != "" {
tb.Fatalf("unexpected diff\n%s", d)
}
}
35 changes: 35 additions & 0 deletions pkg/utils/test_utils_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package utils

import (
"testing"

apiv1 "github.com/superblocksteam/agent/types/gen/go/api/v1"
"google.golang.org/protobuf/proto"
)

func Test_ProtoEquals(t *testing.T) {
t.Parallel()

for _, test := range []struct {
name string
proto1 proto.Message
proto2 proto.Message
expectTestFailure bool
}{
{
name: "equal",
proto1: &apiv1.Blocks{},
proto2: &apiv1.Blocks{},
},
{
name: "not equal",
proto1: &apiv1.Blocks{},
proto2: &apiv1.Blocks{Blocks: []*apiv1.Block{{Name: "foo"}}},
expectTestFailure: true,
},
} {
t.Run(test.name, func(t *testing.T) {
ProtoEquals(newFakeTB(t, test.expectTestFailure), test.proto1, test.proto2)
})
}
}
10 changes: 5 additions & 5 deletions pkg/utils/zap_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,10 @@ type fakeTB struct {
tb testing.TB
}

func newFakeTB(tb testing.TB) *fakeTB {
func newFakeTB(tb testing.TB, expectTestFailure bool) *fakeTB {
f := &fakeTB{tb: tb}
tb.Cleanup(func() {
require.True(tb, f.failed, "fakeTB did not fail as expected")
require.Equal(tb, expectTestFailure, f.failed, "fakeTB did not fail as expected")
})
return f
}
Expand Down Expand Up @@ -44,7 +44,7 @@ func TestZapTestRequireLogContains(t *testing.T) {
func TestZapTestRequireLogContainsMissing(t *testing.T) {
log, logs := NewZapTestObservedLogger(t)
log.Info("here", zap.String("else", "else")) // else for coverage
RequireLogContains(newFakeTB(t), logs, zap.InfoLevel, "hello world")
RequireLogContains(newFakeTB(t, true), logs, zap.InfoLevel, "hello world")
}

func TestZapTestRequireLogErrorEqual(t *testing.T) {
Expand All @@ -58,7 +58,7 @@ func TestZapTestRequireLogErrorEqualMissing(t *testing.T) {
log, logs := NewZapTestObservedLogger(t)
err := errors.New("hello world")
log.Error("error", zap.String("else", "else")) // else for coverage
RequireLogErrorEqual(newFakeTB(t), logs, zap.ErrorLevel, err.Error())
RequireLogErrorEqual(newFakeTB(t, true), logs, zap.ErrorLevel, err.Error())
}

func TestZapTestRequireLogErrorIs(t *testing.T) {
Expand All @@ -72,5 +72,5 @@ func TestZapTestRequireLogErrorIsMissing(t *testing.T) {
log, logs := NewZapTestObservedLogger(t)
err := errors.New("hello world")
log.Error("error", zap.String("else", "else")) // else for coverage
RequireLogErrorIs(newFakeTB(t), logs, zap.ErrorLevel, err)
RequireLogErrorIs(newFakeTB(t, true), logs, zap.ErrorLevel, err)
}
Loading

0 comments on commit e7efa92

Please sign in to comment.