Skip to content

fix(hal-go): use temp file to capture str-receiver output in string e2e test#80

Merged
sittner merged 2 commits intomodusoft-2.9from
copilot/fix-end-to-end-test
Feb 27, 2026
Merged

fix(hal-go): use temp file to capture str-receiver output in string e2e test#80
sittner merged 2 commits intomodusoft-2.9from
copilot/fix-end-to-end-test

Conversation

Copy link
Copy Markdown

Copilot AI commented Feb 27, 2026

loadusr spawns userspace components as separate processes; halrun's 2>&1 redirect only captures halcmd's own output, so fmt.Printf(...) in str-receiver was never visible in $OUTPUT, causing Test 10 to always fail.

Changes

  • str-receiver/main.go: Accept an optional output file path as os.Args[1]. On message receipt, write RECEIVED:<msg> to that file instead of printing to stdout. Backwards-compatible — runs fine without the argument.
if outFile != "" {
    if err := os.WriteFile(outFile, []byte("RECEIVED:"+msg+"\n"), 0644); err != nil {
        log.Printf("Failed to write result file: %v", err)
    }
}
  • run_tests.sh Test 10: Create a temp file before halrun, pass its path to str-receiver via loadusr, then inspect the file after halrun exits rather than grepping captured stdout.
STR_E2E_RESULT=$(mktemp --suffix=.txt)
run_hal <<EOF
loadusr -W $STR_SENDER
loadusr -W $STR_RECEIVER $STR_E2E_RESULT
...
EOF
grep -q 'RECEIVED:hello from go' "$STR_E2E_RESULT"

Warning

Firewall rules blocked me from connecting to one or more addresses (expand for details)

I tried to connect to the following addresses, but was blocked by firewall rules:

  • linuxcnc.org
    • Triggering command: /usr/bin/go go mod tidy -e (dns block)
    • Triggering command: /usr/bin/go go get -v ./... (dns block)

If you need me to access, download, or install something from one of these locations, you can either:

Original prompt

Bug: String end-to-end test fails because halrun doesn't capture loadusr component stdout

Problem

The string end-to-end test (Test 10) in src/hal/hal-go/tests/run_tests.sh always fails because the str-receiver component's fmt.Printf("RECEIVED:...") output goes to the receiver process's stdout, NOT to halrun's captured output.

When halrun -f file.hal runs loadusr, it spawns the component as a separate process. The 2>&1 redirect in run_hal() only captures halcmd's own stderr/stdout, not the stdout of spawned userspace components. So RECEIVED:hello from go never appears in $OUTPUT.

Fix

Use a temp file to communicate the result from the receiver to the test script.

1. Update src/hal/hal-go/tests/str-receiver/main.go

Accept an output file path via a command-line argument. Instead of printing to stdout, write the result to that file.

package main

import (
	"log"
	"os"
	"time"

	"linuxcnc.org/hal"
)

func main() {
	// Accept optional output file argument for test automation
	var outFile string
	if len(os.Args) > 1 {
		outFile = os.Args[1]
	}

	comp, err := hal.NewComponent("str-receiver")
	if err != nil {
		log.Fatalf("Failed to create component: %v", err)
	}
	defer comp.Exit()

	inPin, err := hal.NewPin[string](comp, "in", hal.In)
	if err != nil {
		log.Fatalf("Failed to create in pin: %v", err)
	}

	if err := comp.Ready(); err != nil {
		log.Fatalf("Failed to mark ready: %v", err)
	}
	log.Println("str-receiver ready")

	// Poll for incoming string
	for comp.Running() {
		msg := inPin.Get()
		if msg != "" {
			log.Printf("Received: %s", msg)
			// Write result to file if output path was provided
			if outFile != "" {
				os.WriteFile(outFile, []byte("RECEIVED:"+msg+"\n"), 0644)
			}
			// Keep running so halcmd can unload us cleanly
			for comp.Running() {
				time.Sleep(50 * time.Millisecond)
			}
			break
		}
		time.Sleep(10 * time.Millisecond)
	}

	log.Println("str-receiver exiting")
}

2. Update src/hal/hal-go/tests/run_tests.sh — Test 10

Change the test to:

  1. Create a temp file for the receiver output
  2. Pass the temp file path as an argument to str-receiver via loadusr
  3. After halrun completes, read the temp file to check the result
  4. Clean up the temp file
# Test 10: String end-to-end passthrough
if [[ "$SKIP_STR_E2E" != "true" ]]; then
    echo "Running: String end-to-end passthrough"
    : $((TESTS_RUN++))
    STR_E2E_RESULT=$(mktemp --suffix=.txt)
    run_hal <<EOF
loadusr -W $STR_SENDER
loadusr -Wn str-receiver $STR_RECEIVER $STR_E2E_RESULT
newsig test-msg port
net test-msg str-sender.out str-receiver.in
sets test-msg 1024
loadusr -w sleep 0.5
unload str-sender
unload str-receiver
EOF
    if [[ -f "$STR_E2E_RESULT" ]] && grep -q 'RECEIVED:hello from go' "$STR_E2E_RESULT"; then
        pass "String end-to-end passthrough"
    else
        fail "String end-to-end passthrough" "Expected 'RECEIVED:hello from go' in result file"
    fi
    rm -f "$STR_E2E_RESULT"
fi

Key points:

  • Use loadusr -Wn str-receiver $STR_RECEIVER $STR_E2E_RESULT — the -Wn str-receiver tells halcmd the component name is str-receiver even though the binary path has extra args. Actually, check: loadusr -W waits for the component name matching the binary name. Since the binary is str-receiver, just loadusr -W $STR_RECEIVER $STR_E2E_RESULT should work because the component name is derived from the binary basename. If that doesn't work, use -Wn str-receiver.
  • The $STR_E2E_RESULT temp file is created before halrun, written by the receiver during execution, and read after halrun completes.
  • Also make sure to clean up the temp file in the cleanup trap. Add STR_E2E_RESULT to the cleanup function or just rm -f it after use (which is already done).

Important implementation notes

  • The str-receiver should still work without the argument (for manual usage) — the outFile check handles this
  • The log.Printf calls go to stderr which halrun might capture, but we don't rely on that for the test — we use the explicit file
  • Keep fmt.Printf removed (or alongside) to avoid confusion — the file-based approach is the reliable one

This pull request was created from Copilot chat.


✨ Let Copilot coding agent set things up for you — coding agent works faster and does higher quality work when set up for your repo.

loadusr spawns components as separate processes, so their stdout is
not captured by halrun's 2>&1 redirect. Fix by:
- str-receiver/main.go: accept optional output file arg; write
  RECEIVED:<msg> to that file instead of fmt.Printf to stdout
- run_tests.sh Test 10: create temp file, pass to str-receiver via
  loadusr, check file contents after halrun completes

Co-authored-by: sittner <1475582+sittner@users.noreply.github.com>
Copilot AI changed the title [WIP] Fix string end-to-end test stdout capture fix(hal-go): use temp file to capture str-receiver output in string e2e test Feb 27, 2026
@sittner sittner marked this pull request as ready for review February 27, 2026 17:05
@sittner sittner merged commit 55ff9c2 into modusoft-2.9 Feb 27, 2026
@sittner sittner deleted the copilot/fix-end-to-end-test branch March 4, 2026 08:18
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants