From 1bd6512d6abd0ace178b3bea80296556ee70705b Mon Sep 17 00:00:00 2001 From: Youjung Kim <126618609+ykim-1@users.noreply.github.com> Date: Fri, 19 Jan 2024 09:38:56 -0800 Subject: [PATCH] test: add unit tests (#31) * adding initial set of unit tests except for client.go * Add unit-test command in Makefile --- Makefile | 3 ++ go.mod | 12 ++++++-- go.sum | 10 +++++++ instance_test.go | 72 ++++++++++++++++++++++++++++++++++++++++++++++++ network_test.go | 65 +++++++++++++++++++++++++++++++++++++++++++ sshkeys_test.go | 53 +++++++++++++++++++++++++++++++++++ token_test.go | 43 +++++++++++++++++++++++++++++ userdata_test.go | 46 +++++++++++++++++++++++++++++++ watchers_test.go | 15 ++++++++++ 9 files changed, 317 insertions(+), 2 deletions(-) create mode 100644 instance_test.go create mode 100644 network_test.go create mode 100644 sshkeys_test.go create mode 100644 token_test.go create mode 100644 userdata_test.go create mode 100644 watchers_test.go diff --git a/Makefile b/Makefile index 0b5ab64..1f4002b 100644 --- a/Makefile +++ b/Makefile @@ -39,3 +39,6 @@ e2e: # NOTE: E2E tests must be run from within a Linode. e2e-local: cd test/integration && make e2e-local + +unit-test: + go test -v ./ diff --git a/go.mod b/go.mod index 45c61ce..a9b6b23 100644 --- a/go.mod +++ b/go.mod @@ -2,6 +2,14 @@ module github.com/linode/go-metadata go 1.20 -require github.com/go-resty/resty/v2 v2.9.1 +require ( + github.com/go-resty/resty/v2 v2.9.1 + github.com/stretchr/testify v1.8.4 +) -require golang.org/x/net v0.17.0 // indirect +require ( + github.com/davecgh/go-spew v1.1.1 // indirect + github.com/pmezard/go-difflib v1.0.0 // indirect + golang.org/x/net v0.17.0 // indirect + gopkg.in/yaml.v3 v3.0.1 // indirect +) diff --git a/go.sum b/go.sum index 3123df2..85a7eb7 100644 --- a/go.sum +++ b/go.sum @@ -1,5 +1,11 @@ +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/go-resty/resty/v2 v2.9.1 h1:PIgGx4VrHvag0juCJ4dDv3MiFRlDmP0vicBucwf+gLM= github.com/go-resty/resty/v2 v2.9.1/go.mod h1:4/GYJVjh9nhkhGR6AUNW3XhpDYNUr+Uvy9gV/VGZIy4= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +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/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20210921155107-089bfa567519/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= @@ -43,3 +49,7 @@ golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/tools v0.1.12/go.mod h1:hNGJHUnrk76NpqgfD5Aqm5Crs+Hm0VOH/i9J2+nxYbc= golang.org/x/tools v0.6.0/go.mod h1:Xwgl3UAJ/d3gWutnCtw505GrjyAbvKui8lOU390QaIU= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= +gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= diff --git a/instance_test.go b/instance_test.go new file mode 100644 index 0000000..1436f4e --- /dev/null +++ b/instance_test.go @@ -0,0 +1,72 @@ +package metadata + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +// mock client for testing purposes +type InstanceMockclient struct { + Resp *InstanceData + Err error +} + +func (m *InstanceMockclient) GetInstance(ctx context.Context) (*InstanceData, error) { + if m.Err != nil { + return nil, m.Err + } + return m.Resp, nil +} + +func TestGetInstance_Success(t *testing.T) { + // Create a mock client with a successful response + mockClient := &InstanceMockclient{ + Resp: &InstanceData{ + ID: 1, + Label: "test-instance", + Region: "us-west", + Type: "standard", + HostUUID: "abc123", + Tags: []string{"tag1", "tag2"}, + Specs: InstanceSpecsData{ + VCPUs: 2, + Memory: 4096, + GPUs: 0, + Transfer: 2000, + Disk: 50, + }, + Backups: InstanceBackupsData{ + Enabled: true, + Status: String("active"), + }, + }, + } + + instance, err := mockClient.GetInstance(context.Background()) + + // Assert the result + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, instance, "Expected non-nil instance") + assert.Equal(t, "test-instance", instance.Label, "Unexpected instance label") +} + +func TestGetInstance_Error(t *testing.T) { + // Create a mock client with an error response + mockClient := &InstanceMockclient{ + Err: errors.New("mock error"), + } + + instance, err := mockClient.GetInstance(context.Background()) + + assert.Error(t, err, "Expected an error") + assert.Nil(t, instance, "Expected nil instance") + assert.EqualError(t, err, "mock error", "Unexpected error message") +} + +// Helper function to create a string pointer +func String(s string) *string { + return &s +} diff --git a/network_test.go b/network_test.go new file mode 100644 index 0000000..23898f8 --- /dev/null +++ b/network_test.go @@ -0,0 +1,65 @@ +package metadata + +import ( + "context" + "errors" + "net/netip" + "testing" + + "github.com/stretchr/testify/assert" +) + +// mock client for testing purposes +type NetworkMockclient struct { + Resp *NetworkData + Err error +} + +func (m *NetworkMockclient) GetNetwork(ctx context.Context) (*NetworkData, error) { + if m.Err != nil { + return nil, m.Err + } + return m.Resp, nil +} + +func TestGetNetwork_Success(t *testing.T) { + mockClient := &NetworkMockclient{ + Resp: &NetworkData{ + Interfaces: []InterfaceData{ + {Label: "eth0", Purpose: "public", IPAMAddress: netip.MustParsePrefix("203.0.113.0/24")}, + {Label: "eth1", Purpose: "private", IPAMAddress: netip.MustParsePrefix("192.168.1.0/24")}, + }, + IPv4: IPv4Data{ + Public: []netip.Prefix{netip.MustParsePrefix("203.0.113.0/24")}, + Private: []netip.Prefix{netip.MustParsePrefix("192.168.1.0/24")}, + Shared: []netip.Prefix{netip.MustParsePrefix("198.51.100.0/24")}, + }, + IPv6: IPv6Data{ + SLAAC: netip.MustParsePrefix("2001:db8::/64"), + LinkLocal: netip.MustParsePrefix("fe80::/64"), + Ranges: []netip.Prefix{netip.MustParsePrefix("2001:db8::/64")}, + SharedRanges: []netip.Prefix{netip.MustParsePrefix("fd00::/64")}, + }, + }, + } + + network, err := mockClient.GetNetwork(context.Background()) + + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, network, "Expected non-nil network") + assert.Len(t, network.Interfaces, 2, "Unexpected number of interfaces") + assert.Len(t, network.IPv4.Public, 1, "Unexpected number of public IPv4 prefixes") + assert.Len(t, network.IPv6.Ranges, 1, "Unexpected number of IPv6 ranges") +} + +func TestGetNetwork_Error(t *testing.T) { + mockClient := &NetworkMockclient{ + Err: errors.New("mock error"), + } + + network, err := mockClient.GetNetwork(context.Background()) + + assert.Error(t, err, "Expected an error") + assert.Nil(t, network, "Expected nil network") + assert.EqualError(t, err, "mock error", "Unexpected error message") +} diff --git a/sshkeys_test.go b/sshkeys_test.go new file mode 100644 index 0000000..8a9d918 --- /dev/null +++ b/sshkeys_test.go @@ -0,0 +1,53 @@ +package metadata + +import ( + "context" + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +type SshkeysMockclient struct { + Resp *SSHKeysData + Err error +} + +func (m *SshkeysMockclient) GetSSHKeys(ctx context.Context) (*SSHKeysData, error) { + if m.Err != nil { + return nil, m.Err + } + return m.Resp, nil +} + +func TestGetSSHKeys_Success(t *testing.T) { + // Create a mock client with a successful response + mockClient := &SshkeysMockclient{ + Resp: &SSHKeysData{ + Users: SSHKeysUserData{ + Root: []string{"ssh-randomkeyforunittestas;ldkjfqweeru", "ssh-randomkeyforunittestas;ldkjfqweerutwo"}, + }, + }, + } + + sshKeys, err := mockClient.GetSSHKeys(context.Background()) + + assert.NoError(t, err, "Expected no error") + assert.NotNil(t, sshKeys, "Expected non-nil SSHKeysData") + assert.Len(t, sshKeys.Users.Root, 2, "Unexpected number of root SSH keys") +} + +func TestGetSSHKeys_Error(t *testing.T) { + // Create a mock client with an error response + mockClient := &SshkeysMockclient{ + Err: errors.New("mock error"), + } + + // Call the GetSSHKeys method + sshKeys, err := mockClient.GetSSHKeys(context.Background()) + + // Assert the result + assert.Error(t, err, "Expected an error") + assert.Nil(t, sshKeys, "Expected nil SSHKeysData") + assert.EqualError(t, err, "mock error", "Unexpected error message") +} diff --git a/token_test.go b/token_test.go new file mode 100644 index 0000000..9328a03 --- /dev/null +++ b/token_test.go @@ -0,0 +1,43 @@ +package metadata + +import ( + "context" + "errors" + "github.com/stretchr/testify/assert" + "testing" +) + +type TokenMockclient struct { + Token string + GenerateTokenErr error +} + +func (m *TokenMockclient) GenerateToken(ctx context.Context, opts ...TokenOption) (string, error) { + if m.GenerateTokenErr != nil { + return "", m.GenerateTokenErr + } + return m.Token, nil +} + +func TestGenerateToken_Success(t *testing.T) { + mockClient := &TokenMockclient{ + Token: "mock-token-value", + } + + token, err := mockClient.GenerateToken(context.Background()) + + assert.NoError(t, err, "Expected no error") + assert.Equal(t, "mock-token-value", token, "Unexpected token") +} + +func TestGenerateToken_Error(t *testing.T) { + mockClient := &TokenMockclient{ + GenerateTokenErr: errors.New("mock error"), + } + + token, err := mockClient.GenerateToken(context.Background()) + + assert.Error(t, err, "Expected an error") + assert.Equal(t, "", token, "Expected empty token") + assert.EqualError(t, err, "mock error", "Unexpected error message") +} diff --git a/userdata_test.go b/userdata_test.go new file mode 100644 index 0000000..24ce1e6 --- /dev/null +++ b/userdata_test.go @@ -0,0 +1,46 @@ +package metadata + +import ( + "context" + "encoding/base64" + "errors" + "testing" + + "github.com/stretchr/testify/assert" +) + +type UserdataMockClient struct { + UserData string + GetUserDataError error +} + +func (m *UserdataMockClient) GetUserData(ctx context.Context) (string, error) { + if m.GetUserDataError != nil { + return "", m.GetUserDataError + } + return m.UserData, nil +} + +func TestGetUserData_Success(t *testing.T) { + mockClient := &UserdataMockClient{ + UserData: base64.StdEncoding.EncodeToString([]byte("mock-user-data")), + } + + userData, err := mockClient.GetUserData(context.Background()) + + assert.NoError(t, err, "Expected no error") + // Note "bW9jay11c2VyLWRhdGE=" is the encoded value + assert.Equal(t, "bW9jay11c2VyLWRhdGE=", userData, "Unexpected user data") +} + +func TestGetUserData_Error(t *testing.T) { + mockClient := &UserdataMockClient{ + GetUserDataError: errors.New("mock error"), + } + + userData, err := mockClient.GetUserData(context.Background()) + + assert.Error(t, err, "Expected an error") + assert.Equal(t, "", userData, "Expected empty user data") + assert.EqualError(t, err, "mock error", "Unexpected error message") +} diff --git a/watchers_test.go b/watchers_test.go new file mode 100644 index 0000000..b8c6552 --- /dev/null +++ b/watchers_test.go @@ -0,0 +1,15 @@ +package metadata + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestWatcherWithInterval(t *testing.T) { + config := watcherConfig{} + WatcherWithInterval(10 * time.Minute)(&config) + + assert.Equal(t, 10*time.Minute, config.Interval, "Unexpected interval duration") +}