diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 25164a53..550acee4 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -140,9 +140,9 @@ jobs: with: go-version: ${{ matrix.go-version }} - name: build go - run: go build ./cmd/app/main.go + run: go build ./cmd/app - name: build noui (headless) - run: CGO_ENABLED=0 go build -tags=noui -o console-headless ./cmd/app/main.go + run: CGO_ENABLED=0 go build -tags=noui -o console-headless ./cmd/app - name: Install Test Converter and run tests run: | export GOPATH="$HOME/go/" diff --git a/cmd/app/browser.go b/cmd/app/browser.go new file mode 100644 index 00000000..93411a20 --- /dev/null +++ b/cmd/app/browser.go @@ -0,0 +1,57 @@ +//go:build !noui + +package main + +import ( + "context" + "os/exec" + "runtime" + + "github.com/device-management-toolkit/console/config" +) + +func launchBrowser(cfg *config.Config) { + scheme := "http" + if cfg.TLS.Enabled { + scheme = "https" + } + + if err := openBrowser(scheme+"://localhost:"+cfg.Port, runtime.GOOS); err != nil { + panic(err) + } +} + +// CommandExecutor is an interface to allow for mocking exec.Command in tests. +type CommandExecutor interface { + Execute(name string, arg ...string) error +} + +// RealCommandExecutor is a real implementation of CommandExecutor. +type RealCommandExecutor struct{} + +func (e *RealCommandExecutor) Execute(name string, arg ...string) error { + return exec.CommandContext(context.Background(), name, arg...).Start() +} + +// Global command executor, can be replaced in tests. +var cmdExecutor CommandExecutor = &RealCommandExecutor{} + +func openBrowser(url, currentOS string) error { + var cmd string + + var args []string + + switch currentOS { + case "darwin": + cmd = "open" + args = []string{url} + case "windows": + cmd = "cmd" + args = []string{"/c", "start", url} + default: + cmd = "xdg-open" + args = []string{url} + } + + return cmdExecutor.Execute(cmd, args...) +} diff --git a/cmd/app/browser_noui.go b/cmd/app/browser_noui.go new file mode 100644 index 00000000..6396a413 --- /dev/null +++ b/cmd/app/browser_noui.go @@ -0,0 +1,8 @@ +//go:build noui + +package main + +import "github.com/device-management-toolkit/console/config" + +// launchBrowser is a no-op in noui builds; there is no UI to open. +func launchBrowser(_ *config.Config) {} diff --git a/cmd/app/browser_test.go b/cmd/app/browser_test.go new file mode 100644 index 00000000..c60dde30 --- /dev/null +++ b/cmd/app/browser_test.go @@ -0,0 +1,53 @@ +//go:build !noui + +package main + +import ( + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/mock" +) + +type MockCommandExecutor struct { + mock.Mock +} + +func (m *MockCommandExecutor) Execute(name string, arg ...string) error { + args := m.Called(name, arg) + + return args.Error(0) +} + +func TestOpenBrowserWindows(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. + mockCmdExecutor := new(MockCommandExecutor) + cmdExecutor = mockCmdExecutor + + mockCmdExecutor.On("Execute", "cmd", []string{"/c", "start", "http://localhost:8080"}).Return(nil) + + err := openBrowser("http://localhost:8080", "windows") + assert.NoError(t, err) + mockCmdExecutor.AssertExpectations(t) +} + +func TestOpenBrowserDarwin(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. + mockCmdExecutor := new(MockCommandExecutor) + cmdExecutor = mockCmdExecutor + + mockCmdExecutor.On("Execute", "open", []string{"http://localhost:8080"}).Return(nil) + + err := openBrowser("http://localhost:8080", "darwin") + assert.NoError(t, err) + mockCmdExecutor.AssertExpectations(t) +} + +func TestOpenBrowserLinux(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. + mockCmdExecutor := new(MockCommandExecutor) + cmdExecutor = mockCmdExecutor + + mockCmdExecutor.On("Execute", "xdg-open", []string{"http://localhost:8080"}).Return(nil) + + err := openBrowser("http://localhost:8080", "ubuntu") + assert.NoError(t, err) + mockCmdExecutor.AssertExpectations(t) +} diff --git a/cmd/app/main.go b/cmd/app/main.go index d243023a..8466dc69 100644 --- a/cmd/app/main.go +++ b/cmd/app/main.go @@ -1,13 +1,10 @@ package main import ( - "context" "errors" "fmt" "log" "os" - "os/exec" - "runtime" "github.com/device-management-toolkit/go-wsman-messages/v2/pkg/security" @@ -98,17 +95,6 @@ func handleDebugMode(cfg *config.Config, l logger.Interface) { } } -func launchBrowser(cfg *config.Config) { - scheme := "http" - if cfg.TLS.Enabled { - scheme = "https" - } - - if err := openBrowser(scheme+"://localhost:"+cfg.Port, runtime.GOOS); err != nil { - panic(err) - } -} - func handleOpenAPIGeneration(l logger.Interface) { usecases := usecase.Usecases{} @@ -302,38 +288,3 @@ func handleKeyNotFound(toolkitCrypto security.Crypto, _, _ security.Storager) st return toolkitCrypto.GenerateKey() } - -// CommandExecutor is an interface to allow for mocking exec.Command in tests. -type CommandExecutor interface { - Execute(name string, arg ...string) error -} - -// RealCommandExecutor is a real implementation of CommandExecutor. -type RealCommandExecutor struct{} - -func (e *RealCommandExecutor) Execute(name string, arg ...string) error { - return exec.CommandContext(context.Background(), name, arg...).Start() -} - -// Global command executor, can be replaced in tests. -var cmdExecutor CommandExecutor = &RealCommandExecutor{} - -func openBrowser(url, currentOS string) error { - var cmd string - - var args []string - - switch currentOS { - case "darwin": - cmd = "open" - args = []string{url} - case "windows": - cmd = "cmd" - args = []string{"/c", "start", url} - default: - cmd = "xdg-open" - args = []string{url} - } - - return cmdExecutor.Execute(cmd, args...) -} diff --git a/cmd/app/main_test.go b/cmd/app/main_test.go index 41ec0d14..7f0900ce 100644 --- a/cmd/app/main_test.go +++ b/cmd/app/main_test.go @@ -17,16 +17,6 @@ import ( "github.com/device-management-toolkit/console/pkg/logger" ) -type MockCommandExecutor struct { - mock.Mock -} - -func (m *MockCommandExecutor) Execute(name string, arg ...string) error { - args := m.Called(name, arg) - - return args.Error(0) -} - func TestMainFunction(_ *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying env variables. os.Setenv("GIN_MODE", "debug") @@ -54,39 +44,6 @@ func TestMainFunction(_ *testing.T) { //nolint:paralleltest // cannot have simul main() } -func TestOpenBrowserWindows(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. - mockCmdExecutor := new(MockCommandExecutor) - cmdExecutor = mockCmdExecutor - - mockCmdExecutor.On("Execute", "cmd", []string{"/c", "start", "http://localhost:8080"}).Return(nil) - - err := openBrowser("http://localhost:8080", "windows") - assert.NoError(t, err) - mockCmdExecutor.AssertExpectations(t) -} - -func TestOpenBrowserDarwin(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. - mockCmdExecutor := new(MockCommandExecutor) - cmdExecutor = mockCmdExecutor - - mockCmdExecutor.On("Execute", "open", []string{"http://localhost:8080"}).Return(nil) - - err := openBrowser("http://localhost:8080", "darwin") - assert.NoError(t, err) - mockCmdExecutor.AssertExpectations(t) -} - -func TestOpenBrowserLinux(t *testing.T) { //nolint:paralleltest // cannot have simultaneous tests modifying executor. - mockCmdExecutor := new(MockCommandExecutor) - cmdExecutor = mockCmdExecutor - - mockCmdExecutor.On("Execute", "xdg-open", []string{"http://localhost:8080"}).Return(nil) - - err := openBrowser("http://localhost:8080", "ubuntu") - assert.NoError(t, err) - mockCmdExecutor.AssertExpectations(t) -} - type MockGenerator struct { mock.Mock }