Skip to content

Commit c4455b9

Browse files
committed
feat(buildrunner/noop): add pass-through BuildRunner stub
## Summary ### Why? Wiring tests for the orchestrator's build stage need a `BuildRunner` implementation, but real backends (BuildKite, Jenkins, etc.) won't land until later. A noop that immediately reports success is also useful as the local default in `make local-start` and as a best-case baseline where every build passes. ### What? Adds `extension/buildrunner/noop` — a `BuildRunner` that does no real work. Every `Trigger` returns a unique `noop-<n>` build ID with no error; every `Status` returns `BuildStatusSucceeded` with no metadata; `Cancel` is a no-op. The atomic counter keeps IDs unique under concurrent use. ## Test Plan - ✅ `make test` — 36 unit tests pass, including the new `extension/buildrunner/noop:noop_test` (Trigger uniqueness, Status, Cancel, interface satisfaction). - ✅ `make fmt lint check-tidy check-gazelle check-mocks` — clean. - ✅ `make build` — all targets compile.
1 parent 7d6bf16 commit c4455b9

3 files changed

Lines changed: 141 additions & 0 deletions

File tree

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
load("@rules_go//go:def.bzl", "go_library", "go_test")
2+
3+
go_library(
4+
name = "noop",
5+
srcs = ["noop.go"],
6+
importpath = "github.com/uber/submitqueue/extension/buildrunner/noop",
7+
visibility = ["//visibility:public"],
8+
deps = [
9+
"//entity",
10+
"//extension/buildrunner",
11+
],
12+
)
13+
14+
go_test(
15+
name = "noop_test",
16+
srcs = ["noop_test.go"],
17+
embed = [":noop"],
18+
deps = [
19+
"//entity",
20+
"//extension/buildrunner",
21+
"@com_github_stretchr_testify//assert",
22+
"@com_github_stretchr_testify//require",
23+
],
24+
)

extension/buildrunner/noop/noop.go

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
// Package noop provides a buildrunner.BuildRunner that performs no real
16+
// work: every triggered build immediately succeeds. It is intended as a
17+
// stub for wiring tests and as a best-case baseline where every build
18+
// passes.
19+
package noop
20+
21+
import (
22+
"context"
23+
"fmt"
24+
"sync/atomic"
25+
26+
"github.com/uber/submitqueue/entity"
27+
"github.com/uber/submitqueue/extension/buildrunner"
28+
)
29+
30+
// runner is a buildrunner.BuildRunner that does no real work and reports
31+
// every build as immediately succeeded. The atomic counter hands out
32+
// unique build IDs and makes the type safe for concurrent use.
33+
type runner struct {
34+
counter atomic.Uint64
35+
}
36+
37+
// New returns a buildrunner.BuildRunner that performs no real work.
38+
func New() buildrunner.BuildRunner {
39+
return &runner{}
40+
}
41+
42+
// Trigger returns a unique build ID without contacting any runner.
43+
// Inputs are ignored.
44+
func (r *runner) Trigger(_ context.Context, _ string, _ []entity.Change, _ []entity.Change, _ entity.BuildMetadata) (entity.BuildID, error) {
45+
return entity.BuildID{ID: fmt.Sprintf("noop-%d", r.counter.Add(1))}, nil
46+
}
47+
48+
// Status always reports BuildStatusSucceeded with no metadata.
49+
func (r *runner) Status(_ context.Context, _ entity.BuildID) (entity.BuildStatus, entity.BuildMetadata, error) {
50+
return entity.BuildStatusSucceeded, nil, nil
51+
}
52+
53+
// Cancel is a no-op.
54+
func (r *runner) Cancel(_ context.Context, _ entity.BuildID) error {
55+
return nil
56+
}
Lines changed: 61 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
// Copyright (c) 2025 Uber Technologies, Inc.
2+
//
3+
// Licensed under the Apache License, Version 2.0 (the "License");
4+
// you may not use this file except in compliance with the License.
5+
// You may obtain a copy of the License at
6+
//
7+
// http://www.apache.org/licenses/LICENSE-2.0
8+
//
9+
// Unless required by applicable law or agreed to in writing, software
10+
// distributed under the License is distributed on an "AS IS" BASIS,
11+
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
// See the License for the specific language governing permissions and
13+
// limitations under the License.
14+
15+
package noop
16+
17+
import (
18+
"context"
19+
"testing"
20+
21+
"github.com/stretchr/testify/assert"
22+
"github.com/stretchr/testify/require"
23+
"github.com/uber/submitqueue/entity"
24+
"github.com/uber/submitqueue/extension/buildrunner"
25+
)
26+
27+
func TestNew_ImplementsInterface(t *testing.T) {
28+
var _ buildrunner.BuildRunner = New()
29+
}
30+
31+
func TestRunner_Trigger(t *testing.T) {
32+
r := New()
33+
ctx := context.Background()
34+
35+
id1, err := r.Trigger(ctx, "queueA",
36+
[]entity.Change{{URIs: []string{"github://owner/repo/pull/1"}}},
37+
[]entity.Change{{URIs: []string{"github://owner/repo/pull/2"}}},
38+
entity.BuildMetadata{"requester": "alice"},
39+
)
40+
require.NoError(t, err)
41+
assert.NotEmpty(t, id1.ID)
42+
43+
// IDs are unique across calls, even with empty inputs.
44+
id2, err := r.Trigger(ctx, "queueA", nil, nil, nil)
45+
require.NoError(t, err)
46+
assert.NotEqual(t, id1, id2)
47+
}
48+
49+
func TestRunner_Status(t *testing.T) {
50+
r := New()
51+
52+
status, meta, err := r.Status(context.Background(), entity.BuildID{ID: "any-id"})
53+
require.NoError(t, err)
54+
assert.Equal(t, entity.BuildStatusSucceeded, status)
55+
assert.Empty(t, meta)
56+
}
57+
58+
func TestRunner_Cancel(t *testing.T) {
59+
r := New()
60+
assert.NoError(t, r.Cancel(context.Background(), entity.BuildID{ID: "any-id"}))
61+
}

0 commit comments

Comments
 (0)