Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adding unit tests #13

Merged
merged 1 commit into from
Mar 11, 2024
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
27 changes: 27 additions & 0 deletions .github/workflows/go-tests.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Go Tests

on:
push:
branches:
- main
pull_request:
branches:
- main

jobs:
go-tests:
runs-on: ubuntu-latest

steps:
- name: Checkout
uses: actions/checkout@v3

- name: Setup Golang
uses: actions/setup-go@v3
with:
go-version-file: go.mod

- run: go version

- name: Run GARM Go Tests
run: make go-test
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Don't forget the makefile. Or you could just call go test

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added the Makefile now

6 changes: 6 additions & 0 deletions Makefile
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
SHELL := bash

.PHONY: go-test

go-test:
go test -v ./... $(TEST_ARGS) -timeout=15m -parallel=4
143 changes: 143 additions & 0 deletions config/config_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,143 @@
// SPDX-License-Identifier: Apache-2.0
// Copyright 2024 Cloudbase Solutions SRL
//
// Licensed under the Apache License, Version 2.0 (the "License"); you may
// not use this file except in compliance with the License. You may obtain
// a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
// WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
// License for the specific language governing permissions and limitations
// under the License.

package config

import (
"fmt"
"os"
"testing"

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

func TestConfig_Validate(t *testing.T) {
tests := []struct {
name string
config *Config
errString error
}{
{
name: "ValidConfig",
config: &Config{
Zone: "europe-west1-d",
ProjectId: "my-project",
NetworkID: "my-network",
SubnetworkID: "my-subnetwork",
CredentialsFile: "path/to/credentials.json",
ExternalIPAccess: true,
},
errString: nil,
},
{
name: "MissingRegion",
config: &Config{
ProjectId: "my-project",
NetworkID: "my-network",
SubnetworkID: "my-subnetwork",
CredentialsFile: "path/to/credentials.json",
ExternalIPAccess: true,
},
errString: fmt.Errorf("missing region"),
},
{
name: "MissingProjectID",
config: &Config{
Zone: "europe-west1-d",
NetworkID: "my-network",
SubnetworkID: "my-subnetwork",
CredentialsFile: "path/to/credentials.json",
},
errString: fmt.Errorf("missing project_id"),
},
{
name: "MissingNetworkID",
config: &Config{
Zone: "europe-west1-d",
ProjectId: "my-project",
SubnetworkID: "my-subnetwork",
CredentialsFile: "path/to/credentials.json",
ExternalIPAccess: true,
},
errString: fmt.Errorf("missing network_id"),
},
{
name: "MissingSubnetworkID",
config: &Config{
Zone: "europe-west1-d",
ProjectId: "my-project",
NetworkID: "my-network",
CredentialsFile: "path/to/credentials.json",
ExternalIPAccess: true,
},
errString: fmt.Errorf("missing subnetwork_id"),
},
{
name: "MissingCredentialsFile",
config: &Config{
Zone: "europe-west1-d",
ProjectId: "my-project",
NetworkID: "my-network",
SubnetworkID: "my-subnetwork",
ExternalIPAccess: true,
},
errString: fmt.Errorf("missing credentials_file"),
},
}

for _, tc := range tests {
t.Run(tc.name, func(t *testing.T) {
err := tc.config.Validate()
if tc.errString == nil {
require.Nil(t, err)
} else {
require.Equal(t, tc.errString, err)
}

})
}
}

func TestNewConfig(t *testing.T) {
mockData := `
project_id = "garm-testing"
zone = "europe-west1-d"
network_id = "projects/garm-testing/global/networks/garm"
subnetwork_id = "projects/garm-testing/regions/europe-west1/subnetworks/garm"
credentials_file = "/home/ubuntu/service-account-key.json"
external_ip_access = true
`
// Create a temporary file
tmpFile, err := os.CreateTemp("", "config-*.toml")
require.NoError(t, err, "Failed to create temporary file")
defer os.Remove(tmpFile.Name())

_, err = tmpFile.WriteString(mockData)
require.NoError(t, err, "Failed to write to temporary file")
err = tmpFile.Close()
require.NoError(t, err, "Failed to close temporary file")

// Use the temporary file path as the argument to NewConfig
cfg, err := NewConfig(tmpFile.Name())
require.NoError(t, err, "NewConfig returned an error")

// Validate the content of the Config object
require.Equal(t, "garm-testing", cfg.ProjectId, "ProjectId value did not match expected")
require.Equal(t, "europe-west1-d", cfg.Zone, "Zone value did not match expected")
require.Equal(t, "projects/garm-testing/global/networks/garm", cfg.NetworkID, "NetworkId value did not match expected")
require.Equal(t, "projects/garm-testing/regions/europe-west1/subnetworks/garm", cfg.SubnetworkID, "SubnetworkId value did not match expected")
require.Equal(t, "/home/ubuntu/service-account-key.json", cfg.CredentialsFile, "CredentialsFile value did not match expected")
require.Equal(t, true, cfg.ExternalIPAccess, "ExternalIpAccess value did not match expected")
}
4 changes: 4 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ require (
github.com/BurntSushi/toml v1.3.2
github.com/cloudbase/garm-provider-common v0.1.2-0.20240216125425-bbe4930a1ebf
github.com/googleapis/gax-go/v2 v2.12.0
github.com/stretchr/testify v1.9.0
github.com/xeipuuv/gojsonschema v1.2.0
golang.org/x/oauth2 v0.16.0
google.golang.org/api v0.156.0
Expand All @@ -15,6 +16,7 @@ require (

require (
cloud.google.com/go/compute/metadata v0.2.3 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.1 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
Expand All @@ -27,6 +29,8 @@ require (
github.com/mattn/go-isatty v0.0.19 // indirect
github.com/minio/sio v0.3.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/stretchr/objx v0.5.2 // indirect
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 // indirect
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f // indirect
github.com/xeipuuv/gojsonreference v0.0.0-20180127040603-bd5ef7bd5415 // indirect
Expand Down
6 changes: 4 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -78,12 +78,14 @@ github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/objx v0.5.2 h1:xuMeJ0Sdp5ZMRXx/aWO6RZxdr3beISkG5/G/aIRr3pY=
github.com/stretchr/objx v0.5.2/go.mod h1:FRsXN1f5AsAjCGJKqEizvkpNtU+EGNCLh3NxZ/8L+MA=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/stretchr/testify v1.8.4 h1:CcVxjf3Q8PM0mHUKJCdn+eZZtm5yQwehR5yeSVQQcUk=
github.com/stretchr/testify v1.8.4/go.mod h1:sz/lmYIOXD/1dqDmKjjqLyZ2RngseejIcXlSw2iwfAo=
github.com/stretchr/testify v1.9.0 h1:HtqpIVDClZ4nwg75+f6Lvsy/wHu+3BoSGCbBAcpTsTg=
github.com/stretchr/testify v1.9.0/go.mod h1:r2ic/lqez/lEtzL7wO/rwa5dbSLXVDPFyf8C91i36aY=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569 h1:xzABM9let0HLLqFypcxvLmlvEciCHL7+Lv+4vwZqecI=
github.com/teris-io/shortid v0.0.0-20220617161101-71ec9f2aa569/go.mod h1:2Ly+NIftZN4de9zRmENdYbvPQeaVIYKWpLFStLFEBgI=
github.com/xeipuuv/gojsonpointer v0.0.0-20180127040702-4e3ac2762d5f h1:J9EGpcZtP0E/raorCMxlFGSTBrsSlaDGf3jU/qvAE2c=
Expand Down
44 changes: 37 additions & 7 deletions internal/client/gcp.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import (
"github.com/cloudbase/garm-provider-gcp/config"
"github.com/cloudbase/garm-provider-gcp/internal/spec"
"github.com/cloudbase/garm-provider-gcp/internal/util"
"github.com/googleapis/gax-go/v2"
"github.com/googleapis/gax-go/v2/apierror"
"golang.org/x/oauth2/google"
gcompute "google.golang.org/api/compute/v1"
Expand All @@ -39,6 +40,11 @@ const (
accessConfigType string = "ONE_TO_ONE_NAT"
)

var (
WaitOp = (*compute.Operation).Wait
NextIt = (*compute.InstanceIterator).Next
)

func NewGcpCli(ctx context.Context, cfg *config.Config) (*GcpCli, error) {
jsonKey, err := os.ReadFile(cfg.CredentialsFile)
if err != nil {
Expand All @@ -64,10 +70,34 @@ func NewGcpCli(ctx context.Context, cfg *config.Config) (*GcpCli, error) {
return gcpCli, nil
}

type ClientInterface interface {
Insert(ctx context.Context, req *computepb.InsertInstanceRequest, opts ...gax.CallOption) (*compute.Operation, error)
Start(ctx context.Context, req *computepb.StartInstanceRequest, opts ...gax.CallOption) (*compute.Operation, error)
Stop(ctx context.Context, req *computepb.StopInstanceRequest, opts ...gax.CallOption) (*compute.Operation, error)
Delete(ctx context.Context, req *computepb.DeleteInstanceRequest, opts ...gax.CallOption) (*compute.Operation, error)
List(ctx context.Context, req *computepb.ListInstancesRequest, opts ...gax.CallOption) *compute.InstanceIterator
Get(ctx context.Context, req *computepb.GetInstanceRequest, opts ...gax.CallOption) (*computepb.Instance, error)
}

type GcpCli struct {
cfg *config.Config
cfg *config.Config
client ClientInterface
}

func (g GcpCli) Config() *config.Config {
return g.cfg
}

func (g GcpCli) Client() ClientInterface {
return g.client
}

func (g *GcpCli) SetClient(client ClientInterface) {
g.client = client
}

client *compute.InstancesClient
func (g *GcpCli) SetConfig(cfg *config.Config) {
g.cfg = cfg
}

func (g *GcpCli) CreateInstance(ctx context.Context, spec *spec.RunnerSpec) (*computepb.Instance, error) {
Expand Down Expand Up @@ -128,7 +158,7 @@ func (g *GcpCli) CreateInstance(ctx context.Context, spec *spec.RunnerSpec) (*co
return nil, fmt.Errorf("failed to create instance %s: %w", insertReq, err)
}

if err = op.Wait(ctx); err != nil {
if err = WaitOp(op, ctx); err != nil {
return nil, fmt.Errorf("failed to wait for operation: %w", err)
}

Expand Down Expand Up @@ -161,7 +191,7 @@ func (g *GcpCli) ListDescribedInstances(ctx context.Context, poolID string) ([]*
it := g.client.List(ctx, req)
var instances []*computepb.Instance
for {
instance, _ := it.Next()
instance, _ := NextIt(it)
if instance == nil {
break
}
Expand All @@ -184,7 +214,7 @@ func (g *GcpCli) DeleteInstance(ctx context.Context, instance string) error {
return fmt.Errorf("unable to delete instance: %w", err)
}

if err = op.Wait(ctx); err != nil {
if err = WaitOp(op, ctx); err != nil {
return fmt.Errorf("unable to wait for the delete operation: %w", err)
}

Expand All @@ -203,7 +233,7 @@ func (g *GcpCli) StopInstance(ctx context.Context, instance string) error {
return fmt.Errorf("unable to stop instance: %w", err)
}

if err = op.Wait(ctx); err != nil {
if err = WaitOp(op, ctx); err != nil {
return fmt.Errorf("unable to wait for the operation: %w", err)
}

Expand All @@ -222,7 +252,7 @@ func (g *GcpCli) StartInstance(ctx context.Context, instance string) error {
return fmt.Errorf("unable to start instance: %w", err)
}

if err = op.Wait(ctx); err != nil {
if err = WaitOp(op, ctx); err != nil {
return fmt.Errorf("unable to wait for the operation: %w", err)
}

Expand Down
Loading