Skip to content
quarry Artifact [091e43abd2]
Login

Artifact [091e43abd2]

Artifact 091e43abd24696d55955f52140912244156f8575a22c9411bf7417d873728dcd:


package runner

import (
	"context"
	"encoding/json"
	"fmt"
	"net"
	"net/http/httptest"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"
)

// Exercise the job's actual environment, not just taskTemp's return value.
func TestAJobCanBindAChromeSocketWithTheDefaultTempRoot(t *testing.T) {
	work := filepath.Join(t.TempDir(), strings.Repeat("deployment-depth/", 8), "runner")
	job, err := json.Marshal(Job{Steps: []JobStep{{
		Run: fmt.Sprintf("%q -test.run=^TestChromeSocketJobHelper$", os.Args[0]),
		Env: map[string]string{"QUARRY_TEST_CHROME_SOCKET": "1"},
	}}})
	if err != nil {
		t.Fatal(err)
	}
	tk := task("t1", "c1")
	tk.Metadata = map[string]string{JobKey: string(job)}
	br := &fakeBridge{queue: map[string][]polled{"t-job": {tk}}, resolved: map[string]map[string]any{}, logs: map[string]string{}}
	srv := httptest.NewServer(br.handler())
	defer srv.Close()
	r, err := New(Config{
		Bridge: srv.URL, Token: "WT", Tasks: []string{"t-job"}, MaxTasks: 1,
		WorkDir: work, Checkout: appCheckout{}, Heartbeat: 100 * time.Millisecond,
		Logf: func(string, ...any) {},
	})
	if err != nil {
		t.Fatal(err)
	}
	t.Cleanup(func() { os.RemoveAll(r.cfg.TempRoot) })
	ctx, cancel := context.WithTimeout(context.Background(), 15*time.Second)
	done := make(chan struct{})
	go func() { r.Run(ctx); close(done) }()
	defer func() { cancel(); <-done }()
	for ctx.Err() == nil {
		br.mu.Lock()
		result, resolved := br.resolved["t1"]
		logs := br.logs["t1"]
		br.mu.Unlock()
		if resolved {
			if result["action"] != "complete" {
				t.Fatalf("job failed: %v\n%s", result, logs)
			}
			var actualTemp string
			for _, line := range strings.Split(logs, "\n") {
				if value, ok := strings.CutPrefix(line, "CHROME_SOCKET_BOUND "); ok {
					actualTemp = strings.TrimSpace(value)
				}
			}
			if actualTemp == "" {
				t.Fatalf("job did not report its socket's temp directory:\n%s", logs)
			}
			if filepath.Dir(actualTemp) != r.cfg.TempRoot {
				t.Fatalf("job temp directory %q is not owned by runner root %q", actualTemp, r.cfg.TempRoot)
			}
			if entries, err := os.ReadDir(r.cfg.TempRoot); err != nil || len(entries) != 0 {
				t.Fatalf("task temp directory survived completion: %v, %v", entries, err)
			}
			return
		}
		time.Sleep(20 * time.Millisecond)
	}
	t.Fatal("job did not resolve before the deadline")
}

func TestChromeSocketJobHelper(t *testing.T) {
	if os.Getenv("QUARRY_TEST_CHROME_SOCKET") != "1" {
		return
	}
	tmp := os.Getenv("TMPDIR")
	if tmp == "" || !filepath.IsAbs(tmp) {
		t.Fatalf("TMPDIR must be a nonempty absolute path, got %q", tmp)
	}
	for _, name := range []string{"GOTMPDIR", "TMP", "TEMP"} {
		if os.Getenv(name) != tmp {
			t.Fatalf("%s differs from TMPDIR", name)
		}
	}
	chrome := filepath.Join(tmp, "com.google.Chrome.XXXXXX")
	if err := os.Mkdir(chrome, 0o700); err != nil {
		t.Fatal(err)
	}
	socket := filepath.Join(chrome, "SingletonSocket")
	listener, err := net.Listen("unix", socket)
	if err != nil {
		t.Fatalf("cannot bind %d-byte Chrome socket: %v", len(socket), err)
	}
	defer listener.Close()
	fmt.Println("CHROME_SOCKET_BOUND", tmp)
}