Skip to content

Commit

Permalink
Merge branch 'develop' of github.com:Scalr/go-scalr into fix/SCALRCOR…
Browse files Browse the repository at this point in the history
…E-20952
  • Loading branch information
penja committed Jan 17, 2022
2 parents d192f02 + 8cbac06 commit eab908c
Show file tree
Hide file tree
Showing 4 changed files with 288 additions and 0 deletions.
1 change: 1 addition & 0 deletions GNUmakefile
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,5 @@ BUILD_ENV=CGO_ENABLED=0
MODULE_NAME=github.com/scalr/go-scalr
test:
$(BUILD_ENV) go test -v $(TESTARGS) -timeout=120s -covermode atomic -coverprofile=covprofile $(MODULE_NAME)

.PHONY: test
132 changes: 132 additions & 0 deletions run_triggers.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package scalr

import (
"context"
"errors"
"fmt"
"net/url"
"time"
)

// Compile-time proof of interface implementation.
var _ RunTriggers = (*runTriggers)(nil)

type RunTriggers interface {
// Create is used to create a new run trigger.
Create(ctx context.Context, options RunTriggerCreateOptions) (*RunTrigger, error)

// Read RunTrigger by it's ID
Read(ctx context.Context, runTriggerID string) (*RunTrigger, error)

// Delete RunTrigger by it's ID
Delete(ctx context.Context, runTriggerID string) error
}

// runTriggers implements RunTriggers
type runTriggers struct {
client *Client
}

type RunTrigger struct {
ID string `jsonapi:"primary,run-triggers"`
CreatedAt time.Time `jsonapi:"attr,created-at,iso8601"`

// Relations
Upstream *Upstream `jsonapi:"relation,upstream"`
Downstream *Downstream `jsonapi:"relation,downstream"`
}

type RunTriggerCreateOptions struct {
// For internal use only!
ID string `jsonapi:"primary,run-triggers"`

Downstream *Downstream `jsonapi:"relation,downstream"`
Upstream *Upstream `jsonapi:"relation,upstream"`
}

type Downstream struct {
ID string `jsonapi:"primary,workspaces"`
}

type Upstream struct {
ID string `jsonapi:"primary,workspaces"`
}

// Create is used to create a new runTrigger.
func (s *runTriggers) Create(ctx context.Context, options RunTriggerCreateOptions) (*RunTrigger, error) {
if err := options.valid(); err != nil {
return nil, err
}

// Make sure we don't send a user provided ID.
options.ID = ""

req, err := s.client.newRequest("POST", "run-triggers", &options)
if err != nil {
return nil, err
}

runTrigger := &RunTrigger{}
err = s.client.do(ctx, req, runTrigger)
if err != nil {
return nil, err
}

return runTrigger, nil
}

func (o RunTriggerCreateOptions) valid() error {
if o.Downstream == nil {
return errors.New("downstream ID is required")
}
if o.Upstream == nil {
return errors.New("upstream ID is required")
}
if !validString(&o.Downstream.ID) {
return errors.New("downstream ID is required")
}
if !validStringID(&o.Downstream.ID) {
return errors.New("invalid value for Downstream ID")
}
if !validString(&o.Upstream.ID) {
return errors.New("upstream ID is required")
}
if !validStringID(&o.Upstream.ID) {
return errors.New("invalid value for Upstream ID")
}
return nil
}

func (s *runTriggers) Read(ctx context.Context, runTriggerID string) (*RunTrigger, error) {
if !validStringID(&runTriggerID) {
return nil, errors.New("invalid value for RunTrigger ID")
}
u := fmt.Sprintf("run-triggers/%s", url.QueryEscape(runTriggerID))
req, err := s.client.newRequest("GET", u, nil)

if err != nil {
return nil, err
}

runTrigger := &RunTrigger{}
err = s.client.do(ctx, req, runTrigger)
if err != nil {
return nil, err
}

return runTrigger, nil
}

func (s *runTriggers) Delete(ctx context.Context, runTriggerID string) error {
if !validStringID(&runTriggerID) {
return errors.New("invalid value for RunTrigger ID")
}
u := fmt.Sprintf("run-triggers/%s", url.QueryEscape(runTriggerID))
req, err := s.client.newRequest("DELETE", u, nil)

if err != nil {
return err
}

return s.client.do(ctx, req, nil)
}
153 changes: 153 additions & 0 deletions run_triggers_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,153 @@
package scalr

import (
"context"
"fmt"
"testing"

"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

func TestRunTriggersCreate(t *testing.T) {
client := testClient(t)
ctx := context.Background()

env1Test, env1TestCleanup := createEnvironment(t, client)
defer env1TestCleanup()

env2Test, envTest2Cleanup := createEnvironment(t, client)
defer envTest2Cleanup()

wsEnv1Test1, wsEnv1Test1Cleanup := createWorkspace(t, client, env1Test)
defer wsEnv1Test1Cleanup()
wsEnv1Test2, wsEnv1Test2Cleanup := createWorkspace(t, client, env1Test)
defer wsEnv1Test2Cleanup()
wsEnv2Test1, wsEnv2Test1Cleanup := createWorkspace(t, client, env2Test)
defer wsEnv2Test1Cleanup()

t.Run("missing downstream workspace", func(t *testing.T) {
options := RunTriggerCreateOptions{
Upstream: &Upstream{ID: wsEnv1Test1.ID},
}
trigger, err := client.RunTriggers.Create(ctx, options)
require.Error(t, err)
assert.EqualError(t, err, "downstream ID is required")
assert.Nil(t, trigger)
})

t.Run("missing upstream workspace", func(t *testing.T) {
options := RunTriggerCreateOptions{
Downstream: &Downstream{ID: wsEnv1Test1.ID},
}
trigger, err := client.RunTriggers.Create(ctx, options)
require.Error(t, err)
assert.EqualError(t, err, "upstream ID is required")
assert.Nil(t, trigger)
})

t.Run("from different environments", func(t *testing.T) {
options := RunTriggerCreateOptions{
Downstream: &Downstream{ID: wsEnv1Test1.ID},
Upstream: &Upstream{ID: wsEnv2Test1.ID},
}
trigger, err := client.RunTriggers.Create(ctx, options)
require.Error(t, err)
assert.Contains(t, err.Error(), "The downstream and upstream workspaces must be within the same Scalr environment")
assert.Nil(t, trigger)
})

t.Run("create trigger", func(t *testing.T) {
options := RunTriggerCreateOptions{
Downstream: &Downstream{ID: wsEnv1Test1.ID},
Upstream: &Upstream{ID: wsEnv1Test2.ID},
}
trigger, err := client.RunTriggers.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, trigger.ID)
assert.NotEmpty(t, trigger.CreatedAt)
assert.Equal(t, wsEnv1Test1.ID, trigger.Downstream.ID)
assert.Equal(t, wsEnv1Test2.ID, trigger.Upstream.ID)
})

}

func TestRunTriggersRead(t *testing.T) {
client := testClient(t)
ctx := context.Background()

envTest, envTestCleanup := createEnvironment(t, client)
defer envTestCleanup()

wsTest1, wsEnv1Test1Cleanup := createWorkspace(t, client, envTest)
defer wsEnv1Test1Cleanup()
wsTest2, wsTest2Cleanup := createWorkspace(t, client, envTest)
defer wsTest2Cleanup()

options := RunTriggerCreateOptions{
Downstream: &Downstream{ID: wsTest1.ID},
Upstream: &Upstream{ID: wsTest2.ID},
}
created_trigger, err := client.RunTriggers.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, created_trigger.ID)

t.Run("get run trigger by id", func(t *testing.T) {
trigger, err := client.RunTriggers.Read(ctx, created_trigger.ID)
require.NoError(t, err)
assert.Equal(t, created_trigger, trigger)
})

t.Run("try to get run trigger with not valid ID", func(t *testing.T) {
_, err := client.RunTriggers.Read(ctx, badIdentifier)
require.Error(t, err)
assert.EqualError(t, err, "invalid value for RunTrigger ID")
})

}

func TestRunTriggersDelete(t *testing.T) {
client := testClient(t)
ctx := context.Background()

envTest, envTestCleanup := createEnvironment(t, client)
defer envTestCleanup()

wsTest1, wsEnv1Test1Cleanup := createWorkspace(t, client, envTest)
defer wsEnv1Test1Cleanup()
wsTest2, wsTest2Cleanup := createWorkspace(t, client, envTest)
defer wsTest2Cleanup()

options := RunTriggerCreateOptions{
Downstream: &Downstream{ID: wsTest1.ID},
Upstream: &Upstream{ID: wsTest2.ID},
}
createdTrigger, err := client.RunTriggers.Create(ctx, options)
require.NoError(t, err)
assert.NotEmpty(t, createdTrigger.ID)

t.Run("delete run trigger by id", func(t *testing.T) {
err := client.RunTriggers.Delete(ctx, createdTrigger.ID)
require.NoError(t, err)

// read RunTrigger by ID should fail
trigger, err := client.RunTriggers.Read(ctx, createdTrigger.ID)
require.Error(t, err)
assert.Equal(
t,
ErrResourceNotFound{
Message: fmt.Sprintf("RunTrigger with ID '%s' not found or user unauthorized", createdTrigger.ID),
}.Error(),
err.Error(),
)
assert.Nil(t, trigger)

})

t.Run("try to delete run trigger with not valid ID", func(t *testing.T) {
err := client.RunTriggers.Delete(ctx, badIdentifier)
require.Error(t, err)
assert.EqualError(t, err, "invalid value for RunTrigger ID")
})

}
2 changes: 2 additions & 0 deletions scalr.go
Original file line number Diff line number Diff line change
Expand Up @@ -130,6 +130,7 @@ type Client struct {
VcsRevisions VcsRevisions
Webhooks Webhooks
Workspaces Workspaces
RunTriggers RunTriggers
}

// NewClient creates a new Scalr API client.
Expand Down Expand Up @@ -216,6 +217,7 @@ func NewClient(cfg *Config) (*Client, error) {
client.VcsRevisions = &vcsRevisions{client: client}
client.Webhooks = &webhooks{client: client}
client.Workspaces = &workspaces{client: client}
client.RunTriggers = &runTriggers{client: client}

return client, nil
}
Expand Down

0 comments on commit eab908c

Please sign in to comment.