Skip to content
This repository has been archived by the owner on Oct 25, 2023. It is now read-only.

Commit

Permalink
feat: added test cases for optimus
Browse files Browse the repository at this point in the history
  • Loading branch information
Ayushi Sharma committed Sep 28, 2023
1 parent 0aaf135 commit 84a1e15
Show file tree
Hide file tree
Showing 8 changed files with 606 additions and 7 deletions.
2 changes: 2 additions & 0 deletions cli/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ import (

"github.com/goto/dex/internal/server"
"github.com/goto/dex/internal/server/gcs"
"github.com/goto/dex/internal/server/v1/optimus"
"github.com/goto/dex/pkg/logger"
"github.com/goto/dex/pkg/telemetry"
)
Expand Down Expand Up @@ -101,6 +102,7 @@ func runServer(baseCtx context.Context, nrApp *newrelic.Application, zapLog *zap
}
return server.Serve(ctx, cfg.Service.Addr(), nrApp, zapLog,
shieldv1beta1.NewShieldServiceClient(shieldConn),
&optimus.ClientBuilder{},
entropyv1beta1.NewResourceServiceClient(entropyConn),
sirenv1beta1.NewSirenServiceClient(sirenConn),
compassv1beta1grpc.NewCompassServiceClient(compassConn),
Expand Down
3 changes: 2 additions & 1 deletion internal/server/server.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ import (
func Serve(ctx context.Context, addr string,
nrApp *newrelic.Application, logger *zap.Logger,
shieldClient shieldv1beta1.ShieldServiceClient,
optimusClient optimusv1.OptimusClientBuilder,
entropyClient entropyv1beta1.ResourceServiceClient,
sirenClient sirenv1beta1.SirenServiceClient,
compassClient compassv1beta1grpc.CompassServiceClient,
Expand Down Expand Up @@ -59,7 +60,7 @@ func Serve(ctx context.Context, addr string,
r.Get("/alertTemplates", alertSvc.HandleListTemplates())
r.Route("/subscriptions", alertsv1.SubscriptionRoutes(sirenClient, shieldClient))
r.Route("/alerts", alertsv1.AlertRoutes(sirenClient, shieldClient))
r.Route("/optimus", optimusv1.Routes(shieldClient))
r.Route("/optimus", optimusv1.Routes(shieldClient, optimusClient))
r.Route("/projects", projectsv1.Routes(shieldClient))
r.Route("/dlq", dlqv1.Routes(entropyClient, gcsClient))
r.Route("/firehoses", firehosev1.Routes(entropyClient, shieldClient, alertSvc, compassClient, odinAddr, stencilAddr))
Expand Down
6 changes: 3 additions & 3 deletions internal/server/v1/optimus/optimus_client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@ import (
"google.golang.org/grpc/credentials/insecure"
)

type ClientBuilder struct{}

type OptimusClientBuilder interface {
BuildOptimusClient(hostname string) (optimusv1beta1grpc.JobSpecificationServiceClient, error)
}

type clientBuilder struct{}

func (*clientBuilder) BuildOptimusClient(hostname string) (optimusv1beta1grpc.JobSpecificationServiceClient, error) {
func (*ClientBuilder) BuildOptimusClient(hostname string) (optimusv1beta1grpc.JobSpecificationServiceClient, error) {
optimusConn, err := grpc.Dial(hostname, grpc.WithTransportCredentials(insecure.NewCredentials()))
if err != nil {
return nil, err
Expand Down
22 changes: 22 additions & 0 deletions internal/server/v1/optimus/optimus_client_mock.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package optimus

import (
optimusv1beta1grpc "buf.build/gen/go/gotocompany/proton/grpc/go/gotocompany/optimus/core/v1beta1/corev1beta1grpc"
"github.com/stretchr/testify/mock"
)

type OptimusClientMock struct {
mock.Mock
}

type OptimusClientBuilderMock interface {
BuildOptimusClient(hostname string) (optimusv1beta1grpc.JobSpecificationServiceClient, error)
}

func (mock *OptimusClientMock) BuildOptimusClient(hostname string) (optimusv1beta1grpc.JobSpecificationServiceClient, error) {
args := mock.Called(hostname)
if args[0] == nil {
return nil, args[1].(error)

Check failure on line 19 in internal/server/v1/optimus/optimus_client_mock.go

View workflow job for this annotation

GitHub Actions / golangci-lint

type assertion must be checked (forcetypeassert)

Check failure on line 19 in internal/server/v1/optimus/optimus_client_mock.go

View workflow job for this annotation

GitHub Actions / golangci-lint

type assertion must be checked (forcetypeassert)
}
return args.Get(0).(optimusv1beta1grpc.JobSpecificationServiceClient), args.Error(1)

Check failure on line 21 in internal/server/v1/optimus/optimus_client_mock.go

View workflow job for this annotation

GitHub Actions / golangci-lint

type assertion must be checked (forcetypeassert)

Check failure on line 21 in internal/server/v1/optimus/optimus_client_mock.go

View workflow job for this annotation

GitHub Actions / golangci-lint

type assertion must be checked (forcetypeassert)
}
4 changes: 2 additions & 2 deletions internal/server/v1/optimus/routes.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import (
"github.com/go-chi/chi/v5"
)

func Routes(shieldClient shieldv1beta1rpc.ShieldServiceClient) func(r chi.Router) {
service := NewService(shieldClient, &clientBuilder{})
func Routes(shieldClient shieldv1beta1rpc.ShieldServiceClient, optimusClient OptimusClientBuilder) func(r chi.Router) {
service := NewService(shieldClient, optimusClient)
handler := NewHandler(service)

return func(r chi.Router) {
Expand Down
269 changes: 269 additions & 0 deletions internal/server/v1/optimus/routes_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,269 @@
package optimus_test

import (
"encoding/json"
"fmt"
"net/http"
"net/http/httptest"
"testing"

optimusv1beta1 "buf.build/gen/go/gotocompany/proton/protocolbuffers/go/gotocompany/optimus/core/v1beta1"
shieldv1beta1 "buf.build/gen/go/gotocompany/proton/protocolbuffers/go/gotocompany/shield/v1beta1"
"github.com/go-chi/chi/v5"
"github.com/goto/dex/internal/server/v1/optimus"

Check failure on line 13 in internal/server/v1/optimus/routes_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gci`-ed with --skip-generated -s standard,default,prefix(github.com/goto/dex) (gci)

Check failure on line 13 in internal/server/v1/optimus/routes_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gci`-ed with --skip-generated -s standard,default,prefix(github.com/goto/dex) (gci)
"github.com/goto/dex/mocks"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/mock"
"github.com/stretchr/testify/require"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"

Check failure on line 19 in internal/server/v1/optimus/routes_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gci`-ed with --skip-generated -s standard,default,prefix(github.com/goto/dex) (gci)

Check failure on line 19 in internal/server/v1/optimus/routes_test.go

View workflow job for this annotation

GitHub Actions / golangci-lint

File is not `gci`-ed with --skip-generated -s standard,default,prefix(github.com/goto/dex) (gci)
)

func TestRoutesFindJobSpec(t *testing.T) {
jobName := "sample-optimus-job-name"
hostname := "optimus.staging.golabs.io:80"
projectSlug := "sample-project"
method := http.MethodGet
path := fmt.Sprintf("/projects/%s/jobs/%s", projectSlug, jobName)

t.Run("should return 200 with job spec", func(t *testing.T) {
jobSpecRes := &optimusv1beta1.JobSpecificationResponse{
ProjectName: projectSlug,
NamespaceName: "test-namespcace",
Job: &optimusv1beta1.JobSpecification{
Version: 1,
Name: "sample-job",
Owner: "goto",
TaskName: "sample-task-name",
},
}

projectRes := &shieldv1beta1.GetProjectResponse{
Project: &shieldv1beta1.Project{
Slug: "test-project",
Metadata: newStruct(t, map[string]interface{}{
"optimus_host": hostname,
}),
},
}

shieldClient := new(mocks.ShieldServiceClient)
shieldClient.On("GetProject", mock.Anything, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
}).Return(projectRes, nil)

optimusClient := new(optimus.OptimusClientMock)
defer shieldClient.AssertExpectations(t)

client := mocks.NewJobSpecificationServiceClient(t)
optimusClient.On("BuildOptimusClient", hostname).Return(client, nil)
defer optimusClient.AssertExpectations(t)

client.On("GetJobSpecifications", mock.Anything, &optimusv1beta1.GetJobSpecificationsRequest{
ProjectName: projectSlug,
JobName: jobName,
}).Return(&optimusv1beta1.GetJobSpecificationsResponse{
JobSpecificationResponses: []*optimusv1beta1.JobSpecificationResponse{
jobSpecRes,
},
}, nil)

response := httptest.NewRecorder()
request := httptest.NewRequest(method, path, nil)
router := chi.NewRouter()
optimus.Routes(shieldClient, optimusClient)(router)
router.ServeHTTP(response, request)
// assert
assert.Equal(t, http.StatusOK, response.Code)
resultJSON := response.Body.Bytes()
expectedJSON, err := json.Marshal(jobSpecRes)
require.NoError(t, err)
assert.JSONEq(t, string(expectedJSON), string(resultJSON))
})

t.Run("should return 404 if job could not be found", func(t *testing.T) {
projectRes := &shieldv1beta1.GetProjectResponse{
Project: &shieldv1beta1.Project{
Slug: "test-project",
Metadata: newStruct(t, map[string]interface{}{
"optimus_host": hostname,
}),
},
}

shieldClient := new(mocks.ShieldServiceClient)
shieldClient.On("GetProject", mock.Anything, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
}).Return(projectRes, nil)

optimusClient := new(optimus.OptimusClientMock)
defer shieldClient.AssertExpectations(t)

client := mocks.NewJobSpecificationServiceClient(t)
optimusClient.On("BuildOptimusClient", hostname).Return(client, nil)
defer optimusClient.AssertExpectations(t)

client.On("GetJobSpecifications", mock.Anything, &optimusv1beta1.GetJobSpecificationsRequest{
ProjectName: projectSlug,
JobName: jobName,
}).Return(&optimusv1beta1.GetJobSpecificationsResponse{}, nil)
defer client.AssertExpectations(t)
response := httptest.NewRecorder()
request := httptest.NewRequest(method, path, nil)
router := chi.NewRouter()
optimus.Routes(shieldClient, optimusClient)(router)
router.ServeHTTP(response, request)
assert.Equal(t, http.StatusNotFound, response.Code)
})

t.Run("should return 500 for internal error", func(t *testing.T) {
clientError := status.Error(codes.Internal, "Internal")

projectRes := &shieldv1beta1.GetProjectResponse{
Project: &shieldv1beta1.Project{
Slug: "test-project",
Metadata: newStruct(t, map[string]interface{}{
"optimus_host": hostname,
}),
},
}

shieldClient := new(mocks.ShieldServiceClient)
shieldClient.On("GetProject", mock.Anything, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
}).Return(projectRes, nil)

optimusClient := new(optimus.OptimusClientMock)
defer shieldClient.AssertExpectations(t)

client := mocks.NewJobSpecificationServiceClient(t)
optimusClient.On("BuildOptimusClient", hostname).Return(client, nil)
defer optimusClient.AssertExpectations(t)
client.On("GetJobSpecifications", mock.Anything, &optimusv1beta1.GetJobSpecificationsRequest{
ProjectName: projectSlug,
JobName: jobName,
}).Return(nil, clientError)
defer client.AssertExpectations(t)
response := httptest.NewRecorder()
request := httptest.NewRequest(method, path, nil)
router := chi.NewRouter()
optimus.Routes(shieldClient, optimusClient)(router)
router.ServeHTTP(response, request)
assert.Equal(t, http.StatusInternalServerError, response.Code)
})
}

func TestRoutesListJobs(t *testing.T) {
projectSlug := "sample-project"
hostname := "optimus.staging.golabs.io:80"
method := http.MethodGet
path := fmt.Sprintf("/projects/%s/jobs", projectSlug)

t.Run("should return 200 with jobs list", func(t *testing.T) {
jobSpec1 := &optimusv1beta1.JobSpecificationResponse{
ProjectName: "test-project",
NamespaceName: "test-namespcace",
Job: &optimusv1beta1.JobSpecification{
Version: 1,
Name: "sample-job1",
Owner: "goto",
TaskName: "sample-task-name",
},
}

jobSpec2 := &optimusv1beta1.JobSpecificationResponse{
ProjectName: "test-project",
Job: &optimusv1beta1.JobSpecification{
Version: 1,
Name: "sample-job2",
Owner: "goto",
TaskName: "sample-task-name",
},
}

expectedJobSpecRes := []*optimusv1beta1.JobSpecificationResponse{
jobSpec1,
jobSpec2,
}

projectRes := &shieldv1beta1.GetProjectResponse{
Project: &shieldv1beta1.Project{
Slug: "test-project",
Metadata: newStruct(t, map[string]interface{}{
"optimus_host": hostname,
}),
},
}

shieldClient := new(mocks.ShieldServiceClient)
shieldClient.On("GetProject", mock.Anything, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
}).Return(projectRes, nil)

optimusClient := new(optimus.OptimusClientMock)
defer shieldClient.AssertExpectations(t)

client := mocks.NewJobSpecificationServiceClient(t)
optimusClient.On("BuildOptimusClient", hostname).Return(client, nil)
defer optimusClient.AssertExpectations(t)

client.On("GetJobSpecifications", mock.Anything, &optimusv1beta1.GetJobSpecificationsRequest{
ProjectName: projectSlug,
}).Return(&optimusv1beta1.GetJobSpecificationsResponse{
JobSpecificationResponses: expectedJobSpecRes,
}, nil)
defer client.AssertExpectations(t)

response := httptest.NewRecorder()
request := httptest.NewRequest(method, path, nil)

router := chi.NewRouter()
optimus.Routes(shieldClient, optimusClient)(router)
router.ServeHTTP(response, request)

// assert
assert.Equal(t, http.StatusOK, response.Code)
resultJSON := response.Body.Bytes()
expectedJSON, err := json.Marshal(expectedJobSpecRes)
require.NoError(t, err)
assert.JSONEq(t, string(expectedJSON), string(resultJSON))
})

t.Run("should return 500 for internal error", func(t *testing.T) {
clientError := status.Error(codes.Internal, "Internal")

projectRes := &shieldv1beta1.GetProjectResponse{
Project: &shieldv1beta1.Project{
Slug: "test-project",
Metadata: newStruct(t, map[string]interface{}{
"optimus_host": hostname,
}),
},
}

shieldClient := new(mocks.ShieldServiceClient)
shieldClient.On("GetProject", mock.Anything, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
}).Return(projectRes, nil)

optimusClient := new(optimus.OptimusClientMock)
defer shieldClient.AssertExpectations(t)

client := mocks.NewJobSpecificationServiceClient(t)
optimusClient.On("BuildOptimusClient", hostname).Return(client, nil)
defer optimusClient.AssertExpectations(t)

client.On("GetJobSpecifications", mock.Anything, &optimusv1beta1.GetJobSpecificationsRequest{
ProjectName: projectSlug,
}).Return(nil, clientError)
defer client.AssertExpectations(t)

response := httptest.NewRecorder()
request := httptest.NewRequest(method, path, nil)
router := chi.NewRouter()
optimus.Routes(shieldClient, optimusClient)(router)
router.ServeHTTP(response, request)

assert.Equal(t, http.StatusInternalServerError, response.Code)
})
}
2 changes: 1 addition & 1 deletion internal/server/v1/optimus/service.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,10 +67,10 @@ func (svc *Service) ListJobs(ctx context.Context, projectSlug string) ([]*optimu

func (svc *Service) getOptimusClient(ctx context.Context, projectSlug string) (optimusv1beta1grpc.JobSpecificationServiceClient, error) {
// retrieve hostname from cache

if cl, exists := svc.data[projectSlug]; exists {
return cl, nil
}

// retrieve hostname from shield
prj, err := svc.shieldClient.GetProject(ctx, &shieldv1beta1.GetProjectRequest{
Id: projectSlug,
Expand Down
Loading

0 comments on commit 84a1e15

Please sign in to comment.