Skip to content

Commit

Permalink
Add end-to-end test validating cloud-init functionality
Browse files Browse the repository at this point in the history
  • Loading branch information
EduardGomezEscandell committed Feb 19, 2024
1 parent 2429ea7 commit ae023ab
Show file tree
Hide file tree
Showing 7 changed files with 139 additions and 7 deletions.
115 changes: 115 additions & 0 deletions end-to-end/cloud_init_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
package endtoend_test

import (
"context"
"os"
"path/filepath"
"testing"
"time"

landscapeapi "github.com/canonical/landscape-hostagent-api"
"github.com/canonical/ubuntu-pro-for-wsl/common/golden"
"github.com/stretchr/testify/require"
wsl "github.com/ubuntu/gowsl"
)

func TestCloudInitIntegration(t *testing.T) {
currentFuncName := t.Name()

ctx, cancel := context.WithCancel(context.Background())
defer cancel()

testSetup(t)
defer logWindowsAgentOnError(t)

landscape := NewLandscape(t, ctx)
writeUbuntuProRegistry(t, "LandscapeConfig", landscape.ClientConfig)

go landscape.Serve()
defer landscape.LogOnError(t)
defer landscape.Stop()

hostname, err := os.Hostname()
require.NoError(t, err, "Setup: could not test machine's hostname")

proToken := os.Getenv(proTokenEnv)
require.NotEmptyf(t, proToken, "Setup: environment variable %q should contain a valid pro token, but is empty", proTokenEnv)
writeUbuntuProRegistry(t, "UbuntuProToken", proToken)

cleanup := startAgent(t, ctx, currentFuncName)
defer cleanup()

info := landscape.RequireReceivedInfo(t, proToken, nil, hostname)

out, err := os.ReadFile(filepath.Join(golden.TestFixturePath(t), "user-data.yaml"))
require.NoError(t, err, "Setup: could not read cloud-init file")
cloudInitUserData := string(out)

err = landscape.service.SendCommand(ctx, info.UID, &landscapeapi.Command{
Cmd: &landscapeapi.Command_Install_{
Install: &landscapeapi.Command_Install{
Id: referenceDistro,
Cloudinit: &cloudInitUserData,
},
},
})
require.NoError(t, err, "Setup: could not send install command")

distro := wsl.NewDistro(ctx, referenceDistro)

//nolint:errcheck // Nothing we can do about it
defer distro.Unregister()

require.Eventually(t, func() bool {
ok, err := distro.IsRegistered()
if err != nil {
t.Logf("could not determine if distro is registered: %v", err)
return false
}
return ok
}, time.Minute, time.Second, "Distro should have been registered")

defer logWslProServiceOnError(t, ctx, distro)

runCommand(t, ctx, time.Minute, distro, "cloud-init status --wait")

require.Eventually(t, func() bool {
attached, err := distroIsProAttached(t, ctx, distro)
if err != nil {
t.Logf("could not determine if distro is attached: %v", err)
return false
}
return attached
}, 10*time.Second, time.Second, "distro should have been Pro attached")

userName := runCommand(t, ctx, 10*time.Second, distro, "whoami")
require.Equal(t, "testuser", userName, "cloud-init should have configured the default user")

landscape.RequireReceivedInfo(t, proToken, []wsl.Distro{distro}, hostname)
landscape.RequireUninstallCommand(t, ctx, distro, info)
}

//nolint:revive // t always goes before ctx
func runCommand(t *testing.T, ctx context.Context, timeout time.Duration, distro wsl.Distro, comand string) string {
t.Helper()

ctx, cancel := context.WithTimeout(ctx, timeout)
defer cancel()

out, err := distro.Command(ctx, comand).CombinedOutput()
if err == nil {
return string(out)
}

// We check the context to see if it was a timeout.
// This makes the error message easier to understand.

select {
case <-ctx.Done():
require.Fail(t, "Timed out waiting for cloud-init to finish")
default:
}

require.NoError(t, err, "could not determine if cloud-init is done: %s. Output: %s", out, out)
return ""
}
11 changes: 7 additions & 4 deletions end-to-end/landscape_utils_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,7 @@ func (l landscape) Stop() {
}

// RequireReceivedInfo checks that a connection to Landscape was made and the proper information was sent.
func (l landscape) RequireReceivedInfo(t *testing.T, wantToken string, wantDistro gowsl.Distro, wantHostname string) landscapemockservice.HostInfo {
func (l landscape) RequireReceivedInfo(t *testing.T, wantToken string, wantDistros []gowsl.Distro, wantHostname string) landscapemockservice.HostInfo {
t.Helper()

require.Eventually(t, func() bool {
Expand All @@ -122,9 +122,12 @@ func (l landscape) RequireReceivedInfo(t *testing.T, wantToken string, wantDistr
// Validate token
require.Equal(t, wantToken, info.Token, "Landscape did not receive the right pro token")

// Validate distro
require.Len(t, info.Instances, 1, "Landscape did not receive the right number of distros")
require.Equal(t, wantDistro.Name(), info.Instances[0].ID, "Landscape did not receive the right distro name from the agent")
// Validate distros
gotDistros := make([]string, 0)
for _, instance := range info.Instances {
gotDistros = append(gotDistros, instance.ID)
}
require.ElementsMatch(t, wantDistros, gotDistros, "Landscape did not receive the right distros")

// Validate hostname
require.Equal(t, wantHostname, info.Hostname, "Landscape did not receive the right hostname from the agent")
Expand Down
2 changes: 1 addition & 1 deletion end-to-end/manual_token_input_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,7 +95,7 @@ func TestManualTokenInput(t *testing.T) {
return attached
}, maxTimeout, time.Second, "distro should have been Pro attached")

info := landscape.RequireReceivedInfo(t, os.Getenv(proTokenEnv), d, hostname)
info := landscape.RequireReceivedInfo(t, os.Getenv(proTokenEnv), []wsl.Distro{d}, hostname)
landscape.RequireUninstallCommand(t, ctx, d, info)
})
}
Expand Down
2 changes: 1 addition & 1 deletion end-to-end/organization_token_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -100,7 +100,7 @@ func TestOrganizationProvidedToken(t *testing.T) {
return attached
}, maxTimeout, time.Second, "distro should have been Pro attached")

info := landscape.RequireReceivedInfo(t, proToken, d, hostname)
info := landscape.RequireReceivedInfo(t, proToken, []wsl.Distro{d}, hostname)
landscape.RequireUninstallCommand(t, ctx, d, info)
})
}
Expand Down
2 changes: 1 addition & 1 deletion end-to-end/purchase_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -154,7 +154,7 @@ func TestPurchase(t *testing.T) {
return attached
}, maxTimeout, time.Second, "distro should have been Pro attached")

landscape.RequireReceivedInfo(t, token, d, hostname)
landscape.RequireReceivedInfo(t, token, []wsl.Distro{d}, hostname)
// Skipping because we know it to be broken
// See https://warthogs.atlassian.net/browse/UDENG-1810
//
Expand Down
13 changes: 13 additions & 0 deletions end-to-end/testdata/TestCloudInitIntegration/user-data.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#cloud-config
users:
- name: testuser
gecos: Test User
sudo: ALL=(ALL) NOPASSWD:ALL
groups: [adm,dialout,cdrom,floppy,sudo,audio,dip,video,plugdev,users,netdev]
shell: /bin/bash
write_files:
- path: /etc/wsl.conf
append: true
content: |
[user]
default=testuser
1 change: 1 addition & 0 deletions gui/packages/ubuntupro/end_to_end/end_to_end_test.dart
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ void main(List<String> args) {

const testCases = {
'TestOrganizationProvidedToken': testOrganizationProvidedToken,
'TestCloudInitIntegration': testOrganizationProvidedToken,
'TestManualTokenInput': testManualTokenInput,
'TestPurchase': testPurchase,
};
Expand Down

0 comments on commit ae023ab

Please sign in to comment.