[testrunner] Partition tests in a simpler way.

A switch statement and a for loop are better than the
group() function.

Change-Id: Ia0fbccd985d94c823a4a866813ed65b3e89e91fe
diff --git a/cmd/testrunner/main.go b/cmd/testrunner/main.go
index 80c64d3..96292e7 100644
--- a/cmd/testrunner/main.go
+++ b/cmd/testrunner/main.go
@@ -14,8 +14,6 @@
 	"log"
 	"os"
 	"path"
-	"sort"
-	"strings"
 	"time"
 
 	"fuchsia.googlesource.com/tools/botanist"
@@ -99,8 +97,14 @@
 		summary.Tests = append(summary.Tests, details)
 	}
 
+	// Prepare the Fuchsia DeviceContext.
+	devCtx, err := botanist.GetDeviceContext()
+	if err != nil {
+		log.Fatal(err)
+	}
+
 	// Execute.
-	if err := execute(tests, recordDetails); err != nil {
+	if err := execute(tests, recordDetails, devCtx); err != nil {
 		log.Fatal(err)
 	}
 
@@ -116,51 +120,34 @@
 	}
 }
 
-func execute(tests []testsharder.Test, recorder TestRecorder) error {
-	// Partition the tests into groups according to OS.
-	groups := groupTests(tests, func(test testsharder.Test) string {
-		sys := strings.ToLower(test.OS)
-		switch sys {
-		case "fuchsia", "linux", "mac":
-			return sys
-		}
-		return "unknown"
-	})
-
-	// Fail fast if any test cannot be run.
-	if unknownTests, ok := groups["unknown"]; ok {
-		return fmt.Errorf("could not determine the runtime system for following tests %v", unknownTests)
-	}
-
-	// Execute UNIX tests locally, assuming we're running in a UNIX environment.
-	localTests := append(groups["linux"], groups["mac"]...)
-	if len(localTests) > 0 {
-		if err := runTests(localTests, RunTestInSubprocess, outputDir, recorder); err != nil {
-			return err
-		}
-	}
-
-	// Execute Fuchsia tests.
-	return runFuchsiaTests(groups["fuchsia"], outputDir, recorder)
-}
-
-// groupTests splits a list of tests into named subgroups according to the names returned
-// by `name`.  Within any subgroup, the list of tests is sorted by test name.
-func groupTests(input []testsharder.Test, name func(testsharder.Test) string) map[string][]testsharder.Test {
-	tests := make([]testsharder.Test, len(input))
-	copy(tests, input)
-
-	sort.SliceStable(tests, func(i, j int) bool {
-		return tests[i].Name < tests[j].Name
-	})
-
-	output := make(map[string][]testsharder.Test)
+func execute(tests []testsharder.Test, recorder TestRecorder, devCtx *botanist.DeviceContext) error {
+	var linux, mac, fuchsia, unknown []testsharder.Test
 	for _, test := range tests {
-		group := name(test)
-		output[group] = append(output[group], test)
+		switch test.OS {
+		case "fuchsia":
+			fuchsia = append(fuchsia, test)
+		case "linux":
+			linux = append(linux, test)
+		case "mac":
+			mac = append(mac, test)
+		default:
+			unknown = append(unknown, test)
+		}
 	}
 
-	return output
+	if len(unknown) > 0 {
+		return fmt.Errorf("could not determine the runtime system for following tests %v", unknown)
+	}
+
+	if err := runTests(linux, RunTestInSubprocess, outputDir, recorder); err != nil {
+		return err
+	}
+
+	if err := runTests(mac, RunTestInSubprocess, outputDir, recorder); err != nil {
+		return err
+	}
+
+	return runFuchsiaTests(fuchsia, outputDir, recorder, devCtx)
 }
 
 func sshIntoNode(nodename, privateKeyPath string) (*ssh.Client, error) {
@@ -186,16 +173,11 @@
 	return botanist.SSHIntoNode(context.Background(), nodename, config)
 }
 
-func runFuchsiaTests(tests []testsharder.Test, outputDir string, record TestRecorder) error {
+func runFuchsiaTests(tests []testsharder.Test, outputDir string, record TestRecorder, devCtx *botanist.DeviceContext) error {
 	if len(tests) == 0 {
 		return nil
 	}
 
-	devCtx, err := botanist.GetDeviceContext()
-	if err != nil {
-		return err
-	}
-
 	// Initialize the connection to the Fuchsia device.
 	sshClient, err := sshIntoNode(devCtx.Nodename, devCtx.SSHKey)
 	if err != nil {
diff --git a/cmd/testrunner/main_test.go b/cmd/testrunner/main_test.go
deleted file mode 100644
index e5e04bb..0000000
--- a/cmd/testrunner/main_test.go
+++ /dev/null
@@ -1,59 +0,0 @@
-// Copyright 2019 The Fuchsia Authors. All rights reserved.
-// Use of this source code is governed by a BSD-style license that can be
-// found in the LICENSE file.
-
-package main
-
-import (
-	"reflect"
-	"testing"
-
-	"fuchsia.googlesource.com/tools/testsharder"
-)
-
-func TestGroupTests(t *testing.T) {
-	tests := []struct {
-		name   string
-		input  []testsharder.Test
-		output map[string][]testsharder.Test
-	}{{
-		name: "should sort tests by name and partition them into subgroups",
-		input: []testsharder.Test{
-			{Name: "a", OS: "A"},
-			{Name: "c", OS: "C"},
-			{Name: "e", OS: "B"},
-			{Name: "d", OS: "B"},
-			{Name: "b", OS: "A"},
-		},
-		output: map[string][]testsharder.Test{
-			// Note that tests in each subgroup are sorted by name.
-			"A": []testsharder.Test{
-				{Name: "a", OS: "A"},
-				{Name: "b", OS: "A"},
-			},
-			"B": []testsharder.Test{
-				{Name: "d", OS: "B"},
-				{Name: "e", OS: "B"},
-			},
-			"C": []testsharder.Test{
-				{Name: "c", OS: "C"},
-			},
-		},
-	}, {
-		name:   "should produce an empty map when given empty input",
-		input:  []testsharder.Test{},
-		output: map[string][]testsharder.Test{},
-	}}
-
-	for _, tt := range tests {
-		t.Run(tt.name, func(t *testing.T) {
-			output := groupTests(tt.input, func(test testsharder.Test) string {
-				return test.OS
-			})
-
-			if !reflect.DeepEqual(tt.output, output) {
-				t.Fatalf("got %v, want: '%v'", output, tt.output)
-			}
-		})
-	}
-}