Skip to content

Commit 38d9619

Browse files
test(integration): add brew integration tests for live system ops
Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
1 parent 9fdf4b5 commit 38d9619

1 file changed

Lines changed: 220 additions & 0 deletions

File tree

test/integration/brew_ops_test.go

Lines changed: 220 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,220 @@
1+
//go:build integration
2+
3+
package integration
4+
5+
import (
6+
"testing"
7+
8+
"github.com/openbootdotdev/openboot/internal/brew"
9+
"github.com/stretchr/testify/assert"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
func TestIntegration_Brew_IsInstalled(t *testing.T) {
14+
// Given: a macOS machine running these integration tests
15+
// When: we check if brew is installed
16+
result := brew.IsInstalled()
17+
18+
// Then: brew should be present (required for integration tests to be meaningful)
19+
assert.True(t, result, "brew must be installed to run integration tests")
20+
}
21+
22+
func TestIntegration_Brew_GetInstalledPackages(t *testing.T) {
23+
// Given: brew is installed
24+
require.True(t, brew.IsInstalled(), "brew must be installed")
25+
26+
// When: we fetch installed packages
27+
formulae, casks, err := brew.GetInstalledPackages()
28+
29+
// Then: both maps should be valid and non-nil
30+
require.NoError(t, err)
31+
assert.NotNil(t, formulae)
32+
assert.NotNil(t, casks)
33+
for name := range formulae {
34+
assert.NotEmpty(t, name, "formula name should not be empty")
35+
assert.NotContains(t, name, "\n", "formula name should not contain newlines")
36+
}
37+
for name := range casks {
38+
assert.NotEmpty(t, name, "cask name should not be empty")
39+
}
40+
t.Logf("Found %d formulae, %d casks", len(formulae), len(casks))
41+
}
42+
43+
func TestIntegration_Brew_ListOutdated(t *testing.T) {
44+
if testing.Short() {
45+
t.Skip("skipping ListOutdated in short mode")
46+
}
47+
48+
// Given: brew is installed
49+
require.True(t, brew.IsInstalled(), "brew must be installed")
50+
51+
// When: we list outdated packages
52+
outdated, err := brew.ListOutdated()
53+
54+
// Then: no error; result is a valid (possibly empty) slice
55+
require.NoError(t, err)
56+
assert.NotNil(t, outdated)
57+
for _, pkg := range outdated {
58+
assert.NotEmpty(t, pkg.Name, "outdated package name should not be empty")
59+
assert.NotEmpty(t, pkg.Latest, "outdated package latest version should not be empty")
60+
}
61+
t.Logf("Found %d outdated packages", len(outdated))
62+
}
63+
64+
func TestIntegration_Brew_DoctorDiagnose(t *testing.T) {
65+
if testing.Short() {
66+
t.Skip("skipping DoctorDiagnose in short mode")
67+
}
68+
69+
// Given: brew is installed
70+
require.True(t, brew.IsInstalled(), "brew must be installed")
71+
72+
// When: we run brew doctor through the package
73+
suggestions, err := brew.DoctorDiagnose()
74+
75+
// Then: command succeeds; suggestions is a valid (possibly nil) slice
76+
require.NoError(t, err)
77+
if len(suggestions) > 0 {
78+
for _, s := range suggestions {
79+
assert.NotEmpty(t, s, "each suggestion should be non-empty")
80+
assert.Contains(t, s, "Run:", "suggestions should be actionable commands")
81+
}
82+
t.Logf("Doctor found %d suggestions", len(suggestions))
83+
} else {
84+
t.Log("brew doctor: system is ready to brew")
85+
}
86+
}
87+
88+
func TestIntegration_Brew_CheckDiskSpace(t *testing.T) {
89+
// Given: running on macOS
90+
// When: we check available disk space
91+
gb, err := brew.CheckDiskSpace()
92+
93+
// Then: should return a positive number without error
94+
require.NoError(t, err)
95+
assert.Greater(t, gb, 0.0, "available disk space should be positive")
96+
t.Logf("Available disk space: %.2f GB", gb)
97+
}
98+
99+
func TestIntegration_Brew_CheckNetwork(t *testing.T) {
100+
if testing.Short() {
101+
t.Skip("skipping network check in short mode")
102+
}
103+
104+
// Given: machine has internet access
105+
// When: we check connectivity to required GitHub hosts
106+
err := brew.CheckNetwork()
107+
108+
// Then: both github.com and raw.githubusercontent.com are reachable
109+
assert.NoError(t, err, "network check should pass with internet access")
110+
}
111+
112+
func TestIntegration_Brew_CheckNetwork_HostsReachable(t *testing.T) {
113+
if testing.Short() {
114+
t.Skip("skipping network host check in short mode")
115+
}
116+
117+
// Given: CheckNetwork is expected to reach exactly two hosts
118+
// When: we call it on a machine with internet
119+
err := brew.CheckNetwork()
120+
121+
// Then: no port-connection errors
122+
if err != nil {
123+
t.Logf("Network check failed (expected if offline): %v", err)
124+
t.Skip("machine appears to be offline")
125+
}
126+
}
127+
128+
func TestIntegration_Brew_Update_DryRun(t *testing.T) {
129+
// Given: brew is installed
130+
require.True(t, brew.IsInstalled(), "brew must be installed")
131+
132+
// When: we run Update in dry-run mode
133+
err := brew.Update(true)
134+
135+
// Then: no error and nothing is actually updated
136+
assert.NoError(t, err)
137+
}
138+
139+
func TestIntegration_Brew_Install_DryRun(t *testing.T) {
140+
// Given: brew is installed
141+
require.True(t, brew.IsInstalled(), "brew must be installed")
142+
143+
// When: we call Install with dry-run for known packages
144+
err := brew.Install([]string{"git", "curl"}, true)
145+
146+
// Then: no error, nothing installed
147+
assert.NoError(t, err)
148+
}
149+
150+
func TestIntegration_Brew_InstallCask_DryRun(t *testing.T) {
151+
// Given: brew is installed
152+
require.True(t, brew.IsInstalled(), "brew must be installed")
153+
154+
// When: we call InstallCask with dry-run
155+
err := brew.InstallCask([]string{"firefox"}, true)
156+
157+
// Then: no error, nothing installed
158+
assert.NoError(t, err)
159+
}
160+
161+
func TestIntegration_Brew_InstallTaps_DryRun(t *testing.T) {
162+
// Given: brew is installed
163+
require.True(t, brew.IsInstalled(), "brew must be installed")
164+
165+
// When: we call InstallTaps with dry-run
166+
err := brew.InstallTaps([]string{"homebrew/cask-fonts"}, true)
167+
168+
// Then: no error, nothing tapped
169+
assert.NoError(t, err)
170+
}
171+
172+
func TestIntegration_Brew_InstallWithProgress_DryRun(t *testing.T) {
173+
// Given: brew is installed
174+
require.True(t, brew.IsInstalled(), "brew must be installed")
175+
176+
// When: we call InstallWithProgress with dry-run
177+
formulae, casks, err := brew.InstallWithProgress([]string{"git"}, []string{"firefox"}, true)
178+
179+
// Then: no error; dry-run returns empty slices
180+
assert.NoError(t, err)
181+
assert.Empty(t, formulae)
182+
assert.Empty(t, casks)
183+
}
184+
185+
func TestIntegration_Brew_Uninstall_DryRun(t *testing.T) {
186+
// Given: brew is installed
187+
require.True(t, brew.IsInstalled(), "brew must be installed")
188+
189+
// When: we call Uninstall with dry-run for a package that may or may not be installed
190+
err := brew.Uninstall([]string{"wget"}, true)
191+
192+
// Then: no error (dry-run never touches the system)
193+
assert.NoError(t, err)
194+
}
195+
196+
func TestIntegration_Brew_UninstallCask_DryRun(t *testing.T) {
197+
// Given: brew is installed
198+
require.True(t, brew.IsInstalled(), "brew must be installed")
199+
200+
// When: we call UninstallCask with dry-run
201+
err := brew.UninstallCask([]string{"firefox"}, true)
202+
203+
// Then: no error
204+
assert.NoError(t, err)
205+
}
206+
207+
func TestIntegration_Brew_GetInstalledPackages_Consistency(t *testing.T) {
208+
// Given: brew is installed
209+
require.True(t, brew.IsInstalled(), "brew must be installed")
210+
211+
// When: we call GetInstalledPackages twice in a row
212+
formulae1, casks1, err1 := brew.GetInstalledPackages()
213+
formulae2, casks2, err2 := brew.GetInstalledPackages()
214+
215+
// Then: both calls return the same result (no concurrent modification)
216+
require.NoError(t, err1)
217+
require.NoError(t, err2)
218+
assert.Equal(t, len(formulae1), len(formulae2), "formulae count should be stable")
219+
assert.Equal(t, len(casks1), len(casks2), "casks count should be stable")
220+
}

0 commit comments

Comments
 (0)