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

chore: adds TUI tests #530

Merged
merged 4 commits into from
Mar 27, 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
1 change: 1 addition & 0 deletions src/pkg/bundle/deploy.go
Original file line number Diff line number Diff line change
Expand Up @@ -281,6 +281,7 @@ func (b *Bundle) loadChartOverrides(pkg types.Package, pkgVars map[string]string
return processed, nil
}

// PreDeployValidation validates the bundle before deployment
func (b *Bundle) PreDeployValidation() (string, string, string, error) {

// Check that provided oci source path is valid, and update it if it's missing the full path
Expand Down
2 changes: 1 addition & 1 deletion src/pkg/bundle/tarball.go
Original file line number Diff line number Diff line change
Expand Up @@ -301,7 +301,7 @@ func (tp *tarballBundleProvider) PublishBundle(bundle types.UDSBundle, remote *o
retries := 0

// reset retries if a desc was successful
copyOpts.PostCopy = func(_ context.Context, desc ocispec.Descriptor) error {
copyOpts.PostCopy = func(_ context.Context, _ ocispec.Descriptor) error {
retries = 0
return nil
}
Expand Down
7 changes: 7 additions & 0 deletions src/pkg/bundle/tui/deploy/model.go
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ type pkgState struct {
isRemote bool
}

// Model contains the state of the TUI
type Model struct {
bndlClient bndlClientShim
bundleYAML string
Expand Down Expand Up @@ -137,12 +138,14 @@ func InitModel(client bndlClientShim) Model {
}
}

// Init performs some action when BubbleTea starts up
func (m *Model) Init() tea.Cmd {
return func() tea.Msg {
return doPreDeploy
}
}

// Update updates the model based on the message received
func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
select {
case err := <-m.errChan:
Expand Down Expand Up @@ -247,6 +250,9 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
if tc, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil {
m.packages[m.pkgIdx].numComponents = tc
m.packages[m.pkgIdx].componentStatuses = make([]bool, tc)
if m.isRemoteBundle {
m.packages[m.pkgIdx].downloaded = true
}
}
case totalPackages:
if totalPkgs, err := strconv.Atoi(strings.Split(msg, ":")[1]); err == nil {
Expand Down Expand Up @@ -276,6 +282,7 @@ func (m *Model) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
return m, nil
}

// View returns the view for the TUI
func (m *Model) View() string {
if m.done {
// no errors, clear the controlled Program's output
Expand Down
114 changes: 114 additions & 0 deletions src/pkg/bundle/tui/deploy/model_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
package deploy

import (
"testing"

tea "github.com/charmbracelet/bubbletea"
"github.com/stretchr/testify/require"
)

func TestDeploy(t *testing.T) {
testPkgs := []pkgState{
{
name: "test-pkg",
numComponents: 1,
componentStatuses: []bool{true},
}, {
name: "test-pkg-2",
numComponents: 1,
componentStatuses: []bool{true},
},
}
initTestModel := func() *Model {

m := InitModel(nil)
m.validatingBundle = false
m.totalPkgs = 2
m.bundleName = "test-bundle"
m.logViewport.Width = 50
m.logViewport.Height = 50
m.bundleYAML = "fake bundle YAML"
return &m
}

t.Run("test deploy", func(t *testing.T) {
m := initTestModel()

// check pre-deploy view
view := m.View()
require.Contains(t, view, m.bundleYAML)
require.Contains(t, view, "Deploy this bundle? (y/n)")

// simulate pressing 'y' key to confirm deployment
m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{121}})
view = m.View()
require.Contains(t, view, "UDS Bundle: test-bundle")

// deploy first pkg in bundle with simulated components
m.Update("newPackage:test-pkg:0")
m.packages[m.pkgIdx].numComponents = 1
m.packages[m.pkgIdx].componentStatuses = []bool{true}
view = m.View()
require.Contains(t, view, "Deploying bundle package (1 / 2)")
require.Contains(t, view, "Package test-pkg deploying (1 / 1 components)")

// simulate package deployment completion
m.Update("complete:test-pkg")
//m.Update(deployTickMsg(time.Time{}))
view = m.View()
require.Contains(t, view, "Package test-pkg deployed")
require.NotContains(t, view, "Package test-pkg deploying")

// deploy second pkg in bundle with simulated components
m.Update("newPackage:test-pkg-2:1")
m.packages[m.pkgIdx].numComponents = 1
m.packages[m.pkgIdx].componentStatuses = []bool{true}
view = m.View()
require.Contains(t, view, "Deploying bundle package (2 / 2)")
require.Contains(t, view, "Package test-pkg-2 deploying (1 / 1 components)")

// simulate package deployment completion
m.Update("complete:test-pkg-2")
view = m.View()
require.Contains(t, view, "Package test-pkg-2 deployed")
require.NotContains(t, view, "Package test-pkg-2 deploying")
})

t.Run("test toggle log view", func(t *testing.T) {
m := initTestModel()

// simulate passing --confirm
m.inProgress = true
m.confirmed = true
m.packages = testPkgs

view := m.View()
require.Contains(t, view, "Package test-pkg deploying (1 / 1 components)")

// simulate pressing 'l' key to toggle logs
m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{108}})

view = m.View()
require.Contains(t, view, "test-pkg package logs")

// simulate pressing 'l' key to toggle logs
m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{108}})

view = m.View()
require.NotContains(t, view, "test-pkg package logs")
})

t.Run("test deploy cancel", func(t *testing.T) {
m := initTestModel()
view := m.View()
require.Contains(t, view, "Deploy this bundle? (y/n)")

// simulate pressing 'n' key to cancel deployment
m.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []int32{110}})
view = m.View()

// model's view is cleared after canceling deployment
require.Equal(t, view, "")
})

}
11 changes: 9 additions & 2 deletions src/test/e2e/commands_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,13 @@ func deploy(t *testing.T, tarballPath string) (stdout string, stderr string) {
return stdout, stderr
}

func deployWithTUI(t *testing.T, source string) (stdout string, stderr string) {
cmd := strings.Split(fmt.Sprintf("deploy %s --confirm", source), " ")
stdout, stderr, err := e2e.UDS(cmd...)
require.NoError(t, err)
return stdout, stderr
}

func runCmd(t *testing.T, input string) (stdout string, stderr string) {
cmd := strings.Split(input, " ")
stdout, stderr, err := e2e.UDS(cmd...)
Expand All @@ -124,8 +131,8 @@ func deployResumeFlag(t *testing.T, tarballPath string) {
require.NoError(t, err)
}

func remove(t *testing.T, tarballPath string) {
cmd := strings.Split(fmt.Sprintf("remove %s --confirm --insecure", tarballPath), " ")
func remove(t *testing.T, source string) {
cmd := strings.Split(fmt.Sprintf("remove %s --confirm --insecure", source), " ")
_, _, err := e2e.UDS(cmd...)
require.NoError(t, err)
}
Expand Down
58 changes: 58 additions & 0 deletions src/test/e2e/tui_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
package test

import (
"fmt"
"path/filepath"
"testing"

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

func TestBundleDeploy(t *testing.T) {
deployZarfInit(t)
e2e.CreateZarfPkg(t, "src/test/packages/podinfo", false)

source := "ghcr.io/defenseunicorns/packages/uds-cli/test/publish/ghcr-test:0.0.1"
stdout, _ := deployWithTUI(t, source)
require.Contains(t, stdout, "Validating bundle")
require.Contains(t, stdout, "UDS Bundle: ghcr-test")
require.Contains(t, stdout, "Verifying podinfo package (0%)")
require.Contains(t, stdout, "Downloading podinfo package (0%)")
require.Contains(t, stdout, "Deploying podinfo package (1 / 1 components)")
require.Contains(t, stdout, "Deploying nginx package (1 / 1 components)")
require.Contains(t, stdout, "✔ Package podinfo deployed")
require.Contains(t, stdout, "✔ Package nginx deployed")
require.Contains(t, stdout, "Verifying nginx package (0%)")
require.Contains(t, stdout, "Downloading nginx package (0%)")
require.Contains(t, stdout, "✨ Bundle ghcr-test deployed successfully")
remove(t, source)
}

func TestBundleDeployWithBadSource(t *testing.T) {
deployZarfInit(t)
e2e.CreateZarfPkg(t, "src/test/packages/podinfo", false)

source := "a.bad.source:0.0.1"
stdout, _ := deployWithTUI(t, source)
require.Contains(t, stdout, "❌ Error deploying bundle: a.bad.source:0.0.1: not found")
}

func TestBundleDeployWithBadPkg(t *testing.T) {
deployZarfInit(t)

// deploy a good pkg
source := "ghcr.io/defenseunicorns/packages/uds-cli/test/publish/ghcr-test:0.0.1 --packages=nginx"
stdout, _ := deployWithTUI(t, source)
require.Contains(t, stdout, "✨ Bundle ghcr-test deployed successfully")

// attempt to deploy a conflicting pkg
e2e.CreateZarfPkg(t, "src/test/packages/gitrepo", false)
bundleDir := "src/test/bundles/05-gitrepo"
bundlePath := filepath.Join(bundleDir, fmt.Sprintf("uds-bundle-gitrepo-%s-0.0.1.tar.zst", e2e.Arch))

createLocal(t, bundleDir, e2e.Arch)
stdout, _ = deployWithTUI(t, bundlePath)
require.Contains(t, stdout, "❌ Error deploying bundle: unable to deploy component \"nginx-remote\": unable to install helm chart")
require.Contains(t, stdout, "Run uds logs to view deployment logs")
remove(t, source)
}
Loading