Skip to content

Commit

Permalink
add workaround for node not being executable
Browse files Browse the repository at this point in the history
  • Loading branch information
rusq committed Feb 7, 2023
1 parent f31c81b commit d74c925
Show file tree
Hide file tree
Showing 2 changed files with 150 additions and 2 deletions.
72 changes: 70 additions & 2 deletions auth/browser/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ import (
"fmt"
"net/http"
"net/url"
"os"
"path/filepath"
"regexp"
"runtime"
"runtime/trace"
"strings"
"time"
Expand All @@ -26,7 +29,9 @@ type Client struct {

var Logger logger.Interface = logger.Default

var installFn = playwright.Install
var (
installFn = playwright.Install
)

// New create new browser based client.
func New(workspace string, opts ...Option) (*Client, error) {
Expand All @@ -40,7 +45,12 @@ func New(workspace string, opts ...Option) (*Client, error) {
if err := installFn(&playwright.RunOptions{
Browsers: []string{cl.br.String()},
}); err != nil {
return nil, err
if !strings.Contains(err.Error(), "could not run driver") || runtime.GOOS == "windows" {
return nil, err
}
if err := pwRepair(cl.br.String()); err != nil {
return nil, err
}
}
return cl, nil
}
Expand Down Expand Up @@ -205,3 +215,61 @@ func l() logger.Interface {
}
return Logger
}

// newDriverFn is the function that creates a new driver. It is set to
// playwright.NewDriver by default, but can be overridden for testing.
var newDriverFn = playwright.NewDriver

// pwRepair attempts to repair the playwright installation.
func pwRepair(browser string) error {
if browser == "" {
return nil
}
drv, err := newDriverFn(&playwright.RunOptions{
Browsers: []string{browser},
})
if err != nil {
return err
}

// check node permissions
if err := pwIsKnownProblem(drv.DriverDirectory); err != nil {
return err
}
if err := os.RemoveAll(drv.DriverDirectory); err != nil {
return err
}

// attempt to reinstall
if err := installFn(&playwright.RunOptions{
Browsers: []string{browser},
}); err != nil {
// we did everything we could, but it still failed.
return err
}
return nil
}

var errUnknownProblem = errors.New("unknown problem")

// pwIsKnownProblem checks if the playwright installation is in a known
// problematic state, and if yes, return nil. If the problem is unknown,
// returns an errUnknownProblem.
func pwIsKnownProblem(path string) error {
if runtime.GOOS == "windows" {
// this should not ever happen on windows, as this problem relates to
// executable flag not being set, which is not a thing in a
// DOS/Windows world.
return errors.New("impossible has just happened, call the exorcist")
}
fi, err := os.Stat(filepath.Join(path, "node"))
if err != nil {
return err
}
// check if the file is executable, and if yes, return an error, because
// we wouldn't know what to do.
if fi.Mode()&0111 != 0 {
return errUnknownProblem
}
return nil
}
80 changes: 80 additions & 0 deletions auth/browser/client_test.go
Original file line number Diff line number Diff line change
@@ -1,9 +1,16 @@
package browser

import (
"errors"
"io/fs"
"os"
"path/filepath"
"reflect"
"runtime"
"testing"
"time"

"github.com/playwright-community/playwright-go"
)

func Test_extractToken(t *testing.T) {
Expand Down Expand Up @@ -57,3 +64,76 @@ func Test_float2time(t *testing.T) {
})
}
}

func Test_pwRepair(t *testing.T) {
if runtime.GOOS == "windows" {
t.Skip("skipping test on windows")
}
t.Run("known executable permissions problem causes reinstall", func(t *testing.T) {
baseDir := t.TempDir()
fakePwDir := filepath.Join(baseDir, "playwright-99.20.0")

// installCalledi should be set to true if the install function is
// called.
installCalled := false
// set the mock install functions.
oldInstall := installFn
defer func() { installFn = oldInstall }()
installFn = func(...*playwright.RunOptions) error {
installCalled = true
return nil
}
oldNewDriverFn := newDriverFn
defer func() { newDriverFn = oldNewDriverFn }()
newDriverFn = func(*playwright.RunOptions) (*playwright.PlaywrightDriver, error) {
return &playwright.PlaywrightDriver{
DriverDirectory: fakePwDir,
}, nil
}

// create a fake node file with the wrong permissions.
makeFakeNode(t, fakePwDir, 0o644)
// run the repair function.
if err := pwRepair(baseDir); err != nil {
t.Fatal(err)
}

if !installCalled {
t.Fatal("install was not called")
}
// check that the directory was removed
if _, err := os.Stat(fakePwDir); !os.IsNotExist(err) {
t.Fatal("directory was not removed")
}
})
}

func makeFakeNode(t *testing.T, dir string, mode fs.FileMode) {
if err := os.MkdirAll(dir, 0o755); err != nil {
t.Fatal(err)
}
if err := os.WriteFile(filepath.Join(dir, "node"), []byte("hello"), mode); err != nil {
t.Fatal(err)
}
}

func Test_pwIsKnownProblem(t *testing.T) {
t.Run("known executable permissions problem", func(t *testing.T) {
baseDir := t.TempDir()
makeFakeNode(t, baseDir, 0o644)
if err := pwIsKnownProblem(baseDir); err != nil {
t.Fatal(err)
}
})
t.Run("other problem", func(t *testing.T) {
baseDir := t.TempDir()
makeFakeNode(t, baseDir, 0o755)
err := pwIsKnownProblem(baseDir)
if err == nil {
t.Fatal("unexpected success")
}
if !errors.Is(err, errUnknownProblem) {
t.Fatal("unexpected error")
}
})
}

0 comments on commit d74c925

Please sign in to comment.