Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -178,7 +178,9 @@ define _BACKGROUND_JOBS_STAGES
{"slug":"jd6","tester_log_prefix":"tester::#jd6","title":"Stage#3: List a single job"}, \
{"slug":"dk5","tester_log_prefix":"tester::#dk5","title":"Stage#4: List multiple jobs"}, \
{"slug":"ma9","tester_log_prefix":"tester::#ma9","title":"Stage#5: Reaping one job using jobs"}, \
{"slug":"rq2","tester_log_prefix":"tester::#rq2","title":"Stage#6: Reaping multiple jobs using jobs"} \
{"slug":"rq2","tester_log_prefix":"tester::#rq2","title":"Stage#6: Reaping multiple jobs using jobs"}, \
{"slug":"bv8","tester_log_prefix":"tester::#bv8","title":"Stage#7: Reap before the next prompt"}, \
{"slug":"fy4","tester_log_prefix":"tester::#fy4","title":"Stage#8: Job number reset"} \
]
endef

Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -8,8 +8,10 @@ require (
github.com/charmbracelet/x/vt v0.0.0-20250122132629-a969ddeb820d
github.com/codecrafters-io/tester-utils v0.4.15
github.com/creack/pty v1.1.24
github.com/dustin/go-humanize v1.0.1
github.com/fatih/color v1.18.0
github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510
github.com/stretchr/testify v1.10.0
go.chromium.org/luci v0.0.0-20250611085002-a5741c865576
)

Expand All @@ -20,7 +22,6 @@ require (
github.com/charmbracelet/x/ansi v0.7.0 // indirect
github.com/charmbracelet/x/wcwidth v0.0.0-20241011142426-46044092ad91 // indirect
github.com/davecgh/go-spew v1.1.1 // indirect
github.com/dustin/go-humanize v1.0.1 // indirect
github.com/google/go-cmp v0.7.0 // indirect
github.com/kr/pretty v0.3.1 // indirect
github.com/lucasb-eyer/go-colorful v1.2.0 // indirect
Expand All @@ -30,7 +31,6 @@ require (
github.com/pmezard/go-difflib v1.0.0 // indirect
github.com/rivo/uniseg v0.4.7 // indirect
github.com/rogpeppe/go-internal v1.14.1 // indirect
github.com/stretchr/testify v1.10.0 // indirect
golang.org/x/exp v0.0.0-20250606033433-dcc06ee1d476 // indirect
golang.org/x/sys v0.40.0 // indirect
golang.org/x/term v0.32.0 // indirect
Expand Down
2 changes: 1 addition & 1 deletion internal/stage_bg1.go
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ func testBG1(stageHarness *test_case_harness.TestCaseHarness) error {
jobsTestCase := test_cases.JobsBuiltinResponseTestCase{
SuccessMessage: "✓ Received empty response",
// Expect no output
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{},
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{},
}

if err := jobsTestCase.Run(asserter, shell, logger); err != nil {
Expand Down
2 changes: 1 addition & 1 deletion internal/stage_bg3.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ func testBG3(stageHarness *test_case_harness.TestCaseHarness) error {

// Assert the job output
jobsTestCase := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{{
JobNumber: 1,
Status: "Running",
LaunchCommand: backgroundLaunchCommand,
Expand Down
4 changes: 2 additions & 2 deletions internal/stage_bg4.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,7 +52,7 @@ func launchBgCommandAndAssertJobs(asserter *logged_shell_asserter.LoggedShellAss

jobs = append(jobs, jobInfo{JobNumber: i + 1, Command: bgCommand})

jobsOutputEntries := make([]test_cases.JobsBuiltinOutputEntry, 0, len(jobs))
jobsOutputEntries := make([]test_cases.BackgroundJobStatusEntry, 0, len(jobs))

for i, job := range jobs {
// Default marker is unmarked
Expand All @@ -66,7 +66,7 @@ func launchBgCommandAndAssertJobs(asserter *logged_shell_asserter.LoggedShellAss
marker = test_cases.PreviousJob
}

jobsOutputEntries = append(jobsOutputEntries, test_cases.JobsBuiltinOutputEntry{
jobsOutputEntries = append(jobsOutputEntries, test_cases.BackgroundJobStatusEntry{
JobNumber: job.JobNumber,
Status: "Running",
LaunchCommand: job.Command,
Expand Down
4 changes: 2 additions & 2 deletions internal/stage_bg5.go
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ func testBG5(stageHarness *test_case_harness.TestCaseHarness) error {

// Call jobs
jobsBuiltinTestCase1 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{{
JobNumber: 1,
Status: "Running",
LaunchCommand: bgGrepCommand,
Expand All @@ -64,7 +64,7 @@ func testBG5(stageHarness *test_case_harness.TestCaseHarness) error {

// Call jobs again
jobsBuiltinTestCase2 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{{
JobNumber: 1,
Status: "Done",
LaunchCommand: bgGrepCommand,
Expand Down
6 changes: 3 additions & 3 deletions internal/stage_bg6.go
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ func testBG6(stageHarness *test_case_harness.TestCaseHarness) error {

// Call jobs for the first time
jobsBuiltinTestCase1 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{
{JobNumber: 1, Status: "Running", LaunchCommand: sleepCommand, Marker: test_cases.UnmarkedJob},
{JobNumber: 2, Status: "Done", LaunchCommand: bgGrepCommand1, Marker: test_cases.PreviousJob},
{JobNumber: 3, Status: "Running", LaunchCommand: bgGrepCommand2, Marker: test_cases.CurrentJob},
Expand All @@ -96,7 +96,7 @@ func testBG6(stageHarness *test_case_harness.TestCaseHarness) error {

// Call jobs for the second time
jobsBuiltinTestCase2 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{
{JobNumber: 1, Status: "Running", LaunchCommand: sleepCommand, Marker: test_cases.PreviousJob},
{JobNumber: 3, Status: "Done", LaunchCommand: bgGrepCommand2, Marker: test_cases.CurrentJob},
},
Expand All @@ -108,7 +108,7 @@ func testBG6(stageHarness *test_case_harness.TestCaseHarness) error {

// Call jobs again
jobsBuiltinTestCase3 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.JobsBuiltinOutputEntry{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{
{JobNumber: 1, Status: "Running", LaunchCommand: sleepCommand, Marker: test_cases.CurrentJob},
},
SuccessMessage: "✓ 1 entry matches the running job",
Expand Down
100 changes: 100 additions & 0 deletions internal/stage_bg7.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
package internal

import (
"fmt"

"github.com/codecrafters-io/shell-tester/internal/logged_shell_asserter"
"github.com/codecrafters-io/shell-tester/internal/shell_executable"
"github.com/codecrafters-io/shell-tester/internal/test_cases"
"github.com/codecrafters-io/tester-utils/random"
"github.com/codecrafters-io/tester-utils/test_case_harness"
)

func testBG7(stageHarness *test_case_harness.TestCaseHarness) error {
logger := stageHarness.Logger
shell := shell_executable.NewShellExecutable(stageHarness)
asserter := logged_shell_asserter.NewLoggedShellAsserter(shell)

fifoPath := fmt.Sprintf("/tmp/%s-%d", random.RandomWord(), random.RandomInt(1, 100))
if err := CreateRandomFIFOWithTeardown(stageHarness, fifoPath, 0644); err != nil {
return err
}

if err := asserter.StartShellAndAssertPrompt(true); err != nil {
return err
}

// Spawn background process: sleep 500
sleepCommand := "sleep 500"
bgSleepTestCase := test_cases.BackgroundCommandResponseTestCase{
Command: sleepCommand,
ExpectedJobNumber: 1,
SuccessMessage: "✓ Output includes job number with PID",
}
if err := bgSleepTestCase.Run(asserter, shell, logger); err != nil {
return err
}

// Grep read pattern
grepPattern := random.RandomWord()
bgGrepCommand := fmt.Sprintf("grep -q %s %s", grepPattern, fifoPath)
bgGrepTestCase := test_cases.BackgroundCommandResponseTestCase{
Command: bgGrepCommand,
ExpectedJobNumber: 2,
SuccessMessage: "✓ Output includes job number with PID",
}
if err := bgGrepTestCase.Run(asserter, shell, logger); err != nil {
return err
}

// Run jobs
jobsBuiltinTestCase := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{
{JobNumber: 1, Status: "Running", LaunchCommand: sleepCommand, Marker: test_cases.PreviousJob},
{JobNumber: 2, Status: "Running", LaunchCommand: bgGrepCommand, Marker: test_cases.CurrentJob},
},
SuccessMessage: "✓ Found 2 entries for the running jobs",
}
if err := jobsBuiltinTestCase.Run(asserter, shell, logger); err != nil {
return err
}

// Write to fifo
if err := WriteToFile(stageHarness, fifoPath, grepPattern); err != nil {
return err
}

// Issue an echo command and expect the reaped job entry will follow the echoed text
echoArgument := random.RandomWord()
echoTestCase := test_cases.CommandResponseWithReapedJobsTestCase{
Command: fmt.Sprintf("echo %s", echoArgument),
ExpectedCommandOutput: echoArgument,
ExpectedReapedJobEntries: []*test_cases.BackgroundJobStatusEntry{{
JobNumber: 2,
Status: "Done",
LaunchCommand: bgGrepCommand,
Marker: test_cases.CurrentJob,
}},
SuccessMessage: "✓ Found command output followed by an entry for the reaped job",
}

if err := echoTestCase.Run(asserter, shell, logger); err != nil {
return err
}

// Call jobs — only sleep (job 1) remains
jobsBuiltinTestCase2 := test_cases.JobsBuiltinResponseTestCase{
ExpectedOutputEntries: []test_cases.BackgroundJobStatusEntry{{
JobNumber: 1,
Status: "Running",
LaunchCommand: sleepCommand,
Marker: test_cases.CurrentJob,
}},
SuccessMessage: "✓ 1 entry matches the running job",
}
if err := jobsBuiltinTestCase2.Run(asserter, shell, logger); err != nil {
return err
}

return logAndQuit(asserter, nil)
}
Loading