Skip to content
This repository has been archived by the owner on Feb 17, 2024. It is now read-only.

Commit

Permalink
Merge pull request #24 from stealthrocket/cli-tests
Browse files Browse the repository at this point in the history
timecraft: add tests for CLI
  • Loading branch information
achille-roussel committed May 27, 2023
2 parents 68c28f3 + e32adcd commit e060ed1
Show file tree
Hide file tree
Showing 23 changed files with 264 additions and 135 deletions.
14 changes: 11 additions & 3 deletions Makefile
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
.PHONY: clean flatbuffers generate test
.PHONY: clean flatbuffers generate test testdata
.PRECIOUS: %.wasm

testdata.go.src = $(wildcard testdata/go/*.go)
testdata.go.wasm = $(testdata.go.src:.go=.wasm)

format.src.fbs = \
$(wildcard format/*/*.fbs)
format.src.go = \
Expand All @@ -16,16 +19,21 @@ timecraft: go.mod $(timecraft.src.go)
go build -o timecraft

clean:
rm -f timecraft $(format.src.go)
rm -f timecraft $(format.src.go) $(testdata.go.wasm)

generate: flatbuffers

flatbuffers: go.mod $(format.src.go)
go build ./format/...

test: flatbuffers
test: flatbuffers testdata
go test -v ./...

testdata: $(testdata.go.wasm)

testdata/go/%.wasm: testdata/go/%.go
GOARCH=wasm GOOS=wasip1 gotip build -o $@ $<

# We run goimports because the flatc compiler sometimes adds an unused import of
# strconv.
%_generated.go: %.fbs
Expand Down
2 changes: 1 addition & 1 deletion format/logcache/logcache.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ namespace logcache;
//
// The file is designed to contain one or more records. The intent is to
// support grouping together caches of records that are likely to be accessed
// together (e.g. multiple stages of a transation). Bulk lookup operations
// together (e.g. multiple stages of a transaction). Bulk lookup operations
// can then hit a single record set, which causes a single update of the LRU
// and single access to the storage layer.
table RecordSet {
Expand Down
2 changes: 1 addition & 1 deletion format/logsegment/logsegment.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ table RecordBatch {
compression:types.Compression;
}

// The Record table holds metdata about the recording of a single host function
// The Record table holds metadata about the recording of a single host function
// call.
table Record {
// Monotonic timestamp relative to the process start time of the function
Expand Down
6 changes: 3 additions & 3 deletions format/logsnapshot/logsnapshot.fbs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ include "../types/types.fbs";

namespace logsnapshot;

// RecordRange represents the snapshot of mutations that occured over a
// RecordRange represents the snapshot of mutations that occurred over a
// range of log records.
table RecordRange {
// Unique identifier of the process that the range was snapshot was generated
Expand All @@ -26,10 +26,10 @@ table RecordRange {
uncompressed_size:uint;
// Compression algorithm used to encode the record range data sections.
compression:types.Compression;
// CRC32 cheksum of the record range data section (Castagnoli).
// CRC32 checksum of the record range data section (Castagnoli).
checksum:uint;
// Unique identifier for the OCI layer which records the file system mutations
// that occured through the file range.
// that occurred through the file range.
oci_layer:types.Hash;
// List of files opened at the end the range.
open_files:[OpenFile];
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/help.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For a description of each command, run 'timecraft help <command>'.`

func help(ctx context.Context, args []string) error {
flagSet := newFlagSet("timecraft help", helpUsage)
flagSet.Parse(args)
parseFlags(flagSet, args)

var cmd string
var msg string
Expand Down
2 changes: 1 addition & 1 deletion internal/cmd/profile.go
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ func profile(ctx context.Context, args []string) error {
stringVar(flagSet, &cpuProfile, "cpuprofile")
stringVar(flagSet, &memProfile, "memprofile")
stringVar(flagSet, &registryPath, "r", "registry")
flagSet.Parse(args)
parseFlags(flagSet, args)

if time.Time(startTime).IsZero() {
startTime = timestamp(time.Unix(0, 0))
Expand Down
39 changes: 39 additions & 0 deletions internal/cmd/profile_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package cmd_test

import (
"context"

"github.com/stealthrocket/timecraft/internal/cmd"
)

func ExampleRoot_profileMissingID() {
ctx := context.Background()

FAIL(cmd.Root(ctx, "profile"))
// Output:
// ERR: timecraft profile: expected exactly one process id as argument
}

func ExampleRoot_profileTooManyArgs() {
ctx := context.Background()

FAIL(cmd.Root(ctx, "profile", "1", "2", "3"))
// Output:
// ERR: timecraft profile: expected exactly one process id as argument
}

func ExampleRoot_profileInvalidID() {
ctx := context.Background()

FAIL(cmd.Root(ctx, "profile", "1234567890"))
// Output:
// ERR: timecraft profile: malformed process id passed as argument (not a UUID)
}

func ExampleRoot_profileUnknownID() {
ctx := context.Background()

FAIL(cmd.Root(ctx, "profile", "b0f4dac5-9855-4cde-89fd-ebd3713c2249"))
// Output:
// ERR: timecraft profile: process has no records: b0f4dac5-9855-4cde-89fd-ebd3713c2249
}
2 changes: 1 addition & 1 deletion internal/cmd/replay.go
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ func replay(ctx context.Context, args []string) error {
flagSet := newFlagSet("timecraft replay", replayUsage)
stringVar(flagSet, &registryPath, "r", "registry")
boolVar(flagSet, &trace, "T", "trace")
flagSet.Parse(args)
parseFlags(flagSet, args)

args = flagSet.Args()
if len(args) != 1 {
Expand Down
13 changes: 10 additions & 3 deletions internal/cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -66,9 +66,9 @@ func init() {
}

// Root is the timecraft entrypoint.
func Root(ctx context.Context, args []string) int {
func Root(ctx context.Context, args ...string) int {
flagSet := newFlagSet("timecraft", helpUsage)
flagSet.Parse(args)
parseFlags(flagSet, args)

if args = flagSet.Args(); len(args) == 0 {
fmt.Println(rootUsage)
Expand Down Expand Up @@ -98,7 +98,7 @@ func Root(ctx context.Context, args []string) int {
case ExitCode:
return int(e)
default:
fmt.Fprintf(os.Stderr, "ERR: timecraft %s: %s\n", cmd, err)
fmt.Printf("ERR: timecraft %s: %s\n", cmd, err)
return 1
}
}
Expand Down Expand Up @@ -175,6 +175,13 @@ func newFlagSet(cmd, usage string) *flag.FlagSet {
return flagSet
}

func parseFlags(f *flag.FlagSet, args []string) {
// The flag set is consutrcted with ExitOnError, it should never error.
if err := f.Parse(args); err != nil {
panic(err)
}
}

func customVar(f *flag.FlagSet, dst flag.Value, name string, alias ...string) {
f.Var(dst, name, "")
for _, name := range alias {
Expand Down
18 changes: 18 additions & 0 deletions internal/cmd/root_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package cmd_test

import (
"fmt"
"os"
)

func PASS(rc int) {
if rc != 0 {
fmt.Fprintf(os.Stderr, "exit: %d\n", rc)
}
}

func FAIL(rc int) {
if rc != 1 {
fmt.Fprintf(os.Stderr, "exit: %d\n", rc)
}
}
29 changes: 19 additions & 10 deletions internal/cmd/run.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ func run(ctx context.Context, args []string) error {
boolVar(flagSet, &record, "R", "record")
intVar(flagSet, &batchSize, "record-batch-size")
stringVar(flagSet, &compression, "record-compression")
flagSet.Parse(args)
parseFlags(flagSet, args)

envs = append(os.Environ(), envs...)
args = flagSet.Args()
Expand Down Expand Up @@ -90,13 +90,20 @@ func run(ctx context.Context, args []string) error {
}
defer wasmModule.Close(ctx)

// When running cmd.Root from testable examples, the standard streams are
// not set to alternative files and the fd numbers are not 0, 1, 2.
stdin := int(os.Stdin.Fd())
stdout := int(os.Stdout.Fd())
stderr := int(os.Stderr.Fd())

builder := imports.NewBuilder().
WithName(wasmName).
WithArgs(args...).
WithArgs(args[1:]...).
WithEnv(envs...).
WithDirs("/").
WithListens(listens...).
WithDials(dials...).
WithStdio(stdin, stdout, stderr).
WithSocketsExtension(sockets, wasmModule).
WithTracer(trace, os.Stderr)

Expand Down Expand Up @@ -204,14 +211,16 @@ func exec(ctx context.Context, runtime wazero.Runtime, compiledModule wazero.Com

<-ctx.Done()

switch err := context.Cause(ctx).(type) {
case nil:
err = context.Cause(ctx)
switch err {
case context.Canceled, context.DeadlineExceeded:
err = nil
}

switch e := err.(type) {
case *sys.ExitError:
if exitCode := err.ExitCode(); exitCode != 0 {
return ExitCode(exitCode)
}
default:
return err
return ExitCode(e.ExitCode())
}
return nil

return err
}
22 changes: 22 additions & 0 deletions internal/cmd/run_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package cmd_test

import (
"context"

"github.com/stealthrocket/timecraft/internal/cmd"
)

func ExampleRoot_runExitZero() {
ctx := context.Background()

PASS(cmd.Root(ctx, "run", "../../testdata/go/sleep.wasm", "10ms"))
// Output: sleeping for 10ms
}

func ExampleRoot_runContextCanceled() {
ctx, cancel := context.WithCancel(context.Background())
cancel()

PASS(cmd.Root(ctx, "run", "../../testdata/go/sleep.wasm", "10s"))
// Output:
}
11 changes: 8 additions & 3 deletions internal/cmd/version.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,15 +15,20 @@ Options:

func version(ctx context.Context, args []string) error {
flagSet := newFlagSet("timecraft version", versionUsage)
flagSet.Parse(args)
parseFlags(flagSet, args)
fmt.Printf("timecraft %s\n", currentVersion())
return nil
}

func currentVersion() string {
version := "devel"
if info, ok := debug.ReadBuildInfo(); ok && info.Main.Version != "(devel)" {
version = info.Main.Version
if info, ok := debug.ReadBuildInfo(); ok {
switch info.Main.Version {
case "":
case "(devel)":
default:
version = info.Main.Version
}
}
return version
}
15 changes: 15 additions & 0 deletions internal/cmd/version_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
package cmd_test

import (
"context"

"github.com/stealthrocket/timecraft/internal/cmd"
)

func ExampleRoot_version() {
ctx := context.Background()

PASS(cmd.Root(ctx, "version"))
// Output:
// timecraft devel
}
2 changes: 1 addition & 1 deletion internal/object/store.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ import (
)

var (
// ErrNotExist is an error value which may be tested aginst to determine
// ErrNotExist is an error value which may be tested against to determine
// whether a method invocation from a Store instance failed due to being
// called on an object which did not exist.
ErrNotExist = fs.ErrNotExist
Expand Down
10 changes: 6 additions & 4 deletions internal/object/store_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ func testObjectStore(t *testing.T, newStore func(*testing.T) (object.Store, func
},

{
scenario: "deleting non existing objects from an emtpy store",
scenario: "deleting non existing objects from an empty store",
function: testObjectStoreDeleteEmpty,
},

Expand Down Expand Up @@ -172,7 +172,8 @@ func testObjectStoreListWhileCreate(t *testing.T, ctx context.Context, store obj
assert.OK(t, store.CreateObject(ctx, "test-3", r))
}()

io.WriteString(w, "H")
_, err := io.WriteString(w, "H")
assert.OK(t, err)

beforeCreateObject := readValues(t, store.ListObjects(ctx, "."))
clearCreatedAt(beforeCreateObject)
Expand All @@ -183,8 +184,9 @@ func testObjectStoreListWhileCreate(t *testing.T, ctx context.Context, store obj
{Name: "test-2", Size: 1},
})

io.WriteString(w, "ello World!")
w.Close()
_, err = io.WriteString(w, "ello World!")
assert.OK(t, err)
assert.OK(t, w.Close())
<-done

afterCreateObject := readValues(t, store.ListObjects(ctx, "."))
Expand Down
4 changes: 2 additions & 2 deletions internal/stream/stream.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import "io"
// of type T.
type Reader[T any] interface {
// Reads values from the stream, returning the number of values read and any
// error that occured.
// error that occurred.
//
// The error is io.EOF when the end of the stream has been reached.
Read(values []T) (int, error)
Expand Down Expand Up @@ -62,7 +62,7 @@ func (r *nopCloser[T]) Close() error { return nil }
func (r *nopCloser[T]) Read(values []T) (int, error) { return r.reader.Read(values) }

// ReadAll reads all values from r and returns them as a slice, along with any
// error that occured (other than io.EOF).
// error that occurred (other than io.EOF).
func ReadAll[T any](r Reader[T]) ([]T, error) {
values := make([]T, 0, 1)
for {
Expand Down
Loading

0 comments on commit e060ed1

Please sign in to comment.