Skip to content

Commit

Permalink
Add polyglot hook integration tests
Browse files Browse the repository at this point in the history
  • Loading branch information
moskyb committed May 4, 2023
1 parent 3275836 commit a38c09a
Show file tree
Hide file tree
Showing 3 changed files with 117 additions and 0 deletions.
3 changes: 3 additions & 0 deletions .buildkite/Dockerfile-compile
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
FROM golang:1.20.3@sha256:403f48633fb5ebd49f9a2b6ad6719f912df23dae44974a0c9445be331e72ff5e
COPY build/ssh.conf /etc/ssh/ssh_config.d/
RUN go install github.com/google/go-licenses@latest

# Ruby used for polyglot hook integration tests
RUN apt update && apt install -y ruby
83 changes: 83 additions & 0 deletions bootstrap/integration/hooks_integration_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ package integration
import (
"fmt"
"os"
"os/exec"
"path/filepath"
"runtime"
"strings"
Expand Down Expand Up @@ -489,3 +490,85 @@ func TestPreExitHooksFireAfterCancel(t *testing.T) {

tester.CheckMocks(t)
}

func TestPolyglotScriptHooksCanBeRun(t *testing.T) {
if !which("ruby") {
t.Fatal("ruby not found in $PATH. This test requires ruby to be installed on the host")
}

defer experiments.WithUndo(experiments.PolyglotHooks)()

tester, err := NewBootstrapTester()
if err != nil {
t.Fatalf("NewBootstrapTester() error = %v", err)
}
defer tester.Close()

filename := "environment"
script := []string{
"#!/usr/bin/env ruby",
`puts "ohai, it's ruby!"`,
}

if err := os.WriteFile(filepath.Join(tester.HooksDir, filename), []byte(strings.Join(script, "\n")), 0755); err != nil {
t.Fatalf("os.WriteFile(%q, script, 0755 = %v", filename, err)
}

tester.RunAndCheck(t)

if !strings.Contains(tester.Output, "ohai, it's ruby!") {
t.Fatalf("tester.Output %s does not contain expected output: %q", tester.Output, "ohai, it's ruby!")
}
}

func TestPolyglotBinaryHooksCanBeRun(t *testing.T) {
defer experiments.WithUndo(experiments.PolyglotHooks)()
defer experiments.WithUndo(experiments.JobAPI)()

tester, err := NewBootstrapTester()
if err != nil {
t.Fatalf("NewBootstrapTester() error = %v", err)
}
defer tester.Close()

// We build a binary as part of this test so that we can produce a binary hook
// Forgive me for my sins, RSC, but it's better than the alternatives.
// The code that we're building is in ./test-binary-hook/main.go, it's pretty straightforward.

fmt.Println("Building test-binary-hook")
hookPath := filepath.Join(tester.HooksDir, "environment")
output, err := exec.Command("go", "build", "-o", hookPath, "./test-binary-hook").CombinedOutput()
if err != nil {
t.Fatalf("Failed to build test-binary-hook: %v, output: %s", err, string(output))
}

tester.ExpectGlobalHook("post-command").Once().AndExitWith(0).AndCallFunc(func(c *bintest.Call) {
// Set via ./test-binary-hook/main.go
if c.GetEnv("OCEAN") != "Pacífico" {
fmt.Fprintf(c.Stderr, "Expected OCEAN to be Pacífico, got %q", c.GetEnv("OCEAN"))
c.Exit(1)
} else {
c.Exit(0)
}
})

tester.RunAndCheck(t)

if !strings.Contains(tester.Output, "hi there from golang 🌊") {
t.Fatalf("tester.Output %s does not contain expected output: %q", tester.Output, "hi there from golang 🌊")
}
}

func which(prog string) bool {
paths := strings.Split(os.Getenv("PATH"), string(os.PathListSeparator))

for _, path := range paths {
if fi, err := os.Stat(filepath.Join(path, prog)); err == nil {
if !fi.IsDir() && fi.Mode()&0o111 != 0 {
return true
}
}
}

return false
}
31 changes: 31 additions & 0 deletions bootstrap/integration/test-binary-hook/main.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package main

import (
"context"
"fmt"
"log"

"github.com/buildkite/agent/v3/jobapi"
)

// This file gets built and commited to this repo, then used as part of the hooks integration test to ensure that the
// bootstrap can run binary hooks
func main() {
c, err := jobapi.NewDefaultClient()
if err != nil {
log.Fatalf("error: %v", fmt.Errorf("creating job api client: %w", err))
}

_, err = c.EnvUpdate(context.TODO(), &jobapi.EnvUpdateRequest{
Env: map[string]string{
"OCEAN": "Pacífico",
"MOUNTAIN": "chimborazo",
},
})

if err != nil {
log.Fatalf("error: %v", fmt.Errorf("updating env: %w", err))
}

fmt.Println("hi there from golang 🌊")
}

0 comments on commit a38c09a

Please sign in to comment.