Stable order for serialized requests

BUG=chromium:1051691
TEST=emerge and run_tests.sh

Change-Id: I1b9de092d14241916322097e2bc8b7f7f5040a61
Reviewed-on: https://chromium-review.googlesource.com/c/chromiumos/infra/tnull/+/2304723
Tested-by: Jacob Kopczynski <jkop@chromium.org>
Auto-Submit: Jacob Kopczynski <jkop@chromium.org>
Commit-Queue: Prathmesh Prabhu <pprabhu@chromium.org>
Reviewed-by: Prathmesh Prabhu <pprabhu@chromium.org>
diff --git a/metadata/all-tests.json b/metadata/all-tests.json
index 327ac2e..e98ed3c 100644
--- a/metadata/all-tests.json
+++ b/metadata/all-tests.json
@@ -1,76 +1,76 @@
 {
   "requests": [
     {
-      "name": "request_no-log",
-      "test": "remoteTestDrivers/tnull/tests/no-log"
-    },
-    {
-      "name": "request_two-logs",
-      "test": "remoteTestDrivers/tnull/tests/two-logs"
-    },
-    {
-      "name": "request_mixed-logs",
-      "test": "remoteTestDrivers/tnull/tests/mixed-logs"
-    },
-    {
-      "name": "request_no-artifact",
-      "test": "remoteTestDrivers/tnull/tests/no-artifact"
-    },
-    {
-      "name": "request_report-failure",
-      "test": "remoteTestDrivers/tnull/tests/report-failure"
-    },
-    {
-      "name": "request_success-with-warnings",
-      "test": "remoteTestDrivers/tnull/tests/success-with-warnings"
-    },
-    {
-      "name": "request_report-success",
-      "test": "remoteTestDrivers/tnull/tests/report-success"
-    },
-    {
-      "name": "request_multiline-logs",
-      "test": "remoteTestDrivers/tnull/tests/multiline-logs"
-    },
-    {
-      "name": "request_simple-log",
-      "test": "remoteTestDrivers/tnull/tests/simple-log"
-    },
-    {
-      "name": "request_two-requests",
-      "test": "remoteTestDrivers/tnull/tests/two-requests"
-    },
-    {
-      "name": "request_simple-artifact",
-      "test": "remoteTestDrivers/tnull/tests/simple-artifact"
-    },
-    {
-      "name": "request_multiline-artifact",
-      "test": "remoteTestDrivers/tnull/tests/multiline-artifact"
-    },
-    {
-      "name": "request_two-artifacts",
-      "test": "remoteTestDrivers/tnull/tests/two-artifacts"
-    },
-    {
       "name": "request_dummy-pass",
       "test": "remoteTestDrivers/tnull/tests/dummy-pass"
     },
     {
-      "name": "request_fail-on-second-err",
-      "test": "remoteTestDrivers/tnull/tests/fail-on-second-err"
-    },
-    {
       "name": "request_duped-artifacts",
       "test": "remoteTestDrivers/tnull/tests/duped-artifacts"
     },
     {
-      "name": "request_report-skip",
-      "test": "remoteTestDrivers/tnull/tests/report-skip"
+      "name": "request_fail-on-second-err",
+      "test": "remoteTestDrivers/tnull/tests/fail-on-second-err"
+    },
+    {
+      "name": "request_mixed-logs",
+      "test": "remoteTestDrivers/tnull/tests/mixed-logs"
+    },
+    {
+      "name": "request_multiline-artifact",
+      "test": "remoteTestDrivers/tnull/tests/multiline-artifact"
+    },
+    {
+      "name": "request_multiline-logs",
+      "test": "remoteTestDrivers/tnull/tests/multiline-logs"
+    },
+    {
+      "name": "request_no-artifact",
+      "test": "remoteTestDrivers/tnull/tests/no-artifact"
+    },
+    {
+      "name": "request_no-log",
+      "test": "remoteTestDrivers/tnull/tests/no-log"
     },
     {
       "name": "request_parallel-log",
       "test": "remoteTestDrivers/tnull/tests/parallel-log"
+    },
+    {
+      "name": "request_report-failure",
+      "test": "remoteTestDrivers/tnull/tests/report-failure"
+    },
+    {
+      "name": "request_report-skip",
+      "test": "remoteTestDrivers/tnull/tests/report-skip"
+    },
+    {
+      "name": "request_report-success",
+      "test": "remoteTestDrivers/tnull/tests/report-success"
+    },
+    {
+      "name": "request_simple-artifact",
+      "test": "remoteTestDrivers/tnull/tests/simple-artifact"
+    },
+    {
+      "name": "request_simple-log",
+      "test": "remoteTestDrivers/tnull/tests/simple-log"
+    },
+    {
+      "name": "request_success-with-warnings",
+      "test": "remoteTestDrivers/tnull/tests/success-with-warnings"
+    },
+    {
+      "name": "request_two-artifacts",
+      "test": "remoteTestDrivers/tnull/tests/two-artifacts"
+    },
+    {
+      "name": "request_two-logs",
+      "test": "remoteTestDrivers/tnull/tests/two-logs"
+    },
+    {
+      "name": "request_two-requests",
+      "test": "remoteTestDrivers/tnull/tests/two-requests"
     }
   ]
 }
\ No newline at end of file
diff --git a/src/tnull/cmd/generate.go b/src/tnull/cmd/generate.go
index c66a788..4652639 100644
--- a/src/tnull/cmd/generate.go
+++ b/src/tnull/cmd/generate.go
@@ -8,6 +8,7 @@
 	"fmt"
 	"os"
 	"path/filepath"
+	"sort"
 
 	"github.com/golang/protobuf/jsonpb"
 	"github.com/maruel/subcommands"
@@ -50,7 +51,7 @@
 // WriteJSONInvocation writes a JSON encoded Invocation proto to destFile.
 func WriteJSONInvocation(tests map[string]*tnProto.Steps, destFile string) error {
 	reqs := []*rtd.Request{}
-	for name := range tests {
+	for _, name := range mapKeysToSortedList(tests) {
 		req := rtd.Request{
 			Name: "request_" + filepath.Base(name),
 			Test: name,
@@ -78,3 +79,12 @@
 	}
 	return nil
 }
+
+func mapKeysToSortedList(m map[string]*tnProto.Steps) []string {
+	keys := make([]string, 0, len(m))
+	for k := range m {
+		keys = append(keys, k)
+	}
+	sort.Strings(keys)
+	return keys
+}