Skip to content

Commit

Permalink
Write tests for service and provider clients; Create Makefile
Browse files Browse the repository at this point in the history
  • Loading branch information
gregfurman committed Apr 28, 2024
1 parent ff4e6ea commit 1b58e50
Show file tree
Hide file tree
Showing 11 changed files with 749 additions and 13 deletions.
29 changes: 29 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
BINARY_NAME=pipescope

build:
CGO_ENABLED=0 go build -mod=mod -o ./targets/${BINARY_NAME} main.go

mod:
go mod download

run: build
./${BINARY_NAME}

clean:
go clean -testcache
rm -rf ./targets

test:
go test -race -v ./...

test_coverage:
go test ./... -coverprofile=coverage.out

dep:
go get .

vet:
go vet

lint:
golangci-lint run -v
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,7 +46,7 @@ Output:

## Limitations/Roadmap
- <b>Project is currently experimental</b> so please do not use this in production anywhere
- Needs CI/CD, tests, and a Makefile
- <s>Needs CI/CD, tests, and a Makefile</s>
- <s>Currently, PipeScope can only monitor GitLab pipelines. Future versions will extend this to include GitHub workflows.</s>
- There is not a lot of flexibility to select pipelines or projects via command-line input -- this should be changed to allow custom pipeline IDs to be specified.
- Include more information on pipeline jobs
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ go 1.21

require (
github.com/gen2brain/beeep v0.0.0-20240112042604-c7bb2cd88fea
github.com/go-git/go-billy/v5 v5.5.0
github.com/go-git/go-git/v5 v5.12.0
github.com/google/go-github/v61 v61.0.0
github.com/xanzy/go-gitlab v0.102.0
Expand All @@ -17,7 +18,6 @@ require (
github.com/cyphar/filepath-securejoin v0.2.4 // indirect
github.com/emirpasic/gods v1.18.1 // indirect
github.com/go-git/gcfg v1.5.1-0.20230307220236-3a3c6141e376 // indirect
github.com/go-git/go-billy/v5 v5.5.0 // indirect
github.com/go-toast/toast v0.0.0-20190211030409-01e6764cf0a4 // indirect
github.com/godbus/dbus/v5 v5.1.0 // indirect
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect
Expand Down
4 changes: 2 additions & 2 deletions internal/checker/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,10 +10,10 @@ import (

type Service struct {
gatewayClient gateway.Client
gitClient *git.Client
gitClient git.Client
}

func New(gw gateway.Client, gc *git.Client) *Service {
func New(gw gateway.Client, gc git.Client) *Service {
return &Service{
gatewayClient: gw,
gitClient: gc,
Expand Down
121 changes: 121 additions & 0 deletions internal/checker/service_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,121 @@
package checker

import (
"sync"
"testing"
"time"

"github.com/gregfurman/pipescope/internal/gateway"
)

type providerMock struct {
mockedGetPipelineBySha func(id, sha string) (*gateway.Pipeline, error)
mockedGetPipeline func(id string, pid int) (*gateway.Pipeline, error)
mockedIsStatusPending func(status string) bool
lock sync.Mutex
}

func (pm *providerMock) GetPipelineBySha(id, sha string) (*gateway.Pipeline, error) {
return pm.mockedGetPipelineBySha(id, sha)
}

func (pm *providerMock) GetPipeline(id string, pid int) (*gateway.Pipeline, error) {
pm.lock.Lock()
pipeline, err := pm.mockedGetPipeline(id, pid)
pm.lock.Unlock()

return pipeline, err
}

func (pm *providerMock) IsStatusPending(status string) bool {
pm.lock.Lock()
flag := pm.mockedIsStatusPending(status)
pm.lock.Unlock()
return flag
}

type gitMock struct {
mockedGetHead func() (string, error)
mockedGetRemoteURL func() (string, error)
}

func (gm *gitMock) GetHead() (string, error) {
return gm.mockedGetHead()
}
func (gm *gitMock) GetRemoteURL() (string, error) {
return gm.mockedGetRemoteURL()
}

func Test_Service(t *testing.T) {
expectedPipeline := gateway.Pipeline{
ID: 1,
ProjectID: "PROJECT_ID",
Status: "pending",
URL: "www.example.com/repo/owner/pipelines/1",
CommitSha: "COMMIT_SHA",
}

providerClient := &providerMock{
mockedGetPipelineBySha: func(id, sha string) (*gateway.Pipeline, error) { return &expectedPipeline, nil },
mockedGetPipeline: func(id string, pid int) (*gateway.Pipeline, error) { return &expectedPipeline, nil },
mockedIsStatusPending: func(status string) bool { return true },
lock: sync.Mutex{},
}

gitClient := &gitMock{
mockedGetHead: func() (string, error) { return "COMMIT_SHA", nil },
mockedGetRemoteURL: func() (string, error) { return "www.example.com/repo/owner", nil },
}

svc := New(providerClient, gitClient)

pipeline, err := svc.GetPipeline()
if err != nil {
t.Error("did not expect error")
}

if *pipeline != expectedPipeline {
t.Errorf("expected pipeline object %v, got %v", *pipeline, expectedPipeline)
}

status, err := svc.GetPipelineStatus()
if err != nil {
t.Error("did not expect error")
}

if status != pipeline.Status {
t.Errorf("expected pipeline status %v, got %v", *pipeline, expectedPipeline)
}

// Poll every 500ms
statusCh, _ := svc.PollPipelineStatus("PROJECT_ID", 1, 500*time.Millisecond)

// Change the status to "success" after 1000ms
time.AfterFunc(1000*time.Millisecond, func() {
providerClient.lock.Lock()
providerClient.mockedIsStatusPending = func(status string) bool { return false }
providerClient.mockedGetPipeline = func(id string, pid int) (*gateway.Pipeline, error) {
return &gateway.Pipeline{
ID: 1,
ProjectID: "PROJECT_ID",
Status: "success",
URL: "www.example.com/repo/owner/pipelines/1",
CommitSha: "COMMIT_SHA",
}, nil
}
providerClient.lock.Unlock()
})

var gotStatus string
for s := range statusCh {
gotStatus = s
if svc.gatewayClient.IsStatusPending(gotStatus) && gotStatus != "pending" {
t.Errorf("expected status to be pending, got %s", gotStatus)
}
}

if gotStatus != "success" {
t.Errorf("expected status to be success, got %s", gotStatus)
}

}
15 changes: 12 additions & 3 deletions internal/gateway/factory.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ import (
"strings"
)

func New(token string, t ProviderType) (Client, error) { //nolint:ireturn
func New(token string, t ProviderType) ( //nolint:ireturn
Client,
error,
) {
switch t {
case GitHub:
return NewGitHubClient(token)
Expand All @@ -16,7 +19,10 @@ func New(token string, t ProviderType) (Client, error) { //nolint:ireturn
}
}

func NewFromToken(token string) (Client, error) { //nolint:ireturn
func NewFromToken(token string) ( //nolint:ireturn
Client,
error,
) {
switch {
case isGitHubToken(token):
return NewGitHubClient(token)
Expand All @@ -28,7 +34,10 @@ func NewFromToken(token string) (Client, error) { //nolint:ireturn
}
}

func NewFromRemoteURL(token, remoteURL string) (Client, error) { //nolint:ireturn
func NewFromRemoteURL(token, remoteURL string) ( //nolint:ireturn
Client,
error,
) {
switch {
case strings.Contains(remoteURL, "github.com"):
return NewGitHubClient(token)
Expand Down
7 changes: 6 additions & 1 deletion internal/gateway/github_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ package gateway

import (
"context"
"errors"
"fmt"
"strings"

Expand Down Expand Up @@ -66,6 +67,10 @@ func (c *GitHubClient) GetPipeline(id string, pid int) (*Pipeline, error) {
return nil, fmt.Errorf("failed to retrieve pipeline from GitHub: %w", err)
}

if workflow == nil || workflow.ID == nil {
return nil, errors.New("no workflows found")
}

return workflowToPipeline(workflow), nil
}

Expand All @@ -80,7 +85,7 @@ func workflowToPipeline(wf *github.WorkflowRun) *Pipeline {
ID: int(wf.GetID()),
ProjectID: wf.GetRepository().GetFullName(),
URL: wf.GetHTMLURL(),
CommitSha: wf.GetHeadCommit().GetSHA(),
CommitSha: wf.GetHeadSHA(),
}
}

Expand Down
Loading

0 comments on commit 1b58e50

Please sign in to comment.