diff mbox series

[v3,2/3] trace2: add a schema validator for trace2 events

Message ID 97cb6a3eb4f6c3f21fcdb69a15b0885c03526beb.1564009259.git.steadmon@google.com (mailing list archive)
State New, archived
Headers show
Series Add a JSON Schema for trace2 events | expand

Commit Message

Josh Steadmon July 24, 2019, 11:06 p.m. UTC
trace_schema_validator can be used to verify that trace2 event output
conforms to the expectations set by the API documentation and codified
in event_schema.json (or strict_schema.json). This allows us to build a
regression test to verify that trace2 output does not change
unexpectedly.

Signed-off-by: Josh Steadmon <steadmon@google.com>
---
 t/trace_schema_validator/.gitignore           |  1 +
 t/trace_schema_validator/Makefile             | 18 ++++
 .../trace_schema_validator.go                 | 82 +++++++++++++++++++
 3 files changed, 101 insertions(+)
 create mode 100644 t/trace_schema_validator/.gitignore
 create mode 100644 t/trace_schema_validator/Makefile
 create mode 100644 t/trace_schema_validator/trace_schema_validator.go
diff mbox series

Patch

diff --git a/t/trace_schema_validator/.gitignore b/t/trace_schema_validator/.gitignore
new file mode 100644
index 0000000000..c3f1e04e9e
--- /dev/null
+++ b/t/trace_schema_validator/.gitignore
@@ -0,0 +1 @@ 
+trace_schema_validator
diff --git a/t/trace_schema_validator/Makefile b/t/trace_schema_validator/Makefile
new file mode 100644
index 0000000000..50bd266518
--- /dev/null
+++ b/t/trace_schema_validator/Makefile
@@ -0,0 +1,18 @@ 
+RM = rm -f
+PROGRAMS = trace_schema_validator
+GOCMD = go
+GOBUILD = $(GOCMD) build
+GOGET = $(GOCMD) get
+
+.PHONY: fetch_deps clean
+
+all: $(PROGRAMS)
+
+trace_schema_validator: fetch_deps trace_schema_validator.go
+	$(GOBUILD) -o trace_schema_validator
+
+fetch_deps:
+	$(GOGET) github.com/xeipuuv/gojsonschema
+
+clean:
+	$(RM) $(PROGRAMS)
diff --git a/t/trace_schema_validator/trace_schema_validator.go b/t/trace_schema_validator/trace_schema_validator.go
new file mode 100644
index 0000000000..bfda3c405e
--- /dev/null
+++ b/t/trace_schema_validator/trace_schema_validator.go
@@ -0,0 +1,82 @@ 
+// trace_schema_validator validates individual lines of an input file against a
+// provided JSON-Schema for git trace2 event output.
+//
+// Note that this expects each object to validate to be on its own line in the
+// input file (AKA JSON-Lines format). This is what Git natively writes with
+// GIT_TRACE2_EVENT enabled.
+//
+// Traces can be collected by setting the GIT_TRACE2_EVENT environment variable
+// to an absolute path and running any Git command; traces will be appended to
+// the file.
+//
+// Traces can then be verified like so:
+//   trace_schema_validator \
+//     --trace2-event-file /path/to/trace/output \
+//     --schema-file /path/to/schema
+package main
+
+import (
+	"bufio"
+	"flag"
+	"log"
+	"os"
+	"path/filepath"
+
+	"github.com/xeipuuv/gojsonschema"
+)
+
+// Required flags
+var schemaFile = flag.String("schema-file", "", "JSON-Schema filename")
+var trace2EventFile = flag.String("trace2-event-file", "", "trace2 event filename")
+var progress = flag.Int("progress", 0, "Print progress message each time we have validated this many lines. --progress=0 means no messages are printed")
+
+func main() {
+	flag.Parse()
+	if *schemaFile == "" || *trace2EventFile == "" {
+		log.Fatal("Both --schema-file and --trace2-event-file are required.")
+	}
+	schemaURI, err := filepath.Abs(*schemaFile)
+	if err != nil {
+		log.Fatal("Can't get absolute path for schema file: ", err)
+	}
+	schemaURI = "file://" + schemaURI
+
+	schemaLoader := gojsonschema.NewReferenceLoader(schemaURI)
+	schema, err := gojsonschema.NewSchema(schemaLoader)
+	if err != nil {
+		log.Fatal("Problem loading schema: ", err)
+	}
+
+	tracesFile, err := os.Open(*trace2EventFile)
+	if err != nil {
+		log.Fatal("Problem opening trace file: ", err)
+	}
+	defer tracesFile.Close()
+
+	scanner := bufio.NewScanner(tracesFile)
+
+	count := 0
+	for ; scanner.Scan(); count++ {
+		if *progress != 0 && count%*progress == 0 {
+			log.Print("Validated items: ", count)
+		}
+		event := gojsonschema.NewStringLoader(scanner.Text())
+		result, err := schema.Validate(event)
+		if err != nil {
+			log.Fatal(err)
+		}
+		if !result.Valid() {
+			log.Printf("Trace event line %d is invalid: %s", count+1, scanner.Text())
+			for _, desc := range result.Errors() {
+				log.Print("- ", desc)
+			}
+			os.Exit(1)
+		}
+	}
+
+	if err := scanner.Err(); err != nil {
+		log.Fatal("Scanning error: ", err)
+	}
+
+	log.Print("Validated events: ", count)
+}