Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
27 commits
Select commit Hold shift + click to select a range
b30e994
Parameterize SubCommandTest with configLevel
amoeba Dec 19, 2025
d53fe2e
Rework logic
amoeba Dec 19, 2025
01afc5b
Use sudo -E for system tests
amoeba Dec 19, 2025
5c1405a
See what tests fail with this
amoeba Dec 19, 2025
2340f19
revert changes that were mistakes
amoeba Dec 19, 2025
f587286
Remove my old fake user/system level tests
amoeba Dec 19, 2025
b38b9b3
Add test suite helpers so we can test on all platforms
amoeba Dec 19, 2025
9217c44
handle manifest-only drivers
amoeba Dec 19, 2025
ec0b84c
fix mistake
amoeba Dec 19, 2025
dae5016
Update install_test.go
amoeba Dec 19, 2025
5b5713f
attempt to fix tests
amoeba Dec 19, 2025
bff221b
whoops
amoeba Dec 19, 2025
d7792bb
Update install_test.go
amoeba Dec 19, 2025
410be3a
add user and system level test teardown
amoeba Dec 19, 2025
9bfe476
Fix test failures now that we can clean up
amoeba Dec 19, 2025
a5975be
Fix uninstall tests
amoeba Dec 19, 2025
7fa5be7
Tear down registry correctly
amoeba Dec 19, 2025
e69744f
Fix bug in sidecar removal
amoeba Dec 19, 2025
eda2623
Restore change in install_test.go
amoeba Dec 19, 2025
ed293e7
Factor out expectedDir logic
amoeba Dec 19, 2025
69eaa04
Fix not removing symlink to show off this pr
amoeba Dec 19, 2025
139ef61
Fix symlink behavior on all plats
amoeba Dec 19, 2025
1512cd5
whoops
amoeba Dec 19, 2025
b7a3289
Remove GetLocation wrapper, export ConfigLocation
amoeba Dec 23, 2025
643f102
Use suite.T().Setenv
amoeba Dec 23, 2025
5957bdf
fix windows
amoeba Dec 23, 2025
0336048
whoops
amoeba Dec 24, 2025
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
17 changes: 17 additions & 0 deletions .github/workflows/go.yml
Original file line number Diff line number Diff line change
Expand Up @@ -59,3 +59,20 @@ jobs:
# the file with `test_registry` also requires windows, so we can safely add this tag
# without it running on non-windows OSes
run: go test -v -tags test_registry ./...

# User and System level tests
- name: Run Tests (User)
run: go test -v ./...
env:
DBC_TEST_LEVEL_USER: 1
Comment on lines +63 to +67
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

do we need one of these with DBC_TEST_LEVEL_ENV: 1?

I also really don't like this personally, but can't think of a better option other than maybe using TestMain and adding explicit command line args that we look for instead? meh, I can live with this for now.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We don't, just running the tests normally (which we do above) tests DBC_TEST_LEVEL_ENV.

This was my third attempt at this and I dislike this approach the least. I can live with it too :)

- name: Run Tests (System, Unixlike)
# Run system tests with sudo on Unixlikes to replicate what users do
if: runner.os != 'Windows'
run: sudo -E go test -v ./...
env:
DBC_TEST_LEVEL_SYSTEM: 1
- name: Run Tests (System, Windows)
if: runner.os == 'Windows'
run: go test -v ./...
env:
DBC_TEST_LEVEL_SYSTEM: 1
146 changes: 46 additions & 100 deletions cmd/dbc/install_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,20 @@ import (
)

func (suite *SubcommandTestSuite) TestInstall() {
m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigEnv}.
m := InstallCmd{Driver: "test-driver-1", Level: suite.configLevel}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
out := suite.runCmd(m)

suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n",
"\nInstalled test-driver-1 1.1.0 to "+suite.tempdir+"\n", out)
if runtime.GOOS != "windows" {
suite.FileExists(filepath.Join(suite.tempdir, "test-driver-1.toml"))
}
"\nInstalled test-driver-1 1.1.0 to "+suite.Dir()+"\n", out)
suite.driverIsInstalled("test-driver-1", true)
}

func (suite *SubcommandTestSuite) TestInstallDriverNotFound() {
m := InstallCmd{Driver: "foo", Level: config.ConfigEnv}.
m := InstallCmd{Driver: "foo", Level: suite.configLevel}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
suite.validateOutput("Error: could not find driver: driver `foo` not found in driver registry index\r\n\r ", "", suite.runCmdErr(m))
suite.driverIsNotInstalled("test-driver-1")
}

func (suite *SubcommandTestSuite) TestInstallWithVersion() {
Expand All @@ -54,13 +53,14 @@ func (suite *SubcommandTestSuite) TestInstallWithVersion() {

for _, tt := range tests {
suite.Run(tt.driver, func() {
m := InstallCmd{Driver: tt.driver}.
m := InstallCmd{Driver: tt.driver, Level: suite.configLevel}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
out := suite.runCmd(m)
suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n",
"\nInstalled test-driver-1 "+tt.expectedVersion+" to "+suite.tempdir+"\n", out)

m = UninstallCmd{Driver: "test-driver-1"}.GetModelCustom(
suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n",
"\nInstalled test-driver-1 "+tt.expectedVersion+" to "+suite.Dir()+"\n", out)
suite.driverIsInstalled("test-driver-1", true)
m = UninstallCmd{Driver: "test-driver-1", Level: suite.configLevel}.GetModelCustom(
baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
suite.runCmd(m)
})
Expand Down Expand Up @@ -91,59 +91,9 @@ func (suite *SubcommandTestSuite) TestReinstallUpdateVersion() {
"test-driver-1.1/test-driver-1-not-valid.so.sig", "test-driver-1.toml"}, suite.getFilesInTempDir())
}

func (suite *SubcommandTestSuite) TestInstallUserFake() {
if runtime.GOOS == "windows" {
suite.T().Skip()
}

os.Unsetenv("ADBC_DRIVER_PATH")

m := InstallCmd{Driver: "test-driver-1"}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
installModel := m.(progressiveInstallModel)
suite.Equal(installModel.cfg.Level, config.ConfigUser)
installModel.cfg.Location = filepath.Join(suite.tempdir, "root", installModel.cfg.Location)
m = installModel // <- We need to reassign to make the change stick
suite.runCmd(m)
suite.FileExists(filepath.Join(installModel.cfg.Location, "test-driver-1.toml"))
}

func (suite *SubcommandTestSuite) TestInstallUserFakeExplicit() {
if runtime.GOOS == "windows" {
suite.T().Skip()
}

os.Unsetenv("ADBC_DRIVER_PATH")

m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigUser}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
installModel := m.(progressiveInstallModel)
suite.Equal(installModel.cfg.Level, config.ConfigUser)
installModel.cfg.Location = filepath.Join(suite.tempdir, "root", installModel.cfg.Location)
m = installModel // <- We need to reassign to make the change stick
suite.runCmd(m)
suite.FileExists(filepath.Join(installModel.cfg.Location, "test-driver-1.toml"))
}

func (suite *SubcommandTestSuite) TestInstallSystemFake() {
if runtime.GOOS == "windows" {
suite.T().Skip()
}

m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigSystem}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
installModel := m.(progressiveInstallModel)
suite.Equal(installModel.cfg.Level, config.ConfigSystem)
installModel.cfg.Location = filepath.Join(suite.tempdir, "root", installModel.cfg.Location)
m = installModel // <- We need to reassign to make the change stick
suite.runCmd(m)
suite.FileExists(filepath.Join(installModel.cfg.Location, "test-driver-1.toml"))
}

func (suite *SubcommandTestSuite) TestInstallVenv() {
os.Unsetenv("ADBC_DRIVER_PATH")
os.Setenv("VIRTUAL_ENV", suite.tempdir)
defer os.Unsetenv("VIRTUAL_ENV")
suite.T().Setenv("ADBC_DRIVER_PATH", "")
suite.T().Setenv("VIRTUAL_ENV", suite.tempdir)

m := InstallCmd{Driver: "test-driver-1"}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
Expand All @@ -158,9 +108,10 @@ func (suite *SubcommandTestSuite) TestInstallEnvironmentPrecedence() {
driver_path := filepath.Join(suite.tempdir, "driver_path")
venv_path := filepath.Join(suite.tempdir, "venv_path")
conda_path := filepath.Join(suite.tempdir, "conda_path")
os.Setenv("ADBC_DRIVER_PATH", driver_path)
os.Setenv("VIRTUAL_ENV", venv_path)
os.Setenv("CONDA_PREFIX", conda_path)

suite.T().Setenv("ADBC_DRIVER_PATH", driver_path)
suite.T().Setenv("VIRTUAL_ENV", venv_path)
suite.T().Setenv("CONDA_PREFIX", conda_path)

m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigEnv}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
Expand All @@ -170,59 +121,38 @@ func (suite *SubcommandTestSuite) TestInstallEnvironmentPrecedence() {
suite.NoFileExists(filepath.Join(venv_path, "test-driver-1.toml"))
suite.NoFileExists(filepath.Join(conda_path, "test-driver-1.toml"))

os.Unsetenv("ADBC_DRIVER_PATH")
suite.T().Setenv("ADBC_DRIVER_PATH", "")
m = InstallCmd{Driver: "test-driver-1", Level: config.ConfigEnv}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
suite.runCmd(m)
suite.FileExists(filepath.Join(venv_path, "etc", "adbc", "drivers", "test-driver-1.toml"))
suite.NoFileExists(filepath.Join(conda_path, "etc", "adbc", "drivers", "test-driver-1.toml"))

os.Unsetenv("VIRTUAL_ENV")
suite.T().Setenv("VIRTUAL_ENV", "")
m = InstallCmd{Driver: "test-driver-1", Level: config.ConfigEnv}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
suite.runCmd(m)
suite.FileExists(filepath.Join(conda_path, "etc", "adbc", "drivers", "test-driver-1.toml"))

os.Unsetenv("CONDA_PREFIX")
}

func (suite *SubcommandTestSuite) TestInstallCondaPrefix() {
os.Unsetenv("ADBC_DRIVER_PATH")
os.Setenv("CONDA_PREFIX", suite.tempdir)
defer os.Unsetenv("CONDA_PREFIX")
suite.T().Setenv("ADBC_DRIVER_PATH", "")
suite.T().Setenv("CONDA_PREFIX", suite.tempdir)

m := InstallCmd{Driver: "test-driver-1"}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n",
"\nInstalled test-driver-1 1.1.0 to "+filepath.Join(suite.tempdir, "etc", "adbc", "drivers")+"\n", suite.runCmd(m))
}

func (suite *SubcommandTestSuite) TestInstallUserFakeExplicitLevelOverrides() {
if runtime.GOOS == "windows" {
suite.T().Skip()
}

// If the user explicitly sets level, it should override ADBC_DRIVER_PATH
// which, when testing, is set to tempdir
m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigSystem}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
installModel := m.(progressiveInstallModel)
suite.Equal(installModel.cfg.Level, config.ConfigSystem)
installModel.cfg.Location = filepath.Join(suite.tempdir, "user", installModel.cfg.Location)
m = installModel // <- We need to reassign to make the change stick
suite.runCmd(m)
suite.FileExists(filepath.Join(installModel.cfg.Location, "test-driver-1.toml"))
}

func (suite *SubcommandTestSuite) TestInstallManifestOnlyDriver() {
m := InstallCmd{Driver: "test-driver-manifest-only"}.
m := InstallCmd{Driver: "test-driver-manifest-only", Level: suite.configLevel}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})

suite.validateOutput("\r[✓] searching\r\n[✓] downloading\r\n[✓] installing\r\n[✓] verifying signature\r\n",
"\nInstalled test-driver-manifest-only 1.0.0 to "+suite.tempdir+"\n"+
"\nInstalled test-driver-manifest-only 1.0.0 to "+suite.Dir()+"\n"+
"\nMust have libtest_driver installed to load this driver\n", suite.runCmd(m))
if runtime.GOOS != "windows" {
suite.FileExists(filepath.Join(suite.tempdir, "test-driver-manifest-only.toml"))
}
suite.driverIsInstalled("test-driver-manifest-only", false)
}

func (suite *SubcommandTestSuite) TestInstallDriverNoSignature() {
Expand All @@ -243,8 +173,7 @@ func (suite *SubcommandTestSuite) TestInstallDriverNoSignature() {
func (suite *SubcommandTestSuite) TestInstallGitignoreDefaultBehavior() {
driver_path := filepath.Join(suite.tempdir, "driver_path")
ignorePath := filepath.Join(driver_path, ".gitignore")
os.Setenv("ADBC_DRIVER_PATH", driver_path)
defer os.Unsetenv("ADBC_DRIVER_PATH")
suite.T().Setenv("ADBC_DRIVER_PATH", driver_path)

suite.NoFileExists(ignorePath)

Expand All @@ -258,8 +187,7 @@ func (suite *SubcommandTestSuite) TestInstallGitignoreDefaultBehavior() {
func (suite *SubcommandTestSuite) TestInstallGitignoreExisingDir() {
driver_path := filepath.Join(suite.tempdir, "driver_path")
ignorePath := filepath.Join(driver_path, ".gitignore")
os.Setenv("ADBC_DRIVER_PATH", driver_path)
defer os.Unsetenv("ADBC_DRIVER_PATH")
suite.T().Setenv("ADBC_DRIVER_PATH", driver_path)

// Create the directory before we install the driver
mkdirerr := os.MkdirAll(driver_path, 0o755)
Expand All @@ -282,8 +210,7 @@ func (suite *SubcommandTestSuite) TestInstallGitignoreExisingDir() {
func (suite *SubcommandTestSuite) TestInstallGitignorePreserveUserModified() {
driver_path := filepath.Join(suite.tempdir, "driver_path")
ignorePath := filepath.Join(driver_path, ".gitignore")
os.Setenv("ADBC_DRIVER_PATH", driver_path)
defer os.Unsetenv("ADBC_DRIVER_PATH")
suite.T().Setenv("ADBC_DRIVER_PATH", driver_path)

suite.NoFileExists(ignorePath)

Expand Down Expand Up @@ -316,3 +243,22 @@ func (suite *SubcommandTestSuite) TestInstallGitignorePreserveUserModified() {
}
suite.Equal(userContent, string(data))
}

func (suite *SubcommandTestSuite) TestInstallCreatesSymlinks() {
if runtime.GOOS == "windows" && (suite.configLevel == config.ConfigUser || suite.configLevel == config.ConfigSystem) {
suite.T().Skip("Symlinks aren't created on Windows for User and System config levels")
}

// Install a driver
m := InstallCmd{Driver: "test-driver-1", Level: suite.configLevel}.
GetModelCustom(baseModel{getDriverRegistry: getTestDriverRegistry, downloadPkg: downloadTestPkg})
_ = suite.runCmd(m)
suite.driverIsInstalled("test-driver-1", true)

// Verify symlink is in place in the parent dir and is actually a symlink
manifestPath := filepath.Join(suite.Dir(), "..", "test-driver-1.toml")
suite.FileExists(manifestPath)
info, err := os.Lstat(manifestPath)
suite.NoError(err)
suite.Equal(os.ModeSymlink, info.Mode()&os.ModeSymlink, "Expected test-driver-1.toml to be a symlink")
}
84 changes: 77 additions & 7 deletions cmd/dbc/subcommand_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@ import (

tea "github.com/charmbracelet/bubbletea"
"github.com/columnar-tech/dbc"
"github.com/columnar-tech/dbc/config"
"github.com/go-faster/yaml"
"github.com/stretchr/testify/suite"
)
Expand Down Expand Up @@ -83,22 +84,24 @@ type SubcommandTestSuite struct {
openBrowserFn func(string) error
fallbackDriverDocsUrl map[string]string
tempdir string

configLevel config.ConfigLevel
}

func (suite *SubcommandTestSuite) SetupSuite() {
suite.getDriverRegistryFn = getDriverRegistry
getDriverRegistry = getTestDriverRegistry
suite.openBrowserFn = openBrowserFunc
suite.fallbackDriverDocsUrl = fallbackDriverDocsUrl

if suite.configLevel == config.ConfigUnknown {
suite.configLevel = config.ConfigEnv
}
}

func (suite *SubcommandTestSuite) SetupTest() {
suite.tempdir = suite.T().TempDir()
suite.Require().NoError(os.Setenv("ADBC_DRIVER_PATH", suite.tempdir))
}

func (suite *SubcommandTestSuite) TearDownTest() {
suite.Require().NoError(os.Unsetenv("ADBC_DRIVER_PATH"))
suite.T().Setenv("ADBC_DRIVER_PATH", suite.tempdir)
}

func (suite *SubcommandTestSuite) TearDownSuite() {
Expand All @@ -120,6 +123,15 @@ func (suite *SubcommandTestSuite) getFilesInTempDir() []string {
return filelist
}

// Get the base directory for where drivers are installed. Use this instead of
// hardcoding checks to suite.tempdir to make tests support other config levels.
func (suite *SubcommandTestSuite) Dir() string {
if suite.configLevel == config.ConfigEnv {
return suite.tempdir
}
return suite.configLevel.ConfigLocation()
}

func (suite *SubcommandTestSuite) runCmdErr(m tea.Model) string {
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
Expand Down Expand Up @@ -171,6 +183,64 @@ func (suite *SubcommandTestSuite) validateOutput(expected, extra, actual string)
suite.Equal(terminalPrefix+expected+terminalSuffix+extra, actual)
}

func TestSubcommands(t *testing.T) {
suite.Run(t, new(SubcommandTestSuite))
// The SubcommandTestSuite is only run for ConfigEnv by default but is
// parametrized by configLevel so tests can be run for other levels. Tests must
// opt into this behavior by instantiating subcommands with `suite.configLevel`
// like:
//
// m := InstallCmd{Driver: "foo", Level: suite.configLevel}
// ^---- here
//
// and can opt out of this behavior by specifying it separately like:
//
// m := InstallCmd{Driver: "test-driver-1", Level: config.ConfigEnv}.
//
// When any level is explicitly requested, tests are only run for that level.
// i.e., to run tests for multiple levels, each level must be specified
// separately.
func TestSubcommandsEnv(t *testing.T) {
_, env := os.LookupEnv("DBC_TEST_LEVEL_ENV")
_, user := os.LookupEnv("DBC_TEST_LEVEL_USER")
_, system := os.LookupEnv("DBC_TEST_LEVEL_SYSTEM")

// Run if explicitly requested, or if no levels were requested (default
// behavior)
if env || (!user && !system) {
suite.Run(t, &SubcommandTestSuite{configLevel: config.ConfigEnv})
return
}
t.Skip("skipping tests for config level: ConfigEnv")
}

func TestSubcommandsUser(t *testing.T) {
if _, ok := os.LookupEnv("DBC_TEST_LEVEL_USER"); !ok {
t.Skip("skipping tests for config level: ConfigUser")
}
suite.Run(t, &SubcommandTestSuite{configLevel: config.ConfigUser})
}

func TestSubcommandsSystem(t *testing.T) {
if _, ok := os.LookupEnv("DBC_TEST_LEVEL_SYSTEM"); !ok {
t.Skip("skipping tests for config level: ConfigSystem")
}
suite.Run(t, &SubcommandTestSuite{configLevel: config.ConfigSystem})
}

func (suite *SubcommandTestSuite) driverIsInstalled(path string, checkShared bool) {
cfg := config.Get()[suite.configLevel]

driver, err := config.GetDriver(cfg, path)
suite.Require().NoError(err, "driver manifest should exist for driver `%s`", path)

if checkShared {
sharedPath := driver.Driver.Shared.Get(config.PlatformTuple())
suite.FileExists(sharedPath, "driver shared library should exist for driver `%s`", path)
}
}

func (suite *SubcommandTestSuite) driverIsNotInstalled(path string) {
cfg := config.Get()[suite.configLevel]

_, err := config.GetDriver(cfg, path)
suite.Require().Error(err, "driver manifest should not exist for driver `%s`", path)
}
Loading
Loading