[tint] Read stdout and stderr asynchronously in E2E test runner

This avoids issues with very large output on one pipe being buffered
and blocking progress reading from the other pipe.

Bug: 429625133
Change-Id: I33db4e10f15cdc7bcd5f93fc2f41a68224cd573d
Reviewed-on: https://dawn-review.googlesource.com/c/dawn/+/251514
Commit-Queue: James Price <jrprice@google.com>
Auto-Submit: James Price <jrprice@google.com>
Reviewed-by: dan sinclair <dsinclair@chromium.org>
Commit-Queue: dan sinclair <dsinclair@chromium.org>
diff --git a/tools/src/cmd/tests/main.go b/tools/src/cmd/tests/main.go
index 9104f11..b2aa927 100644
--- a/tools/src/cmd/tests/main.go
+++ b/tools/src/cmd/tests/main.go
@@ -1033,21 +1033,37 @@
 	result := make(chan testResult, 1)
 	go func() {
 		// Send the test arguments to the Tint server.
-		_, in_err := tintServer.stdin.Write([]byte("\"" + strings.Join(args, "\" \"") + "\"\n"))
+		_, inErr := tintServer.stdin.Write([]byte("\"" + strings.Join(args, "\" \"") + "\"\n"))
 
 		// Read from stdout and stderr until the next null character.
-		read := func(stream io.ReadCloser) (str string, err error) {
-			reader := bufio.NewReader(stream)
-			result, err := reader.ReadString(0)
-			return strings.TrimSuffix(result, "\x00"), err
+		// Perform these as two asynchronous operations to prevent buffering of large output from
+		// blocking progress.
+		type readResult struct {
+			str string
+			err error
 		}
-		stdout_str, out_err := read(tintServer.stdout)
-		stderr_str, err_err := read(tintServer.stderr)
-		str := stderr_str + stdout_str
+		read := func(stream io.ReadCloser) chan readResult {
+			resultChannel := make(chan readResult, 1)
+			go func() {
+				reader := bufio.NewReader(stream)
+				result, err := reader.ReadString(0)
+				resultChannel <- readResult{strings.TrimSuffix(result, "\x00"), err}
+			}()
+			return resultChannel
+		}
+		stdoutChannel := read(tintServer.stdout)
+		stderrChannel := read(tintServer.stderr)
+
+		// Read the results from the channels.
+		stdoutResult := <-stdoutChannel
+		stderrResult := <-stderrChannel
+		stdoutStr, outErr := stdoutResult.str, stdoutResult.err
+		stderrStr, errErr := stderrResult.str, stderrResult.err
+		str := stderrStr + stdoutStr
 
 		result <- testResult{
 			output: str,
-			ok:     in_err == nil && out_err == nil && err_err == nil,
+			ok:     inErr == nil && outErr == nil && errErr == nil,
 		}
 	}()