Skip to content

Commit

Permalink
Use ExecCmd abstraction for browserlauncher
Browse files Browse the repository at this point in the history
  • Loading branch information
thschmitt committed Dec 20, 2024
1 parent dfe45d2 commit c58133d
Show file tree
Hide file tree
Showing 14 changed files with 156 additions and 120 deletions.
36 changes: 33 additions & 3 deletions auth/browser_launcher.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,36 @@
package auth

// BrowserLauncher interface for opening browser windows.
type BrowserLauncher interface {
Open(url string) error
import (
"fmt"
"time"

"github.com/UiPath/uipathcli/utils"
)

// BrowserLauncher tries to open the default browser on the local system.
type BrowserLauncher struct {
Exec utils.ExecProcess
}

func (l BrowserLauncher) Open(url string) error {
cmd := l.openBrowser(url)
err := cmd.Start()
if err != nil {
return err
}
done := make(chan error)
go func() {
done <- cmd.Wait()
}()

select {
case err := <-done:
return err
case <-time.After(5 * time.Second):
return fmt.Errorf("Timed out waiting for browser to start")
}
}

func NewBrowserLauncher() *BrowserLauncher {
return &BrowserLauncher{utils.NewExecProcess()}
}
11 changes: 11 additions & 0 deletions auth/browser_launcher_darwin.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build darwin

package auth

import (
"github.com/UiPath/uipathcli/utils"
)

func (l BrowserLauncher) openBrowser(url string) utils.ExecCmd {
return l.Exec.Command("open", url)
}
11 changes: 11 additions & 0 deletions auth/browser_launcher_linux.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build linux

package auth

import (
"github.com/UiPath/uipathcli/utils"
)

func (l BrowserLauncher) openBrowser(url string) utils.ExecCmd {
return l.Exec.Command("xdg-open", url)
}
11 changes: 11 additions & 0 deletions auth/browser_launcher_windows.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
//go:build windows

package auth

import (
"github.com/UiPath/uipathcli/utils"
)

func (l BrowserLauncher) openBrowser(url string) utils.ExecCmd {
return l.Exec.Command("rundll32", "url.dll,FileProtocolHandler", url)
}
47 changes: 0 additions & 47 deletions auth/exec_browser_launcher.go

This file was deleted.

30 changes: 15 additions & 15 deletions auth/oauth_authenticator_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,12 @@ import (
"net/http"
"net/http/httptest"
"net/url"
"runtime"
"strings"
"testing"

"github.com/UiPath/uipathcli/cache"
"github.com/UiPath/uipathcli/utils"
)

func TestOAuthAuthenticatorNotEnabled(t *testing.T) {
Expand All @@ -25,7 +27,7 @@ func TestOAuthAuthenticatorNotEnabled(t *testing.T) {
request := NewAuthenticatorRequest("http:/localhost", map[string]string{})
context := NewAuthenticatorContext("login", config, createIdentityUrl(""), false, false, *request)

authenticator := NewOAuthAuthenticator(cache.NewFileCache(), nil)
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), *NewBrowserLauncher())
result := authenticator.Auth(*context)
if result.Error != "" {
t.Errorf("Expected no error when oauth flow is skipped, but got: %v", result.Error)
Expand All @@ -46,7 +48,7 @@ func TestOAuthAuthenticatorPreservesExistingHeaders(t *testing.T) {
request := NewAuthenticatorRequest("http:/localhost", headers)
context := NewAuthenticatorContext("login", config, createIdentityUrl(""), false, false, *request)

authenticator := NewOAuthAuthenticator(cache.NewFileCache(), nil)
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), *NewBrowserLauncher())
result := authenticator.Auth(*context)
if result.Error != "" {
t.Errorf("Expected no error when oauth flow is skipped, but got: %v", result.Error)
Expand All @@ -65,7 +67,7 @@ func TestOAuthAuthenticatorInvalidConfig(t *testing.T) {
request := NewAuthenticatorRequest("http:/localhost", map[string]string{})
context := NewAuthenticatorContext("login", config, createIdentityUrl(""), false, false, *request)

authenticator := NewOAuthAuthenticator(cache.NewFileCache(), nil)
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), *NewBrowserLauncher())
result := authenticator.Auth(*context)
if result.Error != "Invalid oauth authenticator configuration: Invalid value for clientId: '1'" {
t.Errorf("Expected error with invalid config, but got: %v", result.Error)
Expand Down Expand Up @@ -122,7 +124,7 @@ func TestOAuthFlowIsCached(t *testing.T) {
performLogin(loginUrl, t)
<-resultChannel

authenticator := NewOAuthAuthenticator(cache.NewFileCache(), nil)
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), *NewBrowserLauncher())
result := authenticator.Auth(context)

if result.Error != "" {
Expand Down Expand Up @@ -208,8 +210,15 @@ func TestMissingCodeShowsErrorMessage(t *testing.T) {

func callAuthenticator(context AuthenticatorContext) (url.URL, chan AuthenticatorResult) {
loginChan := make(chan string)
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), NoOpBrowserLauncher{
loginUrlChannel: loginChan,
authenticator := NewOAuthAuthenticator(cache.NewFileCache(), BrowserLauncher{
Exec: utils.NewExecCustomProcess(0, "", "", func(name string, args []string) {
switch runtime.GOOS {
case "windows":
loginChan <- args[1]
default:
loginChan <- args[0]
}
}),
})

resultChannel := make(chan AuthenticatorResult)
Expand Down Expand Up @@ -323,12 +332,3 @@ func (i identityServerFake) writeValidationErrorResponse(response http.ResponseW
response.WriteHeader(400)
_, _ = response.Write([]byte(message))
}

type NoOpBrowserLauncher struct {
loginUrlChannel chan string
}

func (l NoOpBrowserLauncher) Open(url string) error {
l.loginUrlChannel <- url
return nil
}
2 changes: 1 addition & 1 deletion main.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ var embedded embed.FS
func authenticators() []auth.Authenticator {
return []auth.Authenticator{
auth.NewPatAuthenticator(),
auth.NewOAuthAuthenticator(cache.NewFileCache(), auth.NewExecBrowserLauncher()),
auth.NewOAuthAuthenticator(cache.NewFileCache(), *auth.NewBrowserLauncher()),
auth.NewBearerAuthenticator(cache.NewFileCache()),
}
}
Expand Down
1 change: 1 addition & 0 deletions plugin/studio/package_analyze_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -227,6 +227,7 @@ func (c PackageAnalyzeCommand) getSource(context plugin.ExecutionContext) (strin
if source == "" {
return "", errors.New("source is not set")
}
source, _ = filepath.Abs(source)
fileInfo, err := os.Stat(source)
if err != nil {
return "", fmt.Errorf("%s not found", defaultProjectJson)
Expand Down
2 changes: 2 additions & 0 deletions plugin/studio/package_pack_command.go
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,7 @@ func (c PackagePackCommand) getSource(context plugin.ExecutionContext) (string,
if source == "" {
return "", errors.New("source is not set")
}
source, _ = filepath.Abs(source)
fileInfo, err := os.Stat(source)
if err != nil {
return "", fmt.Errorf("%s not found", defaultProjectJson)
Expand Down Expand Up @@ -237,6 +238,7 @@ func (c PackagePackCommand) getDestination(context plugin.ExecutionContext) (str
if destination == "" {
return "", errors.New("destination is not set")
}
destination, _ = filepath.Abs(destination)
return destination, nil
}

Expand Down
3 changes: 2 additions & 1 deletion plugin/studio/studio_plugin_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"testing"

"github.com/UiPath/uipathcli/test"
"github.com/UiPath/uipathcli/utils"
)

const studioDefinition = `
Expand Down Expand Up @@ -69,7 +70,7 @@ func TestPackNonExistentProject(t *testing.T) {
}

func TestFailedPackagingReturnsFailureStatus(t *testing.T) {
exec := test.NewFakeExecProcess(1, "Build output", "There was an error")
exec := utils.NewExecCustomProcess(1, "Build output", "There was an error", func(name string, args []string) {})
context := test.NewContextBuilder().
WithDefinition("studio", studioDefinition).
WithCommandPlugin(PackagePackCommand{exec}).
Expand Down
52 changes: 0 additions & 52 deletions test/fake_exec_process.go

This file was deleted.

2 changes: 1 addition & 1 deletion test/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -187,7 +187,7 @@ func RunCli(args []string, context Context) Result {
stderr := new(bytes.Buffer)
authenticators := []auth.Authenticator{
auth.NewPatAuthenticator(),
auth.NewOAuthAuthenticator(cache.NewFileCache(), auth.NewExecBrowserLauncher()),
auth.NewOAuthAuthenticator(cache.NewFileCache(), *auth.NewBrowserLauncher()),
auth.NewBearerAuthenticator(cache.NewFileCache()),
}
commandPlugins := []plugin.CommandPlugin{}
Expand Down
35 changes: 35 additions & 0 deletions utils/exec_custom_cmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package utils

import (
"io"
)

type ExecCustomCmd struct {
Name string
Args []string
Exit int
StdOut io.ReadCloser
StdErr io.ReadCloser
OnStart func(name string, args []string)
}

func (c ExecCustomCmd) StdoutPipe() (io.ReadCloser, error) {
return c.StdOut, nil
}

func (c ExecCustomCmd) StderrPipe() (io.ReadCloser, error) {
return c.StdErr, nil
}

func (c ExecCustomCmd) Start() error {
c.OnStart(c.Name, c.Args)
return nil
}

func (c ExecCustomCmd) Wait() error {
return nil
}

func (c ExecCustomCmd) ExitCode() int {
return c.Exit
}
33 changes: 33 additions & 0 deletions utils/exec_custom_process.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package utils

import (
"io"
"strings"
)

type ExecCustomProcess struct {
ExitCode int
Stdout string
Stderr string
OnStart func(name string, args []string)
}

func (e ExecCustomProcess) Command(name string, args ...string) ExecCmd {
return ExecCustomCmd{
Name: name,
Args: args,
StdOut: io.NopCloser(strings.NewReader(e.Stdout)),
StdErr: io.NopCloser(strings.NewReader(e.Stderr)),
Exit: e.ExitCode,
OnStart: e.OnStart,
}
}

func NewExecCustomProcess(exitCode int, stdout string, stderr string, onStart func(name string, args []string)) *ExecCustomProcess {
return &ExecCustomProcess{
ExitCode: exitCode,
Stdout: stdout,
Stderr: stderr,
OnStart: onStart,
}
}

0 comments on commit c58133d

Please sign in to comment.