Skip to content

Commit

Permalink
feat: added integration service
Browse files Browse the repository at this point in the history
  • Loading branch information
akhill10 committed Mar 31, 2023
1 parent 670a3ca commit bcbbb4c
Show file tree
Hide file tree
Showing 9 changed files with 550 additions and 4 deletions.
10 changes: 9 additions & 1 deletion cmd/default.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,9 @@ package main
import (
"context"
"fmt"
novu "github.com/novuhq/go-novu/lib"
"log"

novu "github.com/novuhq/go-novu/lib"
)

func main() {
Expand Down Expand Up @@ -82,4 +83,11 @@ func main() {
return
}
fmt.Println(deleteResp)

// get integrations
integrations, err := novuClient.IntegrationsApi.GetAll(ctx)
if err != nil {
log.Fatal("Get all integrations error: ", err.Error())
}
fmt.Println(integrations)
}
136 changes: 136 additions & 0 deletions lib/integration.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,136 @@
package lib

import (
"bytes"
"context"
"encoding/json"
"net/http"

"github.com/pkg/errors"
)

type IIntegration interface {
Create(ctx context.Context, request CreateIntegrationRequest) (*IntegrationResponse, error)
GetAll(ctx context.Context) (*GetIntegrationsResponse, error)
GetActive(ctx context.Context) (*GetIntegrationsResponse, error)
Update(ctx context.Context, integrationId string, request UpdateIntegrationRequest) (*IntegrationResponse, error)
Delete(ctx context.Context, integrationId string) (*IntegrationResponse, error)
}

type IntegrationService service

func (integration *IntegrationService) Create(ctx context.Context, request CreateIntegrationRequest) (*IntegrationResponse, error) {
var response IntegrationResponse
Url := integration.client.config.BackendURL.JoinPath("integrations")

requestBody := CreateIntegrationRequest{
ProviderId: request.ProviderId,
Channel: request.Channel,
Credentials: request.Credentials,
Active: request.Active,
Check: request.Check,
}

jsonBody, _ := json.Marshal(requestBody)

req, err := http.NewRequestWithContext(ctx, http.MethodPost, Url.String(), bytes.NewBuffer(jsonBody))

if err != nil {
return nil, err
}

httpResponse, err := integration.client.sendRequest(req, &response)
if err != nil {
return nil, err
}

if httpResponse.StatusCode != HTTPStatusCreated {
return nil, errors.Wrap(err, "Unable to create integration")
}

return &response, nil
}

func (integration *IntegrationService) GetAll(ctx context.Context) (*GetIntegrationsResponse, error) {
var response GetIntegrationsResponse
Url := integration.client.config.BackendURL.JoinPath("integrations")

req, err := http.NewRequestWithContext(ctx, http.MethodGet, Url.String(), http.NoBody)

if err != nil {
return nil, err
}

_, err = integration.client.sendRequest(req, &response)

if err != nil {
return nil, err
}

return &response, nil
}

func (integration *IntegrationService) GetActive(ctx context.Context) (*GetIntegrationsResponse, error) {
var response GetIntegrationsResponse
Url := integration.client.config.BackendURL.JoinPath("integrations", "active")

req, err := http.NewRequestWithContext(ctx, http.MethodGet, Url.String(), http.NoBody)

if err != nil {
return nil, err
}

_, err = integration.client.sendRequest(req, &response)

if err != nil {
return nil, err
}

return &response, nil
}

func (integration *IntegrationService) Update(ctx context.Context, integrationId string, request UpdateIntegrationRequest) (*IntegrationResponse, error) {
var response IntegrationResponse
Url := integration.client.config.BackendURL.JoinPath("integrations", integrationId)

requestBody := UpdateIntegrationRequest{
Credentials: request.Credentials,
Active: request.Active,
Check: request.Check,
}

jsonBody, _ := json.Marshal(requestBody)

req, err := http.NewRequestWithContext(ctx, http.MethodPut, Url.String(), bytes.NewBuffer(jsonBody))

if err != nil {
return nil, err
}

_, err = integration.client.sendRequest(req, &response)

if err != nil {
return nil, err
}

return &response, nil
}

func (integration *IntegrationService) Delete(ctx context.Context, integrationId string) (*IntegrationResponse, error) {
var response IntegrationResponse
Url := integration.client.config.BackendURL.JoinPath("integrations", integrationId)

req, err := http.NewRequestWithContext(ctx, http.MethodDelete, Url.String(), http.NoBody)

if err != nil {
return nil, err
}

_, err = integration.client.sendRequest(req, &response)

if err != nil {
return nil, err
}

return &response, nil
}
234 changes: 234 additions & 0 deletions lib/integration_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,234 @@
package lib_test

import (
"context"
"encoding/json"
"fmt"
"log"
"net/http"
"net/http/httptest"
"path/filepath"
"strings"
"testing"

"github.com/novuhq/go-novu/lib"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)

type IntegrationRequestDetails[T any] struct {
Url string
Method string
Body T
}

type IntegrationResponseDetails struct {
StatusCode int
Body interface{}
}

type IntegrationServerOptions[T any] struct {
ExpectedRequest IntegrationRequestDetails[T]

ExpectedResponse IntegrationResponseDetails
}

func ValidateIntegrationRequest[T any](t *testing.T, req *http.Request, expectedRequest IntegrationRequestDetails[T]) {
t.Run("Request must be authorized", func(t *testing.T) {
authKey := req.Header.Get("Authorization")
assert.True(t, strings.Contains(authKey, novuApiKey))
assert.True(t, strings.HasPrefix(authKey, "ApiKey"))
})

t.Run("URL and request method is as expected", func(t *testing.T) {
assert.Equal(t, expectedRequest.Method, req.Method)
assert.True(t, strings.HasPrefix(expectedRequest.Url, "/v1/integrations"))
assert.Equal(t, expectedRequest.Url, req.RequestURI)
})
}

func IntegrationTestServer[T any](t *testing.T, options IntegrationServerOptions[T]) *httptest.Server {
var receivedBody T

integrationService := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, req *http.Request) {
ValidateIntegrationRequest(t, req, options.ExpectedRequest)

if req.Body == http.NoBody {
assert.Empty(t, options.ExpectedRequest.Body)
} else {
if err := json.NewDecoder(req.Body).Decode(&receivedBody); err != nil {
log.Printf("error in unmarshalling %+v", err)
w.WriteHeader(http.StatusBadRequest)
return
}

t.Run("Request is as expected", func(t *testing.T) {
assert.Equal(t, options.ExpectedRequest.Body, receivedBody)
})
}

w.WriteHeader(options.ExpectedResponse.StatusCode)

bb, _ := json.Marshal(options.ExpectedResponse.Body)
w.Write(bb)

}))

t.Cleanup(func() {
integrationService.Close()
})

return integrationService
}

func TestCreateIntegration_Success(t *testing.T) {
createIntegrationRequest := lib.CreateIntegrationRequest{
ProviderId: "sendgrid",
Channel: "email",
Credentials: lib.IntegrationCredentials{
ApiKey: "api_key",
SecretKey: "secret_key",
},
Active: true,
Check: false,
}

var response *lib.IntegrationResponse
fileToStruct(filepath.Join("../testdata", "integration_response.json"), &response)

httpServer := IntegrationTestServer(t, IntegrationServerOptions[lib.CreateIntegrationRequest]{
ExpectedRequest: IntegrationRequestDetails[lib.CreateIntegrationRequest]{
Url: "/v1/integrations",
Method: http.MethodPost,
Body: createIntegrationRequest,
},
ExpectedResponse: IntegrationResponseDetails{
StatusCode: http.StatusCreated,
Body: response,
},
})

ctx := context.Background()
novuClient := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)})
res, err := novuClient.IntegrationsApi.Create(ctx, createIntegrationRequest)

assert.Equal(t, response, res)

require.NoError(t, err)
}

func TestGetAllIntegration_Success(t *testing.T) {

var response *lib.GetIntegrationsResponse
fileToStruct(filepath.Join("../testdata", "get_integrations_response.json"), &response)

httpServer := IntegrationTestServer(t, IntegrationServerOptions[interface{}]{
ExpectedRequest: IntegrationRequestDetails[interface{}]{
Url: "/v1/integrations",
Method: http.MethodGet,
},
ExpectedResponse: IntegrationResponseDetails{
StatusCode: http.StatusOK,
Body: response,
},
})

ctx := context.Background()
novuClient := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)})

res, err := novuClient.IntegrationsApi.GetAll(ctx)

assert.Equal(t, response, res)

require.NoError(t, err)
}

func TestGetActiveIntegration_Success(t *testing.T) {

var response *lib.GetIntegrationsResponse
fileToStruct(filepath.Join("../testdata", "get_active_integrations_response.json"), &response)

httpServer := IntegrationTestServer(t, IntegrationServerOptions[interface{}]{
ExpectedRequest: IntegrationRequestDetails[interface{}]{
Url: "/v1/integrations/active",
Method: http.MethodGet,
},
ExpectedResponse: IntegrationResponseDetails{
StatusCode: http.StatusOK,
Body: response,
},
})

ctx := context.Background()
novuClient := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)})

res, err := novuClient.IntegrationsApi.GetActive(ctx)

assert.Equal(t, response, res)

require.NoError(t, err)
}

func TestUpdateIntegration_Success(t *testing.T) {
const integrationId = "integrationId"

updateIntegrationRequest := lib.UpdateIntegrationRequest{
Credentials: lib.IntegrationCredentials{
ApiKey: "new_api_key",
SecretKey: "new_secret_key",
},
Active: true,
Check: false,
}

var response *lib.IntegrationResponse
fileToStruct(filepath.Join("../testdata", "integration_response.json"), &response)

httpServer := IntegrationTestServer(t, IntegrationServerOptions[lib.UpdateIntegrationRequest]{
ExpectedRequest: IntegrationRequestDetails[lib.UpdateIntegrationRequest]{
Url: fmt.Sprintf("/v1/integrations/%s", integrationId),
Method: http.MethodPut,
Body: updateIntegrationRequest,
},
ExpectedResponse: IntegrationResponseDetails{
StatusCode: http.StatusOK,
Body: response,
},
})

ctx := context.Background()
novuClient := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)})

res, err := novuClient.IntegrationsApi.Update(ctx, integrationId, updateIntegrationRequest)

assert.Equal(t, response, res)

require.NoError(t, err)
}

func TestDeleteActiveIntegration_Success(t *testing.T) {
const integrationId = "integrationId"

var response *lib.IntegrationResponse
fileToStruct(filepath.Join("../testdata", "delete_integration_response.json"), &response)

httpServer := IntegrationTestServer(t, IntegrationServerOptions[interface{}]{
ExpectedRequest: IntegrationRequestDetails[interface{}]{
Url: fmt.Sprintf("/v1/integrations/%s", integrationId),
Method: http.MethodDelete,
},
ExpectedResponse: IntegrationResponseDetails{
StatusCode: http.StatusOK,
Body: response,
},
})

ctx := context.Background()
novuClient := lib.NewAPIClient(novuApiKey, &lib.Config{BackendURL: lib.MustParseURL(httpServer.URL)})

res, err := novuClient.IntegrationsApi.Delete(ctx, integrationId)

assert.Equal(t, response, res)

require.NoError(t, err)
}
Loading

0 comments on commit bcbbb4c

Please sign in to comment.