Skip to content

Commit

Permalink
(testing): refactor + add initial set of unit tests (#48)
Browse files Browse the repository at this point in the history
* large refactor to prep for easier unit tests

Signed-off-by: everettraven <everettraven@gmail.com>

* add initial set of unit tests

Signed-off-by: everettraven <everettraven@gmail.com>

* fix linter error

Signed-off-by: everettraven <everettraven@gmail.com>

---------

Signed-off-by: everettraven <everettraven@gmail.com>
  • Loading branch information
everettraven authored Jan 16, 2024
1 parent 83d62e6 commit 58033a1
Show file tree
Hide file tree
Showing 28 changed files with 1,051 additions and 512 deletions.
4 changes: 3 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,4 @@
buoy
dist/
dist/

cover.out
2 changes: 1 addition & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -23,5 +23,5 @@ GOLANGCI_LINT_ARGS ?=
lint: $(GOLANGCI_LINT)
$(GOLANGCI_LINT) run $(GOLANGCI_LINT_ARGS)
unit:
go test ./...
go test ./... -coverprofile=cover.out -covermode=atomic

2 changes: 2 additions & 0 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ require (
github.com/common-nighthawk/go-figure v0.0.0-20210622060536-734e95fb86be
github.com/sahilm/fuzzy v0.1.0
github.com/spf13/cobra v1.7.0
github.com/stretchr/testify v1.8.2
github.com/tidwall/gjson v1.17.0
k8s.io/api v0.28.1
k8s.io/apimachinery v0.28.1
Expand All @@ -21,6 +22,7 @@ require (
require (
github.com/atotto/clipboard v0.1.4 // indirect
github.com/dlclark/regexp2 v1.4.0 // indirect
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/tidwall/match v1.1.1 // indirect
github.com/tidwall/pretty v1.2.0 // indirect
)
Expand Down
27 changes: 23 additions & 4 deletions internal/cli/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,8 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/everettraven/buoy/pkg/charm/models"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/everettraven/buoy/pkg/paneler"
"github.com/everettraven/buoy/pkg/factories/datastream"
"github.com/everettraven/buoy/pkg/factories/panel"
"github.com/everettraven/buoy/pkg/types"
"github.com/spf13/cobra"
"sigs.k8s.io/controller-runtime/pkg/client/config"
Expand All @@ -38,6 +39,10 @@ func init() {
rootCommand.Flags().String("theme", styles.DefaultThemePath, "path to theme file")
}

type ErrorSetter interface {
SetError(err error)
}

func run(path string, themePath string) error {
var raw []byte
var ext string
Expand Down Expand Up @@ -76,21 +81,35 @@ func run(path string, themePath string) error {
log.Fatalf("loading theme: %s", err)
}

p := panel.NewPanelFactory(theme)

cfg := config.GetConfigOrDie()
p, err := paneler.NewDefaultPaneler(cfg, theme)
df, err := datastream.NewDatastreamFactory(cfg)
if err != nil {
log.Fatalf("configuring paneler: %s", err)
log.Fatalf("configuring datastream factory: %s", err)
}

panelModels := []tea.Model{}
for _, panel := range dash.Panels {
mod, err := p.Model(panel)
mod, err := p.ModelForPanel(panel)
if err != nil {
log.Fatalf("getting model for panel %q: %s", panel.Name, err)
}
panelModels = append(panelModels, mod)
}

for _, panel := range panelModels {
dataStream, err := df.DatastreamForModel(panel)
if err != nil {
if errSetter, ok := panel.(ErrorSetter); ok {
errSetter.SetError(err)
} else {
log.Fatalf("getting datastream for model: %s", err)
}
}
go dataStream.Run(make(<-chan struct{}))
}

m := models.NewDashboard(models.DefaultDashboardKeys, theme, panelModels...)
if _, err := tea.NewProgram(m, tea.WithAltScreen()).Run(); err != nil {
fmt.Println("Error running program:", err)
Expand Down
4 changes: 2 additions & 2 deletions pkg/charm/models/dashboard.go
Original file line number Diff line number Diff line change
Expand Up @@ -53,10 +53,10 @@ type Dashboard struct {
width int
help help.Model
keys DashboardKeyMap
theme *styles.Theme
theme styles.Theme
}

func NewDashboard(keys DashboardKeyMap, theme *styles.Theme, panels ...tea.Model) *Dashboard {
func NewDashboard(keys DashboardKeyMap, theme styles.Theme, panels ...tea.Model) *Dashboard {
tabs := []Tab{}
for _, panel := range panels {
if namer, ok := panel.(Namer); ok {
Expand Down
36 changes: 36 additions & 0 deletions pkg/charm/models/dashboard_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
package models

import (
"testing"

"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/everettraven/buoy/pkg/charm/models/panels"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/everettraven/buoy/pkg/types"
"github.com/stretchr/testify/assert"
)

func TestDashboardUpdate(t *testing.T) {
panels := []tea.Model{
panels.NewItem(types.Item{
PanelBase: types.PanelBase{
Name: "test",
},
}, viewport.New(10, 10), styles.Theme{}),
}

d := NewDashboard(DefaultDashboardKeys, styles.Theme{}, panels...)

t.Log("WindowSizeUpdate")
d.Update(tea.WindowSizeMsg{Width: 50, Height: 50})
assert.Equal(t, 50, d.width)

t.Log("toggle detailed help")
d.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("ctrl+h")})
assert.True(t, d.help.ShowAll)

t.Log("quit the program")
_, cmd := d.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("q")})
assert.Equal(t, cmd(), tea.Quit())
}
28 changes: 24 additions & 4 deletions pkg/charm/models/panels/item.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,26 @@ import (

"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/everettraven/buoy/pkg/types"
)

// Item is a tea.Model implementation
// that represents an item panel
type Item struct {
viewport viewport.Model
name string
mutex *sync.Mutex
item types.Item
theme styles.Theme
err error
}

func NewItem(name string, viewport viewport.Model) *Item {
func NewItem(item types.Item, viewport viewport.Model, theme styles.Theme) *Item {
return &Item{
viewport: viewport,
name: name,
mutex: &sync.Mutex{},
item: item,
theme: theme,
}
}

Expand All @@ -37,6 +42,9 @@ func (m *Item) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (m *Item) View() string {
if m.err != nil {
return m.err.Error()
}
return m.viewport.View()
}

Expand All @@ -47,5 +55,17 @@ func (m *Item) SetContent(content string) {
}

func (m *Item) Name() string {
return m.name
return m.item.Name
}

func (m *Item) ItemDefinition() types.Item {
return m.item
}

func (m *Item) Theme() styles.Theme {
return m.theme
}

func (m *Item) SetError(err error) {
m.err = err
}
32 changes: 32 additions & 0 deletions pkg/charm/models/panels/item_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
package panels

import (
"errors"
"testing"

"github.com/charmbracelet/bubbles/viewport"
tea "github.com/charmbracelet/bubbletea"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/everettraven/buoy/pkg/types"
"github.com/stretchr/testify/assert"
)

func TestItemUpdate(t *testing.T) {
item := NewItem(types.Item{}, viewport.New(10, 10), styles.Theme{})
item.Update(tea.WindowSizeMsg{Width: 50, Height: 50})
assert.Equal(t, 50, item.viewport.Width)
assert.Equal(t, 25, item.viewport.Height)
}

func TestItemViewWithError(t *testing.T) {
item := NewItem(types.Item{}, viewport.New(10, 10), styles.Theme{})
err := errors.New("some error")
item.SetError(err)
assert.Equal(t, err.Error(), item.View())
}

func TestViewWithContent(t *testing.T) {
item := NewItem(types.Item{}, viewport.New(50, 50), styles.Theme{})
item.SetContent("some content")
assert.Contains(t, item.View(), "some content")
}
24 changes: 19 additions & 5 deletions pkg/charm/models/panels/logs.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import (
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/everettraven/buoy/pkg/types"
"github.com/muesli/reflow/wrap"
"github.com/sahilm/fuzzy"
)
Expand Down Expand Up @@ -65,25 +66,26 @@ const modeSearched = "searched"
type Logs struct {
viewport viewport.Model
searchbar textinput.Model
name string
mutex *sync.Mutex
content string
contentUpdated bool
mode string
keys LogsKeyMap
strictSearch bool
theme *styles.Theme
theme styles.Theme
log *types.Logs
err error
}

func NewLogs(keys LogsKeyMap, name string, theme *styles.Theme) *Logs {
func NewLogs(keys LogsKeyMap, log *types.Logs, theme styles.Theme) *Logs {
searchbar := textinput.New()
searchbar.Prompt = "> "
searchbar.Placeholder = "search term"
vp := viewport.New(10, 10)
return &Logs{
viewport: vp,
searchbar: searchbar,
name: name,
log: log,
mutex: &sync.Mutex{},
content: "",
mode: modeLogs,
Expand Down Expand Up @@ -149,6 +151,10 @@ func (m *Logs) Update(msg tea.Msg) (tea.Model, tea.Cmd) {
}

func (m *Logs) View() string {
if m.err != nil {
return m.err.Error()
}

searchMode := "fuzzy"
if m.strictSearch {
searchMode = "strict"
Expand Down Expand Up @@ -184,7 +190,15 @@ func (m *Logs) AddContent(content string) {
}

func (m *Logs) Name() string {
return m.name
return m.log.Name
}

func (m *Logs) LogDefinition() *types.Logs {
return m.log
}

func (m *Logs) SetError(err error) {
m.err = err
}

// searchLogs searches the logs for the term in the searchbar
Expand Down
89 changes: 89 additions & 0 deletions pkg/charm/models/panels/logs_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
package panels

import (
"errors"
"testing"

tea "github.com/charmbracelet/bubbletea"
"github.com/everettraven/buoy/pkg/charm/styles"
"github.com/stretchr/testify/assert"
)

func TestEnterSearchMode(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("/")})
assert.Equal(t, logs.mode, modeSearching)
}

func TestExecuteSearch(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("/")})
logs.Update(tea.KeyMsg{Type: tea.KeyEnter})
assert.Equal(t, logs.mode, modeSearched)
}

func TestExitSearchMode(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.mode = modeSearching
logs.searchbar.Focus()
logs.Update(tea.KeyMsg{Type: tea.KeyEsc})
assert.Equal(t, logs.mode, modeLogs)
assert.False(t, logs.searchbar.Focused())

logs.mode = modeSearched
logs.searchbar.Focus()
logs.Update(tea.KeyMsg{Type: tea.KeyEsc})
assert.Equal(t, logs.mode, modeLogs)
assert.False(t, logs.searchbar.Focused())
}

func TestSearchModeToggle(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.Update(tea.KeyMsg{Type: tea.KeyRunes, Runes: []rune("/")})
logs.Update(tea.KeyMsg{Type: tea.KeyCtrlS})
assert.True(t, logs.strictSearch)
logs.Update(tea.KeyMsg{Type: tea.KeyCtrlS})
assert.False(t, logs.strictSearch)
}

func TestSearchLogs(t *testing.T) {
t.Log("strict search")
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.strictSearch = true
logs.content = "some log line\nlog line with a search term\n"
logs.viewport.Width = 50
logs.searchbar.SetValue("search")
match := logs.searchLogs()
assert.Equal(t, "log line with a search term\n", match)

t.Log("fuzzy search")
logs.searchbar.SetValue("sll")
logs.strictSearch = false
match = logs.searchLogs()
assert.Equal(t, "some log line\n", match)
}

func TestLogsWindowSizeUpdate(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.Update(tea.WindowSizeMsg{Width: 100, Height: 100})
assert.Equal(t, logs.viewport.Width, 100)
assert.Equal(t, logs.viewport.Height, 50)
}

func TestLogsAddContent(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
logs.AddContent("some log line\n")
assert.Equal(t, "\nsome log line\n", logs.content)
assert.True(t, logs.contentUpdated)

logs.Update(tea.KeyMsg{Type: tea.KeyDown})
assert.False(t, logs.contentUpdated)
}

func TestLogsViewWithError(t *testing.T) {
logs := NewLogs(DefaultLogsKeys, nil, styles.Theme{})
err := errors.New("some error")
logs.SetError(err)
assert.Equal(t, err, logs.err)
assert.Equal(t, err.Error(), logs.View())
}
Loading

0 comments on commit 58033a1

Please sign in to comment.