Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .env.test
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ SWITCHER_API_URL=https://switcherapi.com/api/gitops-graphql
SWITCHER_API_JWT_SECRET=[YOUR_JWT_SECRET]

# Only for testing purposes. Values are loaded from accounts
API_DOMAIN_ID=
GIT_TOKEN=
GIT_REPO_URL=https://github.com/switcherapi/switcher-gitops-fixture
GIT_BRANCH=main
3 changes: 3 additions & 0 deletions .github/workflows/master.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,9 @@ jobs:
GO_ENV: test
MONGODB_URI: mongodb://127.0.0.1:27017
MONGO_DB: switcher-gitops-test
SWITCHER_API_URL: ${{ secrets.SWITCHER_API_URL }}
SWITCHER_API_JWT_SECRET: ${{ secrets.SWITCHER_API_JWT_SECRET }}
API_DOMAIN_ID: ${{ secrets.API_DOMAIN_ID }}
GIT_TOKEN: ${{ secrets.GIT_TOKEN }}
GIT_REPO_URL: ${{ secrets.GIT_REPO_URL }}
GIT_BRANCH: ${{ secrets.GIT_BRANCH }}
Expand Down
1 change: 1 addition & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ require (

require (
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/golang-jwt/jwt v3.2.2+incompatible
github.com/gorilla/mux v1.8.1
github.com/pmezard/go-difflib v1.0.0 // indirect
go.mongodb.org/mongo-driver v1.16.0
Expand Down
2 changes: 2 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,8 @@ github.com/go-git/go-git v4.7.0+incompatible h1:+W9rgGY4DOKKdX2x6HxSR7HNeTxqiKrO
github.com/go-git/go-git v4.7.0+incompatible/go.mod h1:6+421e08gnZWn30y26Vchf7efgYLe4dl5OQbBSUXShE=
github.com/go-git/go-git/v5 v5.12.0 h1:7Md+ndsjrzZxbddRDZjF14qK+NN56sy6wkqaVrjZtys=
github.com/go-git/go-git/v5 v5.12.0/go.mod h1:FTM9VKtnI2m65hNI/TenDDDnUf2Q9FHnXYjuz9i5OEY=
github.com/golang-jwt/jwt v3.2.2+incompatible h1:IfV12K8xAKAnZqdXVzCZ+TOjboZ2keLg81eXfW3O+oY=
github.com/golang-jwt/jwt v3.2.2+incompatible/go.mod h1:8pz2t5EyA70fFQQSrl6XZXzqecmYZeUEB8OUGHkxJ+I=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l8iNU+DwB5epxmsaqB+rhGL0m5jtYqE=
github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
Expand Down
105 changes: 105 additions & 0 deletions src/core/api.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,105 @@
package core

import (
"bytes"
"encoding/json"
"fmt"
"io"
"net/http"
"time"

"github.com/golang-jwt/jwt"
)

type GraphQLRequest struct {
Query string `json:"query"`
}

type IAPIService interface {
FetchSnapshot(domainId string, environment string) (string, error)
}

type ApiService struct {
ApiKey string
ApiUrl string
}

func NewApiService(apiKey string, apiUrl string) *ApiService {
return &ApiService{
ApiKey: apiKey,
ApiUrl: apiUrl,
}
}

func (a *ApiService) FetchSnapshot(domainId string, environment string) (string, error) {
// Generate a bearer token
token := generateBearerToken(a.ApiKey, domainId)

// Define the GraphQL query
query := createQuery(domainId, environment)

// Create a new request
reqBody, _ := json.Marshal(GraphQLRequest{Query: query})
req, _ := http.NewRequest("POST", a.ApiUrl, bytes.NewBuffer(reqBody))

// Set the request headers
req.Header.Set("Content-Type", "application/json")
req.Header.Set("Authorization", "Bearer "+token)

// Send the request
client := &http.Client{}
resp, err := client.Do(req)
if err != nil {
return "", err
}
defer resp.Body.Close()

// Read and print the response
body, _ := io.ReadAll(resp.Body)
return string(body), nil
}

func generateBearerToken(apiKey string, subject string) string {
// Define the claims for the JWT token
claims := jwt.MapClaims{
"iss": "GitOps Service",
"sub": "/resource",
"subject": subject,
"exp": time.Now().Add(time.Minute).Unix(),
}

// Create the JWT token
token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)

// Sign the token with the API key
signedToken, _ := token.SignedString([]byte(apiKey))

return signedToken
}

func createQuery(domainId string, environment string) string {
return fmt.Sprintf(`
{
domain(_id: "%s", environment: "%s") {
name
version
group {
name
description
activated
config {
key
description
activated
strategies {
strategy
activated
operation
values
}
components
}
}
}
}`, domainId, environment)
}
45 changes: 45 additions & 0 deletions src/core/api_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
package core

import (
"testing"

"github.com/stretchr/testify/assert"
"github.com/switcherapi/switcher-gitops/src/config"
)

func TestFetchSnapshot(t *testing.T) {
if !canRunIntegratedTests() {
t.Skip(SkipMessage)
}

t.Run("Should return snapshot", func(t *testing.T) {
apiService := NewApiService(config.GetEnv("SWITCHER_API_JWT_SECRET"), config.GetEnv("SWITCHER_API_URL"))
snapshot, _ := apiService.FetchSnapshot(config.GetEnv("API_DOMAIN_ID"), "default")

assert.Contains(t, snapshot, "domain", "Missing domain in snapshot")
assert.Contains(t, snapshot, "version", "Missing version in snapshot")
assert.Contains(t, snapshot, "group", "Missing groups in snapshot")
assert.Contains(t, snapshot, "config", "Missing config in snapshot")
})

t.Run("Should return error - invalid API key", func(t *testing.T) {
apiService := NewApiService("INVALID_KEY", config.GetEnv("SWITCHER_API_URL"))
snapshot, _ := apiService.FetchSnapshot(config.GetEnv("API_DOMAIN_ID"), "default")

assert.Contains(t, snapshot, "Invalid API token")
})

t.Run("Should return error - invalid domain", func(t *testing.T) {
apiService := NewApiService(config.GetEnv("SWITCHER_API_JWT_SECRET"), config.GetEnv("SWITCHER_API_URL"))
snapshot, _ := apiService.FetchSnapshot("INVALID_DOMAIN", "default")

assert.Contains(t, snapshot, "errors")
})

t.Run("Should return error - invalid API URL", func(t *testing.T) {
apiService := NewApiService(config.GetEnv("SWITCHER_API_JWT_SECRET"), "http://localhost:8080")
_, err := apiService.FetchSnapshot(config.GetEnv("API_DOMAIN_ID"), "default")

AssertNotNil(t, err)
})
}
7 changes: 7 additions & 0 deletions src/core/core_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ func shutdown() {
mongoDb.Client().Disconnect(context.Background())
}

func canRunIntegratedTests() bool {
return config.GetEnv("GIT_REPO_URL") != "" &&
config.GetEnv("GIT_TOKEN") != "" &&
config.GetEnv("GIT_BRANCH") != "" &&
config.GetEnv("API_DOMAIN_ID") != ""
}

// Fixtures

func givenAccount() model.Account {
Expand Down
12 changes: 3 additions & 9 deletions src/core/git_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func TestNewGitService(t *testing.T) {
}

func TestGetRepositoryData(t *testing.T) {
if !canRunTests() {
if !canRunIntegratedTests() {
t.Skip(SkipMessage)
}

Expand All @@ -48,7 +48,7 @@ func TestGetRepositoryData(t *testing.T) {
}

func TestGetRepositoryDataErrorInvalidEnvironment(t *testing.T) {
if !canRunTests() {
if !canRunIntegratedTests() {
t.Skip(SkipMessage)
}

Expand All @@ -69,7 +69,7 @@ func TestGetRepositoryDataErrorInvalidEnvironment(t *testing.T) {
}

func TestGetRepositoryDataErrorInvalidToken(t *testing.T) {
if !canRunTests() {
if !canRunIntegratedTests() {
t.Skip(SkipMessage)
}

Expand All @@ -88,9 +88,3 @@ func TestGetRepositoryDataErrorInvalidToken(t *testing.T) {
assert.Empty(t, date)
assert.Empty(t, content)
}

// Helpers

func canRunTests() bool {
return config.GetEnv("GIT_REPO_URL") != "" && config.GetEnv("GIT_TOKEN") != "" && config.GetEnv("GIT_BRANCH") != ""
}