From 3c1fbe902092d53b2d8112669d1e62566e8c8977 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Sun, 3 May 2020 06:10:51 -0700 Subject: [PATCH 01/11] Git Smash --- Makefile | 28 ++++++++++++++++++++ OWNERS | 1 + orcareduce/director/director.go | 45 +++++++++++++++++++++++++++++++++ orcareduce/exceptions/errors.go | 7 +++++ orcareduce/iface.go | 26 +++++++++++++++++++ 5 files changed, 107 insertions(+) create mode 100644 Makefile create mode 100644 OWNERS create mode 100644 orcareduce/director/director.go create mode 100644 orcareduce/exceptions/errors.go create mode 100644 orcareduce/iface.go diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..4d868dd --- /dev/null +++ b/Makefile @@ -0,0 +1,28 @@ +.PHONY: bootstrap +bootstrap: + go get -u github.com/golangci/golangci-lint/cmd/golangci-lint + go get -u github.com/kyoh86/richgo + go get -v github.com/ramya-rao-a/go-outline + go get -v github.com/mdempsky/gocode + go get -v github.com/uudashr/gopkgs/cmd/gopkgs + go get -v golang.org/x/tools/cmd/goimports + +.PHONY: lint +lint: fmt + golangci-lint run + +.PHONY: test-ci +test-ci: + @echo "tests:" + go test -v -covermode=count -coverprofile=data/coverage.out ./data/... + go test -v -covermode=count -coverprofile=brewery/coverage.out ./brewery/... + +.PHONY: install-golang-ci +lint-ci: + curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh + +.PHONY: fmt +fmt: + @echo "fmt:" + scripts/fmt + diff --git a/OWNERS b/OWNERS new file mode 100644 index 0000000..86aa9e6 --- /dev/null +++ b/OWNERS @@ -0,0 +1 @@ +mkuchenbecker \ No newline at end of file diff --git a/orcareduce/director/director.go b/orcareduce/director/director.go new file mode 100644 index 0000000..7b47d99 --- /dev/null +++ b/orcareduce/director/director.go @@ -0,0 +1,45 @@ +package prod + +import ( + "github.com/mkuchenbecker/orcareduce/orcareduce" + "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" + "golang.org/pkg/errors" +) + +type queueDirector struct { + actors []orcareduce.Reactor +} + +func (d * queueDirector) GetNextActor() (actor orcareduce.Reactor, err error) { + if len(d.actors) == 0 { + return nil, exceptions.ErrActorsDepleted + } + actor = d.actors[0] + return actor,nil +} + + +func (d *queueDirector) Direct() (err error) { + defer func() { + err = errors.Wrap(err,"unable to direct") + } + actor, err := d.GetNextActor() + if err != nil { + return err + } + err = actor.Preconditions() + if err != nil { + return err + } + err = actor.Act() + if err != nil { + return err + } + err = actor.SignalSuccess() + if err != nil { + return err + } + actor.Notify() + + return nil +} \ No newline at end of file diff --git a/orcareduce/exceptions/errors.go b/orcareduce/exceptions/errors.go new file mode 100644 index 0000000..f7476fd --- /dev/null +++ b/orcareduce/exceptions/errors.go @@ -0,0 +1,7 @@ +package exceptions + +import "fmt" + +var ( + ErrActorsDepleted = fmt.Errorf("actors depleted") +) diff --git a/orcareduce/iface.go b/orcareduce/iface.go new file mode 100644 index 0000000..cf005d6 --- /dev/null +++ b/orcareduce/iface.go @@ -0,0 +1,26 @@ +package orcareduce + +// Reactor is a repeatable actor. +type Reactor interface { + Preconditions() error + Act() error + SignalSuccess() error + Notify() + ID() ID +} + +type Precondition interface { + Check() error +} + +// ID is a generalized interface for identifying reactors. +type ID interface { + String() string + Bytes() []byte + Parent() ID +} + +type Director interface { + GetNextActor() error + Act() error +} From 407e999436192bd1dfb7d38fbec51dc31613b892 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Sun, 3 May 2020 06:55:02 -0700 Subject: [PATCH 02/11] . --- go.mod | 5 ++++ go.sum | 2 ++ orcareduce/director/director.go | 43 +++++++++++++++++++++++---------- orcareduce/exceptions/errors.go | 8 ++++++ 4 files changed, 45 insertions(+), 13 deletions(-) create mode 100644 go.mod create mode 100644 go.sum diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..017eb22 --- /dev/null +++ b/go.mod @@ -0,0 +1,5 @@ +module github.com/mkuchenbecker/orcareduce + +go 1.13 + +require github.com/pkg/errors v0.9.1 diff --git a/go.sum b/go.sum new file mode 100644 index 0000000..7c401c3 --- /dev/null +++ b/go.sum @@ -0,0 +1,2 @@ +github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= +github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= diff --git a/orcareduce/director/director.go b/orcareduce/director/director.go index 7b47d99..911eb8f 100644 --- a/orcareduce/director/director.go +++ b/orcareduce/director/director.go @@ -3,33 +3,41 @@ package prod import ( "github.com/mkuchenbecker/orcareduce/orcareduce" "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" - "golang.org/pkg/errors" + "github.com/pkg/errors" ) -type queueDirector struct { - actors []orcareduce.Reactor + + +type config struct { + retries int + backoffFactor int } -func (d * queueDirector) GetNextActor() (actor orcareduce.Reactor, err error) { - if len(d.actors) == 0 { - return nil, exceptions.ErrActorsDepleted - } - actor = d.actors[0] - return actor,nil +func (c *config) Backoff(retry int) time.Duration { + return math.Max(1,2) * time.Second } +func (c *config) Retries() int { + +} -func (d *queueDirector) Direct() (err error) { + +type director struct { + actor orcareduce.Reactor + cfg config +} + +func (d *director) Direct() (err error) { defer func() { err = errors.Wrap(err,"unable to direct") - } + }() actor, err := d.GetNextActor() if err != nil { return err } err = actor.Preconditions() if err != nil { - return err + return exceptions.PreconditionError(err.Error()) } err = actor.Act() if err != nil { @@ -42,4 +50,13 @@ func (d *queueDirector) Direct() (err error) { actor.Notify() return nil -} \ No newline at end of file +} + + +func (d *director) Run() { + for i:= 0; i < d.config.Retries(); i++ { + + + } +} + diff --git a/orcareduce/exceptions/errors.go b/orcareduce/exceptions/errors.go index f7476fd..ad6828f 100644 --- a/orcareduce/exceptions/errors.go +++ b/orcareduce/exceptions/errors.go @@ -4,4 +4,12 @@ import "fmt" var ( ErrActorsDepleted = fmt.Errorf("actors depleted") + ErrPreconditionsNotMet = fmt.Errorf("preconditions not met") ) + + +type PreconditionError string + +func (err PreconditionError) Error() string { + return fmt.Sprintf("preconditions not met: %s", err) +} \ No newline at end of file From f44f2c0bab39166c424490a746fcf58c501b74e8 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Thu, 21 May 2020 13:46:37 -0700 Subject: [PATCH 03/11] injector --- go.mod | 5 ++++- go.sum | 11 +++++++++++ 2 files changed, 15 insertions(+), 1 deletion(-) diff --git a/go.mod b/go.mod index 017eb22..8e54a22 100644 --- a/go.mod +++ b/go.mod @@ -2,4 +2,7 @@ module github.com/mkuchenbecker/orcareduce go 1.13 -require github.com/pkg/errors v0.9.1 +require ( + github.com/pkg/errors v0.9.1 + github.com/stretchr/testify v1.5.1 +) diff --git a/go.sum b/go.sum index 7c401c3..ddf632a 100644 --- a/go.sum +++ b/go.sum @@ -1,2 +1,13 @@ +github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= +github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= +github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= +github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= +github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= +gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= From d54e0f0a0d64f2156409ba7fbc2f453a51cc58b6 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Wed, 17 Jun 2020 08:05:11 -0700 Subject: [PATCH 04/11] checkpoint --- go.mod | 1 + go.sum | 323 ++++++++++++++++++++++++++++ orcareduce/chaos/chaos.go | 104 +++++++++ orcareduce/chaos/chaos_test.go | 26 +++ orcareduce/chaos/iface.go | 14 ++ orcareduce/director/director.go | 58 +++-- orcareduce/director/influx.go | 182 ++++++++++++++++ orcareduce/effsleep/channel.go | 98 +++++++++ orcareduce/effsleep/channel_test.go | 40 ++++ orcareduce/effsleep/doc.go | 7 + orcareduce/exceptions/errors.go | 77 ++++++- orcareduce/iface.go | 80 ++++++- orcareduce/state/datastore.go | 104 +++++++++ 13 files changed, 1087 insertions(+), 27 deletions(-) create mode 100644 orcareduce/chaos/chaos.go create mode 100644 orcareduce/chaos/chaos_test.go create mode 100644 orcareduce/chaos/iface.go create mode 100644 orcareduce/director/influx.go create mode 100644 orcareduce/effsleep/channel.go create mode 100644 orcareduce/effsleep/channel_test.go create mode 100644 orcareduce/effsleep/doc.go create mode 100644 orcareduce/state/datastore.go diff --git a/go.mod b/go.mod index 8e54a22..29a5dac 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/mkuchenbecker/orcareduce go 1.13 require ( + github.com/influxdata/influxdb v1.8.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.5.1 ) diff --git a/go.sum b/go.sum index ddf632a..6215109 100644 --- a/go.sum +++ b/go.sum @@ -1,13 +1,336 @@ +cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.34.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.38.0/go.mod h1:990N+gfupTy94rShfmMCWGDn0LpTmnzTp2qbd1dvSRU= +cloud.google.com/go v0.43.0/go.mod h1:BOSR3VbTLkk6FDC/TcffxP4NF/FFBGA5ku+jvKOP7pg= +cloud.google.com/go v0.44.1/go.mod h1:iSa0KzasP4Uvy3f1mN/7PiObzGgflwredwwASm/v6AU= +cloud.google.com/go v0.44.2/go.mod h1:60680Gw3Yr4ikxnPRS/oxxkBccT6SA1yMk63TGekxKY= +cloud.google.com/go v0.45.1/go.mod h1:RpBamKRgapWJb87xiFSdk4g1CME7QZg3uwTez+TSTjc= +cloud.google.com/go v0.46.3/go.mod h1:a6bKKbmY7er1mI7TEI4lsAkts/mkhTSZK8w33B4RAg0= +cloud.google.com/go v0.50.0/go.mod h1:r9sluTvynVuxRIOHXQEHMFffphuXHOMZMycpNR5e6To= +cloud.google.com/go v0.51.0/go.mod h1:hWtGJ6gnXH+KgDv+V0zFGDvpi07n3z8ZNj3T1RW0Gcw= +cloud.google.com/go/bigquery v1.0.1/go.mod h1:i/xbL2UlR5RvWAURpBYZTtm/cXjCha9lbfbpx4poX+o= +cloud.google.com/go/bigquery v1.3.0/go.mod h1:PjpwJnslEMmckchkHFfq+HTD2DmtT67aNFKH1/VBDHE= +cloud.google.com/go/bigtable v1.2.0/go.mod h1:JcVAOl45lrTmQfLj7T6TxyMzIN/3FGGcFm+2xVAli2o= +cloud.google.com/go/datastore v1.0.0/go.mod h1:LXYbyblFSglQ5pkeyhO+Qmw7ukd3C+pD7TKLgZqpHYE= +cloud.google.com/go/pubsub v1.0.1/go.mod h1:R0Gpsv3s54REJCy4fxDixWD93lHJMoZTyQ2kNxGRt3I= +cloud.google.com/go/pubsub v1.1.0/go.mod h1:EwwdRX2sKPjnvnqCa270oGRyludottCI76h+R3AArQw= +cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= +cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= +collectd.org v0.3.0/go.mod h1:A/8DzQBkF6abtvrT2j/AU/4tiBgJWYyh0y/oB/4MlWE= +dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= +github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= +github.com/OneOfOne/xxhash v1.2.2/go.mod h1:HSdplMjZKSmBqAxg5vPj2TmRDmfkzw+cTzAElWljhcU= +github.com/ajstarks/svgo v0.0.0-20180226025133-644b8db467af/go.mod h1:K08gAheRH3/J6wwsYMMT4xOr94bZjxIelGM0+d/wbFw= +github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= +github.com/alecthomas/units v0.0.0-20151022065526-2efee857e7cf/go.mod h1:ybxpYRFXyAe+OPACYpWeL0wqObRcbAqCMya13uyzqw0= +github.com/andreyvit/diff v0.0.0-20170406064948-c7f18ee00883/go.mod h1:rCTlJbsFo29Kk6CurOXKm700vrz8f0KW0JNfpkRJY/8= +github.com/apache/arrow/go/arrow v0.0.0-20191024131854-af6fa24be0db/go.mod h1:VTxUBvSJ3s3eHAg65PNgrsn5BtqCRPdmyXh6rAfdxN0= +github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= +github.com/beorn7/perks v1.0.0/go.mod h1:KWe93zE9D1o94FZ5RNwFwVgaQK1VOXiVxmqh+CedLV8= +github.com/bmizerany/pat v0.0.0-20170815010413-6226ea591a40/go.mod h1:8rLXio+WjiTceGBHIoTvn60HIbs7Hm7bcHjyrSqYB9c= +github.com/boltdb/bolt v1.3.1/go.mod h1:clJnj/oiGkjum5o1McbSZDSLxVThjynRyGBgiAx27Ps= +github.com/c-bata/go-prompt v0.2.2/go.mod h1:VzqtzE2ksDBcdln8G7mk2RX9QyGjH+OVqOCSiVIqS34= +github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= +github.com/cespare/xxhash v1.1.0/go.mod h1:XrSqR1VqqWfGrhpAt58auRo0WTKS1nRRg3ghfAqPWnc= +github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= +github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= +github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= +github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/dave/jennifer v1.2.0/go.mod h1:fIb+770HOpJ2fmN9EPPKOqm1vMGhB+TwXKMZhrIygKg= github.com/davecgh/go-spew v1.1.0 h1:ZDRjVQ15GmhC3fiQ8ni8+OwkZQO4DARzQgrnXU1Liz8= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= +github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= +github.com/dgryski/go-bitstream v0.0.0-20180413035011-3522498ce2c8/go.mod h1:VMaSuZ+SZcx/wljOQKvp5srsbCiKDEb6K2wC4+PiBmQ= +github.com/eclipse/paho.mqtt.golang v1.2.0/go.mod h1:H9keYFcgq3Qr5OUJm/JZI/i6U7joQ8SYLhZwfeOo6Ts= +github.com/envoyproxy/go-control-plane v0.9.1-0.20191026205805-5f8ba28d4473/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= +github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= +github.com/fogleman/gg v1.2.1-0.20190220221249-0403632d5b90/go.mod h1:R/bRT+9gY/C5z7JzPU0zXsXHKM4/ayA+zqcVNZzPa1k= +github.com/glycerine/go-unsnap-stream v0.0.0-20180323001048-9f0cb55181dd/go.mod h1:/20jfyN9Y5QPEAprSgKAUr+glWDY39ZiUEAYOEv5dsE= +github.com/glycerine/goconvey v0.0.0-20190410193231-58a59202ab31/go.mod h1:Ogl1Tioa0aV7gstGFO7KhffUsb9M4ydbEbbxpcEDc24= +github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= +github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= +github.com/go-kit/kit v0.8.0/go.mod h1:xBxKIO96dXMWWy0MnWVtmwkA9/13aqxPnvrjFYMA2as= +github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9GBnD5lWE= +github.com/go-logfmt/logfmt v0.4.0/go.mod h1:3RMwSq7FuexP4Kalkev3ejPJsZTpXXBr9+V4qmtdjCk= +github.com/go-sql-driver/mysql v1.4.1/go.mod h1:zAC/RDZ24gD3HViQzih4MyKcchzm+sOG5ZlKdlhCg5w= +github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/melR3HDY= +github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= +github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= +github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= +github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= +github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= +github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= +github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= +github.com/google/flatbuffers v1.11.0/go.mod h1:1AeVuKshWv4vARoZatz6mlQ0JxURH0Kv5+zNeJKJCa8= +github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= +github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU= +github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= +github.com/google/martian v2.1.0+incompatible/go.mod h1:9I4somxYTbIHy5NJKHRl3wXiIaQGbYVAs8BPL6v8lEs= +github.com/google/pprof v0.0.0-20181206194817-3ea8567a2e57/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20190515194954-54271f7e092f/go.mod h1:zfwlbNMJ+OItoe0UupaVj+oy1omPYYDuagoSzA8v9mc= +github.com/google/pprof v0.0.0-20191218002539-d4f498aebedc/go.mod h1:ZgVRPoUq/hfqzAqh7sHMqb3I9Rq5C59dIz2SbBwJ4eM= +github.com/google/renameio v0.1.0/go.mod h1:KWCgfxg9yswjAJkECMjeO8J8rahYeXnNhOm40UhjYkI= +github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= +github.com/googleapis/gax-go/v2 v2.0.5/go.mod h1:DWXyrwAJ9X0FpwwEdw+IPEYBICEFu5mhpdKc/us6bOk= +github.com/gopherjs/gopherjs v0.0.0-20181017120253-0766667cb4d1/go.mod h1:wJfORRmW1u3UXTncJ5qlYoELFm8eSnnEO6hX4iZ3EWY= +github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/ianlancetaylor/demangle v0.0.0-20181102032728-5e5cf60278f6/go.mod h1:aSSvb/t6k1mPoxDqO4vJh6VOCGPwU4O0C2/Eqndh1Sc= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= +github.com/influxdata/flux v0.65.0/go.mod h1:BwN2XG2lMszOoquQaFdPET8FRQfrXiZsWmcMO9rkaVY= +github.com/influxdata/influxdb v1.8.0 h1:/X+G+i3udzHVxpBMuXdPZcUbkIE0ouT+6U+CzQTsOys= +github.com/influxdata/influxdb v1.8.0/go.mod h1:SIzcnsjaHRFpmlxpJ4S3NT64qtEKYweNTUMb/vh0OMQ= +github.com/influxdata/influxql v1.1.0/go.mod h1:KpVI7okXjK6PRi3Z5B+mtKZli+R1DnZgb3N+tzevNgo= +github.com/influxdata/line-protocol v0.0.0-20180522152040-32c6aa80de5e/go.mod h1:4kt73NQhadE3daL3WhR5EJ/J2ocX0PZzwxQ0gXJ7oFE= +github.com/influxdata/promql/v2 v2.12.0/go.mod h1:fxOPu+DY0bqCTCECchSRtWfc+0X19ybifQhZoQNF5D8= +github.com/influxdata/roaring v0.4.13-0.20180809181101-fc520f41fab6/go.mod h1:bSgUQ7q5ZLSO+bKBGqJiCBGAl+9DxyW63zLTujjUlOE= +github.com/influxdata/tdigest v0.0.0-20181121200506-bf2b5ad3c0a9/go.mod h1:Js0mqiSBE6Ffsg94weZZ2c+v/ciT8QRHFOap7EKDrR0= +github.com/influxdata/usage-client v0.0.0-20160829180054-6d3895376368/go.mod h1:Wbbw6tYNvwa5dlB6304Sd+82Z3f7PmVZHVKU637d4po= +github.com/json-iterator/go v1.1.6/go.mod h1:+SdeFBvtyEkXs7REEP0seUULqWtbJapLOCVDaaPEHmU= +github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= +github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= +github.com/jsternberg/zap-logfmt v1.0.0/go.mod h1:uvPs/4X51zdkcm5jXl5SYoN+4RK21K8mysFmDaM/h+o= +github.com/jtolds/gls v4.20.0+incompatible/go.mod h1:QJZ7F/aHp+rZTRtaJ1ow/lLfFfVYBRgL+9YlvaHOwJU= +github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/jung-kurt/gofpdf v1.0.3-0.20190309125859-24315acbbda5/go.mod h1:7Id9E/uU8ce6rXgefFLlgrJj/GYY22cpxn+r32jIOes= +github.com/jwilder/encoding v0.0.0-20170811194829-b4e1701a28ef/go.mod h1:Ct9fl0F6iIOGgxJ5npU/IUOhOhqlVrGjyIZc8/MagT0= +github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= +github.com/klauspost/compress v1.4.0/go.mod h1:RyIbtBH6LamlWaDj8nUwkbUhJ87Yi3uG0guNDohfE1A= +github.com/klauspost/cpuid v0.0.0-20170728055534-ae7887de9fa5/go.mod h1:Pj4uuM528wm8OyEC2QMXAi2YiTZ96dNQPGgoMS4s3ek= +github.com/klauspost/crc32 v0.0.0-20161016154125-cb6bfca970f6/go.mod h1:+ZoRqAPRLkC4NPOvfYeR5KNOrY6TD+/sAC3HXPZgDYg= +github.com/klauspost/pgzip v1.0.2-0.20170402124221-0bf5dcad4ada/go.mod h1:Ch1tH69qFZu15pkjo5kYi6mth2Zzwzt50oCQKQE9RUs= +github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFBFZlji/RkVcI2GknAs/DXo4wKdlNEc= +github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo= +github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ= +github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI= +github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU= +github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4= +github.com/mattn/go-runewidth v0.0.3/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU= +github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= +github.com/mattn/go-tty v0.0.0-20180907095812-13ff1204f104/go.mod h1:XPvLUNfbS4fJH25nqRHfWLMa1ONC8Amw+mIA639KxkE= +github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v1.0.1/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= +github.com/mschoch/smat v0.0.0-20160514031455-90eadee771ae/go.mod h1:qAyveg+e4CE+eKJXWVjKXM4ck2QobLqTDytGJbLLhJg= +github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/opentracing/opentracing-go v1.0.2/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/opentracing/opentracing-go v1.0.3-0.20180606204148-bd9c31933947/go.mod h1:UkNAQd3GIcIGf0SeVgPpRdFStlNbqXla1AfSYxPUl2o= +github.com/paulbellamy/ratecounter v0.2.0/go.mod h1:Hfx1hDpSGoqxkVVpBi/IlYD7kChlfo5C6hzIHwPqfFE= +github.com/peterh/liner v1.0.1-0.20180619022028-8c1271fcf47f/go.mod h1:xIteQHvHuaLYG9IFj6mSxM0fCKrs34IrEQUhOYuGPHc= +github.com/philhofer/fwd v1.0.0/go.mod h1:gk3iGcWd9+svBvR0sR+KPcfE+RNWozjowpeBVG3ZVNU= +github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY= +github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/errors v0.8.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4= github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0= +github.com/pkg/term v0.0.0-20180730021639-bffc007b7fd5/go.mod h1:eCbImbZ95eXtAUIbLAuAVnBnwf83mjf6QIVH8SHYwqQ= github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= +github.com/prometheus/client_golang v0.9.1/go.mod h1:7SWBe2y4D6OKWSNQJUaRYU/AaXPKyh/dDVn+NZz0KFw= +github.com/prometheus/client_golang v1.0.0/go.mod h1:db9x61etRT2tGnBNRi70OPL5FsnadC4Ky3P0J6CfImo= +github.com/prometheus/client_model v0.0.0-20180712105110-5c3871d89910/go.mod h1:MbSGuTsp3dbXC40dX6PRTWyKYBIrTGTE9sqQNg2J8bo= +github.com/prometheus/client_model v0.0.0-20190129233127-fd36f4220a90/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/client_model v0.0.0-20190812154241-14fe0d1b01d4/go.mod h1:xMI15A0UPsDsEKsMN9yxemIoYk6Tm2C1GtYGdfGttqA= +github.com/prometheus/common v0.4.1/go.mod h1:TNfzLD0ON7rHzMJeJkieUDPYmFC7Snx/y86RQel1bk4= +github.com/prometheus/common v0.6.0/go.mod h1:eBmuwkDJBwy6iBfxCBob6t6dR6ENT/y+J+Zk0j9GMYc= +github.com/prometheus/procfs v0.0.0-20181005140218-185b4288413d/go.mod h1:c3At6R/oaqEKCNdg8wHV1ftS6bRYblBhIjjI8uT2IGk= +github.com/prometheus/procfs v0.0.2/go.mod h1:TjEm7ze935MbeOT/UhFTIMYKhuLP4wbCsTZCD3I8kEA= +github.com/retailnext/hllpp v1.0.1-0.20180308014038-101a6d2f8b52/go.mod h1:RDpi1RftBQPUCDRw6SmxeaREsAaRKnOclghuzp/WRzc= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/satori/go.uuid v1.2.1-0.20181028125025-b2ce2384e17b/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0= +github.com/segmentio/kafka-go v0.1.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/segmentio/kafka-go v0.2.0/go.mod h1:X6itGqS9L4jDletMsxZ7Dz+JFWxM6JHfPOCvTvk+EJo= +github.com/sergi/go-diff v1.0.0/go.mod h1:0CfEIISq7TuYL3j771MWULgwwjU+GofnZX9QAmXWZgo= +github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d/go.mod h1:OnSkiWE9lh6wB0YB77sQom3nweQdgAjqCqsofrRNTgc= +github.com/smartystreets/goconvey v1.6.4/go.mod h1:syvi0/a8iFYH4r/RixwvyeAJjdLS9QV7WQ/tjFTllLA= +github.com/spaolacci/murmur3 v0.0.0-20180118202830-f09979ecbc72/go.mod h1:JwIasOWyU6f++ZhiEuf87xNszmSA2myDM2Kzu9HwQUA= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.3/go.mod h1:1l0Ry5zgKvJasoi3XT1TypsSe7PqH0Sj9dhYf7v3XqQ= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= github.com/stretchr/objx v0.1.0 h1:4G4v2dO3VZwixGIRoQ5Lfboy6nUhCyYzaqnIAPPhYs4= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/objx v0.1.1/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= +github.com/stretchr/testify v1.2.0/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= +github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= +github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/stretchr/testify v1.5.1 h1:nOGnQDM7FYENwehXlg/kFVnos3rEvtKTjRvOWSzb6H4= github.com/stretchr/testify v1.5.1/go.mod h1:5W2xD1RspED5o8YsWQXVCued0rvSQ+mT+I5cxcmMvtA= +github.com/tinylib/msgp v1.0.2/go.mod h1:+d+yLhGm8mzTaHzB+wgMYrodPfmZrzkirds8fDWklFE= +github.com/willf/bitset v1.1.3/go.mod h1:RjeCKbqT1RxIR/KWY6phxZiaY1IyutSBfGjNPySAYV4= +github.com/xlab/treeprint v0.0.0-20180616005107-d6fb6747feb6/go.mod h1:ce1O1j6UtZfjr22oyGxGLbauSBp2YVXpARAosm7dHBg= +go.opencensus.io v0.21.0/go.mod h1:mSImk1erAIZhrmZN+AvHh14ztQfjbGwt4TtuofqLduU= +go.opencensus.io v0.22.0/go.mod h1:+kGneAE2xo2IficOXnaByMWTGM9T73dGwxeWcUqIpI8= +go.opencensus.io v0.22.2/go.mod h1:yxeiOL68Rb0Xd1ddK5vPZ/oVn4vY4Ynel7k9FzqtOIw= +go.uber.org/atomic v1.3.2/go.mod h1:gD2HeocX3+yG+ygLZcrzQJaqmWj9AIm7n08wl/qW/PE= +go.uber.org/multierr v1.1.0/go.mod h1:wR5kodmAFQ0UK8QlbwjlSNy0Z68gJhDJUG5sjR94q/0= +go.uber.org/zap v1.9.1/go.mod h1:vwi/ZaCAaUcBkycHslxD9B2zi4UTXhF60s6SWpuDF0Q= +golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190510104115-cbcb75029529/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20190605123033-f99c8df09eb5/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= +golang.org/x/exp v0.0.0-20180321215751-8460e604b9de/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20180807140117-3d87b88a115f/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190125153040-c74c464bbbf2/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= +golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= +golang.org/x/exp v0.0.0-20190829153037-c13cbed26979/go.mod h1:86+5VVa7VpoJ4kLfm080zCjGlMRFzhUhsZKEZO7MGek= +golang.org/x/exp v0.0.0-20191030013958-a1ab85dbe136/go.mod h1:JXzH8nQsPlswgeRAPE3MuO9GYsAcnJvJ4vnMwN/5qkY= +golang.org/x/exp v0.0.0-20191129062945-2f5052295587/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/exp v0.0.0-20191227195350-da58074b4299/go.mod h1:2RIsYlXP63K8oxa1u096TMicItID8zy7Y6sNkU49FU4= +golang.org/x/image v0.0.0-20180708004352-c73c2afc3b81/go.mod h1:ux5Hcp/YLpHSI86hEcLt0YII63i6oz57MZXIpbrjZUs= +golang.org/x/image v0.0.0-20190227222117-0694c2d4d067/go.mod h1:kZ7UVZpmo3dzQBMxlp+ypCbDeSB+sBbTgSJuh5dn5js= +golang.org/x/image v0.0.0-20190802002840-cff245a6509b/go.mod h1:FeLwcggjj3mMvU+oOTbSwawSJRM1uh48EjtB4UJZlP0= +golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190227174305-5b3e6a55c961/go.mod h1:wehouNa3lNwaWXcvxsM5YxQ5yQlVC4a0KAMCusXpPoU= +golang.org/x/lint v0.0.0-20190301231843-5614ed5bae6f/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= +golang.org/x/lint v0.0.0-20190313153728-d0100b6bd8b3/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190409202823-959b441ac422/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190909230951-414d861bb4ac/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20190930215403-16217165b5de/go.mod h1:6SW0HCj/g11FgYtHlgUYUwCkIfeOF89ocIRzGO/8vkc= +golang.org/x/lint v0.0.0-20191125180803-fdd1cda4f05f/go.mod h1:5qLYkcX4OjUUV8bRuDixDT3tpyyb+LUpUlRWLxfhWrs= +golang.org/x/mobile v0.0.0-20190312151609-d3739f865fa6/go.mod h1:z+o9i4GpDbdi3rU15maQ/Ox0txvL9dWGYEHz965HBQE= +golang.org/x/mobile v0.0.0-20190719004257-d2bd2a29d028/go.mod h1:E/iHnbuqvinMTCcRqshq8CkpyQDoeVncDDYHnLhea+o= +golang.org/x/mod v0.0.0-20190513183733-4bf6d317e70e/go.mod h1:mXi4GBBbnImb6dmsKGUJ2LatrhH/nqhxcFungHvyanc= +golang.org/x/mod v0.1.0/go.mod h1:0QHyrYULN0/3qlju5TqG8bIK38QM8yzMo5ekMj3DlcY= +golang.org/x/mod v0.1.1-0.20191105210325-c90efee705ee/go.mod h1:QqPTAvyqsEbceGzBzNggFXnrqF1CaUcvgkdR5Ot7KZg= +golang.org/x/net v0.0.0-20180724234803-3673e40ba225/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20180826012351-8a410e7b638d/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190213061140-3a22650c66bd/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4= +golang.org/x/net v0.0.0-20190311183353-d8887717615a/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190501004415-9ce7a6920f09/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190503192946-f4e77d36d62c/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg= +golang.org/x/net v0.0.0-20190603091049-60506f45cf65/go.mod h1:HSz+uSET+XFnRR8LxR5pz3Of3rY3CfYBVs4xY44aLks= +golang.org/x/net v0.0.0-20190613194153-d28f0bde5980/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20190724013045-ca1201d0de80/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/net v0.0.0-20191209160850-c0dbc17a3553/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= +golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= +golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20191202225959-858c2ad4c8b6/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= +golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20181221193216-37e7f081c4d4/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190227155943-e225da77a7e6/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sync v0.0.0-20190911185100-cd5d95a43a6e/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= +golang.org/x/sys v0.0.0-20180830151530-49385e6e1522/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190312061237-fead79001313/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190502145724-3ef323f4f1fd/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190507160741-ecd444e8653b/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190606165138-5da285871e9c/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190624142023-c5567b49c5d0/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190726091711-fc99dfbffb4e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191204072324-ce4227a45e2e/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20191228213918-04cbcbbfeed8/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20200107162124-548cf772de50/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= +golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk= +golang.org/x/time v0.0.0-20181108054448-85acf8d2951c/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/time v0.0.0-20190308202827-9d24e82272b4/go.mod h1:tRJNPiyCQ0inRvYxbN9jk5I+vvW/OXSQhTDSoE431IQ= +golang.org/x/tools v0.0.0-20180525024113-a5b4c53f6e8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190206041539-40960b6deb8e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ= +golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= +golang.org/x/tools v0.0.0-20190311212946-11955173bddd/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312151545-0bb0c0a6e846/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190328211700-ab21143f2384/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190425150028-36563e24a262/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190506145303-2d16b83fe98c/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190524140312-2c0ae7006135/go.mod h1:RgjU9mgBXZiqYHBnxXauZ1Gv1EHHAz9KjViQ78xBX0Q= +golang.org/x/tools v0.0.0-20190606124116-d0a3d012864b/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190621195816-6e04913cbbac/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= +golang.org/x/tools v0.0.0-20190816200558-6889da9d5479/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20190911174233-4f2ddba30aff/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191012152004-8de300cfc20a/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191113191852-77e3bb0ad9e7/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191115202509-3a792d9c32b2/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191125144606-a911d9008d1f/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= +golang.org/x/tools v0.0.0-20191216173652-a0e659d51361/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20191227053925-7b8e75db28f4/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/tools v0.0.0-20200108203644-89082a384178/go.mod h1:TB2adYChydJhpapKDTa4BR/hXlZSLoq2Wpct/0txZ28= +golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= +gonum.org/v1/gonum v0.0.0-20180816165407-929014505bf4/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.0.0-20181121035319-3f7ecaa7e8ca/go.mod h1:Y+Yx5eoAFn32cQvJDxZx5Dpnq+c3wtXuadVZAcxbbBo= +gonum.org/v1/gonum v0.6.0/go.mod h1:9mxDZsDKxgMAuccQkewq682L+0eCu4dCN2yonUJTCLU= +gonum.org/v1/netlib v0.0.0-20181029234149-ec6d1f5cefe6/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/netlib v0.0.0-20190313105609-8cb42192e0e0/go.mod h1:wa6Ws7BG/ESfp6dHfk7C6KdzKA7wR7u/rKwOGE66zvw= +gonum.org/v1/plot v0.0.0-20190515093506-e2840ee46a6b/go.mod h1:Wt8AAjI+ypCyYX3nZBvf6cAIx93T+c/OS2HFAYskSZc= +google.golang.org/api v0.4.0/go.mod h1:8k5glujaEP+g9n7WNsDg8QP6cUVNI86fCNMcbazEtwE= +google.golang.org/api v0.7.0/go.mod h1:WtwebWUNSVBH/HAw79HIFXZNqEvBhG+Ra+ax0hx3E3M= +google.golang.org/api v0.8.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.9.0/go.mod h1:o4eAsZoiT+ibD93RtjEohWalFOjRDx6CVaqeizhEnKg= +google.golang.org/api v0.13.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.14.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/api v0.15.0/go.mod h1:iLdEw5Ide6rF15KTC1Kkl0iskquN2gFfn9o9XIsbkAI= +google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.5.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.6.1/go.mod h1:i06prIuMbXzDqacNJfV5OdTW448YApPu5ww/cMBSeb0= +google.golang.org/appengine v1.6.5/go.mod h1:8WjMMxjGQR8xUklV/ARdw2HLXBOI7O7uCIDZVag1xfc= +google.golang.org/genproto v0.0.0-20180817151627-c66870c02cf8/go.mod h1:JiN7NxoALGmiZfu7CAH4rXhgtRTLTxftemlI0sWmxmc= +google.golang.org/genproto v0.0.0-20190307195333-5fe7a883aa19/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190418145605-e7d98fc518a7/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190425155659-357c62f0e4bb/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190502173448-54afdca5d873/go.mod h1:VzzqZJRnGkLBvHegQrXjBqPurQTc5/KpmUdxsrq26oE= +google.golang.org/genproto v0.0.0-20190716160619-c506a9f90610/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190801165951-fa694d86fc64/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190819201941-24fa4b261c55/go.mod h1:DMBHOl98Agz4BDEuKkezgsaosCRResVns1a3J2ZsMNc= +google.golang.org/genproto v0.0.0-20190911173649-1774047e7e51/go.mod h1:IbNlFCBrqXvoKpeg0TB2l7cyZUmoaFKYIwrEpbDKLA8= +google.golang.org/genproto v0.0.0-20191108220845-16a3f7862a1a/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= +google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= +google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= +google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= +google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= +gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= +honnef.co/go/tools v0.0.0-20190102054323-c2f93a96b099/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190106161140-3f1c8253044a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190418001031-e561f6794a2a/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.0-20190523083050-ea95bdfd59fc/go.mod h1:rf3lG4BRIbNafJWhAfAdb/ePZxsR/4RtNHQocxwk9r4= +honnef.co/go/tools v0.0.1-2019.2.3/go.mod h1:a3bituU0lyd329TUQxRnasdCoJDkEUEAqEt0JzvZhAg= +rsc.io/binaryregexp v0.2.0/go.mod h1:qTv7/COck+e2FymRvadv62gMdZztPaShugOCi3I+8D8= +rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= diff --git a/orcareduce/chaos/chaos.go b/orcareduce/chaos/chaos.go new file mode 100644 index 0000000..d5c3f0a --- /dev/null +++ b/orcareduce/chaos/chaos.go @@ -0,0 +1,104 @@ +package chaos + +import ( + "fmt" + "math/rand" + "time" +) + +type randomStaticErrors struct { + err error + errorRate float64 +} + +func (cfg *randomStaticErrors) Error() error { + if rand.Float64() <= cfg.errorRate { + return cfg.err + } + return nil +} + +type staticLatency struct { + latency time.Duration +} + +type metaErrors struct { + errors []ErrorInjector +} + +func (cfg *metaErrors) Error() error { + for _, injector := range cfg.errors { + err := injector.Error() + if err != nil { + return err + } + } + return nil +} + +func (cfg *staticLatency) Latency() { + time.Sleep(cfg.latency) +} + +type dynamicLatency struct { + maxLatency time.Duration +} + +func (cfg *dynamicLatency) Latency() { + val := rand.Int63n(int64(cfg.maxLatency)) + time.Sleep(time.Duration(val)) +} + +type randomLatency struct { + latency LatencyInjector + percent float64 +} + +func (cfg *randomLatency) Latency() { + if rand.Float64() < cfg.percent { + cfg.latency.Latency() + } +} + +type metaLatency struct { + latency []LatencyInjector +} + +func (this *metaLatency) Latency() { + for _, latency := range this.latency { + latency.Latency() + } +} + +type metaInjector struct { + latency LatencyInjector + errors ErrorInjector +} + +func (cfg *metaInjector) Latency() { + cfg.latency.Latency() +} + +func (cfg *metaInjector) Error() error { + return cfg.errors.Error() +} + +func NewDefault() Injector { + return &metaInjector{ + latency: &metaLatency{ + latency: []LatencyInjector{ + &staticLatency{latency: 20 * time.Millisecond}, + &dynamicLatency{maxLatency: 20 * time.Millisecond}, + &randomLatency{percent: 0.1, latency: &dynamicLatency{maxLatency: 100 * time.Millisecond}}, + &randomLatency{percent: 0.01, latency: &dynamicLatency{maxLatency: 1000 * time.Millisecond}}, + &randomLatency{percent: 0.001, latency: &dynamicLatency{maxLatency: 5000 * time.Millisecond}}, + &randomLatency{percent: 0.0001, latency: &dynamicLatency{maxLatency: 30 * time.Second}}, + }, + }, + errors: &metaErrors{ + errors: []ErrorInjector{ + &randomStaticErrors{err: fmt.Errorf("[chaos] encountered an error"), errorRate: 0.1}, + }, + }, + } +} diff --git a/orcareduce/chaos/chaos_test.go b/orcareduce/chaos/chaos_test.go new file mode 100644 index 0000000..ce88824 --- /dev/null +++ b/orcareduce/chaos/chaos_test.go @@ -0,0 +1,26 @@ +package chaos + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDefaultChaos(t *testing.T) { + rand.Seed(5) // Static seed so the test is deterministic. + chaos := NewDefault() + + now := time.Now() + chaos.Latency() + assert.True(t, time.Since(now) >= time.Millisecond*20) + + errCount := 0 + for i := 0; i < 1000; i++ { + if err := chaos.Error(); err != nil { + errCount++ + } + } + assert.Equal(t, 105, errCount) +} diff --git a/orcareduce/chaos/iface.go b/orcareduce/chaos/iface.go new file mode 100644 index 0000000..c188d10 --- /dev/null +++ b/orcareduce/chaos/iface.go @@ -0,0 +1,14 @@ +package chaos + +type Injector interface { + Latency() + Error() error +} + +type ErrorInjector interface { + Error() error +} + +type LatencyInjector interface { + Latency() +} diff --git a/orcareduce/director/director.go b/orcareduce/director/director.go index 911eb8f..c660f48 100644 --- a/orcareduce/director/director.go +++ b/orcareduce/director/director.go @@ -1,40 +1,39 @@ -package prod +package director import ( + "math" + "time" + "github.com/mkuchenbecker/orcareduce/orcareduce" "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" "github.com/pkg/errors" ) - - type config struct { - retries int - backoffFactor int + maxAttempts int } -func (c *config) Backoff(retry int) time.Duration { - return math.Max(1,2) * time.Second +func (c *config) Backoff(attempt int) time.Duration { + return time.Duration(int64(math.Max(float64(attempt), 2))) * time.Second } -func (c *config) Retries() int { - +func (c *config) Attempts() int { + return c.maxAttempts } - type director struct { - actor orcareduce.Reactor - cfg config + actor orcareduce.Reactor + cfg config + handler exceptions.Handler + id orcareduce.ID + clock Clock } func (d *director) Direct() (err error) { defer func() { - err = errors.Wrap(err,"unable to direct") + err = errors.Wrap(err, "unable to direct") }() - actor, err := d.GetNextActor() - if err != nil { - return err - } + actor := d.actor err = actor.Preconditions() if err != nil { return exceptions.PreconditionError(err.Error()) @@ -47,16 +46,31 @@ func (d *director) Direct() (err error) { if err != nil { return err } - actor.Notify() + actor.Notify() return nil } +func (d *director) Run() (err error) { + defer d.handler.HandlePanic(&err) + runtime := NewRuntime(d.id, d.clock) + defer func() { + err := runtime.Save() + _ = d.handler.HandleError(err) + }() -func (d *director) Run() { - for i:= 0; i < d.config.Retries(); i++ { - - + for i := 0; i < d.cfg.Attempts(); i++ { + _, endFunc := runtime.StartRun() + err := d.Direct() + endFunc(err, "") + if d.handler.HandleError(err) != nil { + return err + } + d.cfg.Backoff(i) } + return nil } +func (d *director) RunAsync(err chan error) { + err <- d.Run() +} diff --git a/orcareduce/director/influx.go b/orcareduce/director/influx.go new file mode 100644 index 0000000..6cc9f71 --- /dev/null +++ b/orcareduce/director/influx.go @@ -0,0 +1,182 @@ +package director + +import ( + "fmt" + "log" + "time" + + "github.com/influxdata/influxdb/client/v2" + "github.com/mkuchenbecker/orcareduce/orcareduce" +) + +const ( + // MyDB specifies name of database + MyDB = "go_influx" +) + +type Product struct { + ID int `json:"id"` + Name string `json:"name"` + Price float32 `json:"price"` + Image string `json:"image"` + Description string `json:"description"` + Views string +} + +type Run interface { + StartTime() time.Time + EndTime() time.Time + Runtime() time.Duration + Error() error + Message() string + KeyValue() map[string]interface{} + // Add(key string, value interface{}) Run +} + +type EndFunc func(error, string) + +type Runtime interface { + ID() orcareduce.ID + Runs() []Run + StartRun() (Run, EndFunc) + Save() error +} + +type Clock interface { + Now() time.Time +} + +type wallClock struct{} + +func (w wallClock) Now() time.Time { + return time.Now() +} + +func NewClock() Clock { + return wallClock{} +} + +type simpleRuntime struct { + identifier orcareduce.ID + runs []Run + clock Clock +} + +func (this *simpleRuntime) ID() orcareduce.ID { + return this.identifier +} + +func (this *simpleRuntime) Runs() []Run { + return this.runs +} + +func (this *simpleRuntime) StartRun() (Run, EndFunc) { + run := &simpleRun{KV: make(map[string]interface{})} + run.ID = this.identifier.NewChild() + this.runs = append(this.runs, run) + run.Start = this.clock.Now() + return run, func(err error, msg string) { + run.End = this.clock.Now() + run.Err = err + run.Msg = msg + } +} + +func NewRuntime(parent orcareduce.ID, clock Clock) Runtime { + return &simpleRuntime{ + identifier: parent.NewScopedChild("runtime"), + clock: clock, + runs: make([]Run, 0), + } +} + +type simpleRun struct { + ID orcareduce.ID + Start time.Time + End time.Time + Err error + Msg string + KV map[string]interface{} +} + +func (this *simpleRun) StartTime() time.Time { + return this.Start +} +func (this *simpleRun) EndTime() time.Time { + return this.End +} +func (this *simpleRun) Runtime() time.Duration { + return this.End.Sub(this.Start) +} +func (this *simpleRun) Error() error { + return this.Err +} +func (this *simpleRun) Message() string { + return this.Msg +} +func (this *simpleRun) KeyValue() map[string]interface{} { + this.KV["ID"] = this.ID.String() + this.KV["startTime"] = this.StartTime() + this.KV["endTime"] = this.EndTime() + this.KV["runtime"] = this.Runtime() + this.KV["error"] = this.Runtime() + this.KV["Msg"] = this.Message() + return this.KV +} +func (this *simpleRun) Add(key string, value interface{}) Run { + this.KV[key] = value + return this +} + +func (s *simpleRuntime) Save() error { + c, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: "http://localhost:8086", + }) + if err != nil { + return err + } + defer c.Close() + // Create a new point batch + bp, err := client.NewBatchPoints(client.BatchPointsConfig{ + Database: MyDB, + Precision: "ms", + }) + if err != nil { + return err + } + for i, run := range s.Runs() { + tags := map[string]string{ + "runtime": s.ID().String(), + "run": fmt.Sprintf("%d", i), + } + pt, err := client.NewPoint("run", tags, run.KeyValue(), time.Now()) + if err != nil { + log.Fatal(err) + } + bp.AddPoint(pt) + } + if err := c.Write(bp); err != nil { + return err + } + return nil +} + +// queryDB convenience function to query the database +func queryDB(cmd string) (res []client.Result, err error) { + q := client.Query{ + Command: cmd, + Database: MyDB, + } + c, err := client.NewHTTPClient(client.HTTPConfig{ + Addr: "http://localhost:8086", + }) + if response, err := c.Query(q); err == nil { + if response.Error() != nil { + return res, response.Error() + } + res = response.Results + } else { + return res, err + } + return res, nil +} diff --git a/orcareduce/effsleep/channel.go b/orcareduce/effsleep/channel.go new file mode 100644 index 0000000..8d30eb6 --- /dev/null +++ b/orcareduce/effsleep/channel.go @@ -0,0 +1,98 @@ +package effsleep + +import ( + "context" + "errors" + "sync" + + "github.com/mkuchenbecker/orcareduce/orcareduce/chaos" +) + +type ChannelInjector interface { + Done() + Sync() +} + +type chanInjector chan bool + +func NewInjector() ChannelInjector { + out := chanInjector(make(chan bool)) + return &out +} + +func (this *chanInjector) Done() { + *this <- true +} + +func (this *chanInjector) Sync() { + <-*this +} + +type InjectorManager interface { + Subscribe(key string) ChannelInjector + Done(key string) bool + Sync(key string) bool +} + +type injectorManager struct { + injectors map[string]ChannelInjector + mux sync.RWMutex +} + +func NewInjectorManager() InjectorManager { + return &injectorManager{injectors: make(map[string]ChannelInjector)} +} + +func (this *injectorManager) Subscribe(key string) ChannelInjector { + injector := NewInjector() + this.injectors[key] = injector + return injector +} + +func (this *injectorManager) Done(key string) (ok bool) { + injector, ok := this.injectors[key] + if !ok { + return + } + injector.Done() + return +} + +func (this *injectorManager) Sync(key string) (ok bool) { + injector, ok := this.injectors[key] + if !ok { + return + } + injector.Done() + return +} + +type IndeterminateRuntime struct { + chaos chaos.Injector +} + +const InjectorManagerContextKey = "INJECTION_MANAGER" + +func Finished(ctx context.Context) error { + manager := ctx.Value(InjectorManagerContextKey) + if manager == nil { + return errors.New("unable to find manager") + } + man, ok := manager.(ChannelInjector) + if !ok { + return errors.New("manager wrong type") + } + man.Done() + return nil +} + +func (this *IndeterminateRuntime) Run(doneFunc func(), i *int) { + defer doneFunc() + this.chaos.Latency() + *i = *i + 1 +} +func (this *IndeterminateRuntime) RunCtx(ctx context.Context, i *int) error { + this.chaos.Latency() + *i = *i + 1 + return Finished(ctx) +} diff --git a/orcareduce/effsleep/channel_test.go b/orcareduce/effsleep/channel_test.go new file mode 100644 index 0000000..fe3d7aa --- /dev/null +++ b/orcareduce/effsleep/channel_test.go @@ -0,0 +1,40 @@ +package effsleep + +import ( + "context" + "testing" + + "github.com/mkuchenbecker/orcareduce/orcareduce/chaos" + "github.com/stretchr/testify/assert" +) + +func TestInjector(t *testing.T) { + t.Parallel() + + syncFunctionName := "IndeterminateRuntime.Run" + manager := NewInjectorManager() + injector := manager.Subscribe(syncFunctionName) + m := map[string]ChannelInjector{"0":} + ctx := context.WithValue(context.Background(), InjectorManagerContextKey, injector) + + runtime := IndeterminateRuntime{chaos: chaos.NewDefault()} + + i := 0 + go func() { + for i := 0; i < 10; i++ { + assert.NoError(t, runtime.RunCtx(ctx, &i)) + } + }() + injector.Sync() + assert.Equal(t, 1, i) + +} + +type SyncFunc func() error + +type SafeGoRunner struct { +} + + + +func RunAsync( \ No newline at end of file diff --git a/orcareduce/effsleep/doc.go b/orcareduce/effsleep/doc.go new file mode 100644 index 0000000..b72b521 --- /dev/null +++ b/orcareduce/effsleep/doc.go @@ -0,0 +1,7 @@ +package effsleep + +/* +Indeterminant tests are the bain of any sane developer. +All tests should be deterministic. +No tests should rely on sleep. +*/ \ No newline at end of file diff --git a/orcareduce/exceptions/errors.go b/orcareduce/exceptions/errors.go index ad6828f..891bb03 100644 --- a/orcareduce/exceptions/errors.go +++ b/orcareduce/exceptions/errors.go @@ -1,15 +1,84 @@ package exceptions -import "fmt" +import ( + "fmt" + + "github.com/pkg/errors" +) var ( - ErrActorsDepleted = fmt.Errorf("actors depleted") + ErrActorsDepleted = fmt.Errorf("actors depleted") ErrPreconditionsNotMet = fmt.Errorf("preconditions not met") ) - type PreconditionError string func (err PreconditionError) Error() string { return fmt.Sprintf("preconditions not met: %s", err) -} \ No newline at end of file +} + +type Logger interface { + Error(err error, msg string) + Info(err error, msg string) +} + +type logger struct { +} + +func (l logger) Error(err error, msg string) { + fmt.Printf("encountered an error: %s: %s", msg, err.Error()) +} + +type Handler interface { + HandleError(error) error + HandlePanic(err *error) +} + +type workflowHandler struct { + logger Logger +} + +func (w workflowHandler) HandleError(err error) error { + if err == nil { + return nil + } + cause := errors.Cause(err) + switch cause.(type) { + case PreconditionError: + w.logger.Info(err, "preconditions not met") + return err + default: + w.logger.Info(err, "encountered unknown error") + return nil + } + return nil +} + +func (w workflowHandler) HandlePanic(err *error) { + r := recover() + if r == nil { + return + } + _ = w.HandleError(r.(error)) // Ignore result. + if err == nil { + return + } + if *err == nil { + *err = errors.Errorf("encountered a panic: %s", (*err).Error()) + } +} + +type SyncFunc func() error + +func (w workflowHandler) RunAsync(f func()) SyncFunc { + done := make(chan bool) + go func() { + defer w.HandlePanic(nil) + f() + done <- true + }() + return func() error { + <-done + return nil + } +} diff --git a/orcareduce/iface.go b/orcareduce/iface.go index cf005d6..a25aba0 100644 --- a/orcareduce/iface.go +++ b/orcareduce/iface.go @@ -1,5 +1,11 @@ package orcareduce +import ( + "bytes" + "crypto/sha256" + "time" +) + // Reactor is a repeatable actor. type Reactor interface { Preconditions() error @@ -16,11 +22,83 @@ type Precondition interface { // ID is a generalized interface for identifying reactors. type ID interface { String() string - Bytes() []byte + Value() string + Lineage() []ID Parent() ID + NewChild() ID + NewScopedChild(scope Scope) ID } type Director interface { GetNextActor() error Act() error + ID() ID +} + +type ActorDataSink interface { + Success(Reactor) error + Failure(Reactor) + Attempt(Reactor) error +} + +type Scope string + +type identifier struct { + id string + scope Scope + level int + parent *identifier +} + +func (this *identifier) Lineage() []ID { + out := make([]ID, 0) + curr := this + for { + out = append(out, curr) + if curr.parent == nil { + break + } + curr = curr.parent + } + return out +} + +func (this *identifier) String() string { + lineage := this.Lineage() + var buf bytes.Buffer + for i := len(lineage) - 1; i >= 0; i++ { + buf.WriteString(lineage[i].Value()) + } + return buf.String() +} + +func (this *identifier) Value() string { + return this.id +} + +func (this *identifier) Parent() ID { + return this.parent +} + +func (this *identifier) NewChild() ID { + out := NewID() + out.level = this.level + 1 + out.parent = this + return out +} + +func (this *identifier) NewScopedChild(scope Scope) ID { + out := NewID() + out.scope = scope + out.level = this.level + 1 + out.parent = this + return out +} + +func NewID() *identifier { + sha := sha256.New() + val := sha.Sum([]byte(time.Now().String())) // Re-hash the parent ID. + return &identifier{ + id: string(val), + } } diff --git a/orcareduce/state/datastore.go b/orcareduce/state/datastore.go new file mode 100644 index 0000000..7be1272 --- /dev/null +++ b/orcareduce/state/datastore.go @@ -0,0 +1,104 @@ +package state + +import ( + "sync" + + "github.com/mkuchenbecker/orcareduce/orcareduce" + "github.com/pkg/errors" +) + +type State string + +var ( + PENDING State = "PENDING" + SUCCESS State = "SUCCESS" + FAILURE State = "FAILURE" +) + +type document struct { + actor orcareduce.Reactor + state State + attempt int +} + +type inMemorySink struct { + data map[orcareduce.ID]document + mux sync.RWMutex +} + +func (sink *inMemorySink) Success(r orcareduce.Reactor) (err error) { + defer func() { + err = errors.Wrap(err, "unable to record success") + }() + sink.mux.Lock() + defer sink.mux.Unlock() + val, ok := sink.data[r.ID()] + if !ok { + val = document{actor: r} + } + if val.state == FAILURE { + return errors.New("record already marked as failure") + } + val.state = SUCCESS + sink.data[r.ID()] = val + return nil +} + +func (sink *inMemorySink) Failure(r orcareduce.Reactor) { + sink.mux.Lock() + defer sink.mux.Unlock() + val, ok := sink.data[r.ID()] + if !ok { + val = document{actor: r} + } + if val.state == SUCCESS { + return + } + val.state = FAILURE + sink.data[r.ID()] = val + return +} + +func (sink *inMemorySink) Attempt(r orcareduce.Reactor) error { + sink.mux.Lock() + defer sink.mux.Unlock() + val, ok := sink.data[r.ID()] + if !ok { + val = document{actor: r} + } + if val.state != PENDING { + return errors.New("only make an attempt on pending requests") + } + val.attempt++ + sink.data[r.ID()] = val + return nil +} + +type DatastoreActor struct { + actor orcareduce.Reactor + sink orcareduce.ActorDataSink +} + +func (d *DatastoreActor) SignalSuccess() error { + return d.sink.Success(d) +} + +func (d *DatastoreActor) Preconditions() error { + return d.actor.Preconditions() +} + +func (d *DatastoreActor) Act() error { + err := d.sink.Attempt(d) + if err != nil { + return err + } + return d.Act() +} + +func (d *DatastoreActor) Notify() { + d.actor.Notify() +} + +func (d *DatastoreActor) ID() orcareduce.ID { + return d.ID() +} From 5d83a04906757f55d34eb87c44edcf8681f462e3 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Sun, 21 Jun 2020 11:19:36 -0700 Subject: [PATCH 05/11] Implements Exceptions and Logging Exceptions have a new Handler interface, and the interface allows for common handling of errors and running async tasks. Logger implementation using Glog with basic logging functions implemented. --- .gitignore | 2 + Makefile | 5 +- go.mod | 2 + go.sum | 2 + orcareduce/effsleep/channel.go | 98 ------------ orcareduce/effsleep/channel_test.go | 40 ----- orcareduce/effsleep/doc.go | 7 - orcareduce/exceptions/doc.go | 14 ++ orcareduce/exceptions/errors.go | 84 ---------- orcareduce/exceptions/handler/handler.go | 74 +++++++++ orcareduce/exceptions/handler/handler_test.go | 147 ++++++++++++++++++ orcareduce/exceptions/logger/logger.go | 35 +++++ orcareduce/exceptions/logger/logger_test.go | 56 +++++++ orcareduce/exceptions/mock/mock.go | 143 +++++++++++++++++ orcareduce/exceptions/types.go | 78 ++++++++++ 15 files changed, 555 insertions(+), 232 deletions(-) delete mode 100644 orcareduce/effsleep/channel.go delete mode 100644 orcareduce/effsleep/channel_test.go delete mode 100644 orcareduce/effsleep/doc.go create mode 100644 orcareduce/exceptions/doc.go delete mode 100644 orcareduce/exceptions/errors.go create mode 100644 orcareduce/exceptions/handler/handler.go create mode 100644 orcareduce/exceptions/handler/handler_test.go create mode 100644 orcareduce/exceptions/logger/logger.go create mode 100644 orcareduce/exceptions/logger/logger_test.go create mode 100644 orcareduce/exceptions/mock/mock.go create mode 100644 orcareduce/exceptions/types.go diff --git a/.gitignore b/.gitignore index 66fd13c..fc8c26e 100644 --- a/.gitignore +++ b/.gitignore @@ -13,3 +13,5 @@ # Dependency directories (remove the comment below to include it) # vendor/ + +.vscode \ No newline at end of file diff --git a/Makefile b/Makefile index 4d868dd..94c2e47 100644 --- a/Makefile +++ b/Makefile @@ -11,11 +11,10 @@ bootstrap: lint: fmt golangci-lint run -.PHONY: test-ci +.PHONY: test-flake test-ci: @echo "tests:" - go test -v -covermode=count -coverprofile=data/coverage.out ./data/... - go test -v -covermode=count -coverprofile=brewery/coverage.out ./brewery/... + richgo test -count=30 -v -cover ./... .PHONY: install-golang-ci lint-ci: diff --git a/go.mod b/go.mod index 29a5dac..04dc0d6 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,8 @@ module github.com/mkuchenbecker/orcareduce go 1.13 require ( + github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b + github.com/golang/mock v1.3.1 github.com/influxdata/influxdb v1.8.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.5.1 diff --git a/go.sum b/go.sum index 6215109..4fc882c 100644 --- a/go.sum +++ b/go.sum @@ -61,11 +61,13 @@ github.com/go-stack/stack v1.8.0/go.mod h1:v0f6uXyyMGvRgIKkXu+yp6POWl0qKG85gN/me github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/freetype v0.0.0-20170609003504-e2365dfdc4a0/go.mod h1:E/TSTwGwJL78qG/PmXZO1EjYhfJinVAhrmmHX6Z8B9k= github.com/golang/geo v0.0.0-20190916061304-5b978397cfec/go.mod h1:QZ0nwyI2jOfgRAoBvP+ab5aRr7c9x7lhGEJrKvBwjWI= +github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b h1:VKtxabqXZkF25pY9ekfRL6a582T4P37/31XEstQ5p58= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= github.com/golang/groupcache v0.0.0-20190702054246-869f871628b6/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/groupcache v0.0.0-20191227052852-215e87163ea7/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/mock v1.1.1/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= github.com/golang/mock v1.2.0/go.mod h1:oTYuIxOrZwtPieC+H1uAHpcLFnEyAGVDL/k47Jfbm0A= +github.com/golang/mock v1.3.1 h1:qGJ6qTW+x6xX/my+8YUVl4WNpX9B7+/l2tRsHGZ7f2s= github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFUx0Y= github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= diff --git a/orcareduce/effsleep/channel.go b/orcareduce/effsleep/channel.go deleted file mode 100644 index 8d30eb6..0000000 --- a/orcareduce/effsleep/channel.go +++ /dev/null @@ -1,98 +0,0 @@ -package effsleep - -import ( - "context" - "errors" - "sync" - - "github.com/mkuchenbecker/orcareduce/orcareduce/chaos" -) - -type ChannelInjector interface { - Done() - Sync() -} - -type chanInjector chan bool - -func NewInjector() ChannelInjector { - out := chanInjector(make(chan bool)) - return &out -} - -func (this *chanInjector) Done() { - *this <- true -} - -func (this *chanInjector) Sync() { - <-*this -} - -type InjectorManager interface { - Subscribe(key string) ChannelInjector - Done(key string) bool - Sync(key string) bool -} - -type injectorManager struct { - injectors map[string]ChannelInjector - mux sync.RWMutex -} - -func NewInjectorManager() InjectorManager { - return &injectorManager{injectors: make(map[string]ChannelInjector)} -} - -func (this *injectorManager) Subscribe(key string) ChannelInjector { - injector := NewInjector() - this.injectors[key] = injector - return injector -} - -func (this *injectorManager) Done(key string) (ok bool) { - injector, ok := this.injectors[key] - if !ok { - return - } - injector.Done() - return -} - -func (this *injectorManager) Sync(key string) (ok bool) { - injector, ok := this.injectors[key] - if !ok { - return - } - injector.Done() - return -} - -type IndeterminateRuntime struct { - chaos chaos.Injector -} - -const InjectorManagerContextKey = "INJECTION_MANAGER" - -func Finished(ctx context.Context) error { - manager := ctx.Value(InjectorManagerContextKey) - if manager == nil { - return errors.New("unable to find manager") - } - man, ok := manager.(ChannelInjector) - if !ok { - return errors.New("manager wrong type") - } - man.Done() - return nil -} - -func (this *IndeterminateRuntime) Run(doneFunc func(), i *int) { - defer doneFunc() - this.chaos.Latency() - *i = *i + 1 -} -func (this *IndeterminateRuntime) RunCtx(ctx context.Context, i *int) error { - this.chaos.Latency() - *i = *i + 1 - return Finished(ctx) -} diff --git a/orcareduce/effsleep/channel_test.go b/orcareduce/effsleep/channel_test.go deleted file mode 100644 index fe3d7aa..0000000 --- a/orcareduce/effsleep/channel_test.go +++ /dev/null @@ -1,40 +0,0 @@ -package effsleep - -import ( - "context" - "testing" - - "github.com/mkuchenbecker/orcareduce/orcareduce/chaos" - "github.com/stretchr/testify/assert" -) - -func TestInjector(t *testing.T) { - t.Parallel() - - syncFunctionName := "IndeterminateRuntime.Run" - manager := NewInjectorManager() - injector := manager.Subscribe(syncFunctionName) - m := map[string]ChannelInjector{"0":} - ctx := context.WithValue(context.Background(), InjectorManagerContextKey, injector) - - runtime := IndeterminateRuntime{chaos: chaos.NewDefault()} - - i := 0 - go func() { - for i := 0; i < 10; i++ { - assert.NoError(t, runtime.RunCtx(ctx, &i)) - } - }() - injector.Sync() - assert.Equal(t, 1, i) - -} - -type SyncFunc func() error - -type SafeGoRunner struct { -} - - - -func RunAsync( \ No newline at end of file diff --git a/orcareduce/effsleep/doc.go b/orcareduce/effsleep/doc.go deleted file mode 100644 index b72b521..0000000 --- a/orcareduce/effsleep/doc.go +++ /dev/null @@ -1,7 +0,0 @@ -package effsleep - -/* -Indeterminant tests are the bain of any sane developer. -All tests should be deterministic. -No tests should rely on sleep. -*/ \ No newline at end of file diff --git a/orcareduce/exceptions/doc.go b/orcareduce/exceptions/doc.go new file mode 100644 index 0000000..b87641c --- /dev/null +++ b/orcareduce/exceptions/doc.go @@ -0,0 +1,14 @@ +package exceptions + +/* + +exceptions is a package dedicated to the handling and logging of errors and messages in the system, +as well as functionality to safely run asycronous go code in a manor that is visible and protected +from exceptions bringing down a service. + +The core functionality works around a Handler object which handles the execution of asyncrounous +tasks and has the ability to consistently log across the codebase. The intended use of a handler +is all processes have access to a Handler, which acts as a common method of running ansyc tasks +and structured logging of errors. + +*/ diff --git a/orcareduce/exceptions/errors.go b/orcareduce/exceptions/errors.go deleted file mode 100644 index 891bb03..0000000 --- a/orcareduce/exceptions/errors.go +++ /dev/null @@ -1,84 +0,0 @@ -package exceptions - -import ( - "fmt" - - "github.com/pkg/errors" -) - -var ( - ErrActorsDepleted = fmt.Errorf("actors depleted") - ErrPreconditionsNotMet = fmt.Errorf("preconditions not met") -) - -type PreconditionError string - -func (err PreconditionError) Error() string { - return fmt.Sprintf("preconditions not met: %s", err) -} - -type Logger interface { - Error(err error, msg string) - Info(err error, msg string) -} - -type logger struct { -} - -func (l logger) Error(err error, msg string) { - fmt.Printf("encountered an error: %s: %s", msg, err.Error()) -} - -type Handler interface { - HandleError(error) error - HandlePanic(err *error) -} - -type workflowHandler struct { - logger Logger -} - -func (w workflowHandler) HandleError(err error) error { - if err == nil { - return nil - } - cause := errors.Cause(err) - switch cause.(type) { - case PreconditionError: - w.logger.Info(err, "preconditions not met") - return err - default: - w.logger.Info(err, "encountered unknown error") - return nil - } - return nil -} - -func (w workflowHandler) HandlePanic(err *error) { - r := recover() - if r == nil { - return - } - _ = w.HandleError(r.(error)) // Ignore result. - if err == nil { - return - } - if *err == nil { - *err = errors.Errorf("encountered a panic: %s", (*err).Error()) - } -} - -type SyncFunc func() error - -func (w workflowHandler) RunAsync(f func()) SyncFunc { - done := make(chan bool) - go func() { - defer w.HandlePanic(nil) - f() - done <- true - }() - return func() error { - <-done - return nil - } -} diff --git a/orcareduce/exceptions/handler/handler.go b/orcareduce/exceptions/handler/handler.go new file mode 100644 index 0000000..6f2ca10 --- /dev/null +++ b/orcareduce/exceptions/handler/handler.go @@ -0,0 +1,74 @@ +package exceptions + +import ( + "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" + "github.com/pkg/errors" +) + +// workflowHandler is a private implementation of the Handler interface. +// It has basic functionality and an internal logger so it can log +// errors it encountners. +type workflowHandler struct { + logger exceptions.Logger +} + +// HandleError logs an error at the appropriate level and returns +// the error as-is. If err is nil, nothing is logged and nil is +// returned. +func (w workflowHandler) HandleError(err error) (out error) { + out = err + if err == nil { + return nil + } + cause := errors.Cause(err) + switch cause.(type) { + case exceptions.PreconditionError: + w.logger.Infof(err.Error()) + return + default: + w.logger.Error(err, "encountered an error") + return + } +} + +// HandlePanic recovers from a panic, logs that the panic occured, and populates +// the err paramerter with details about the panic if err is supplied and not +// already populated. +func (w workflowHandler) HandlePanic(err *error) { + r := recover() + if r == nil { + return + } + w.logger.Errorf("encountered a panic: %+v", r) + if err == nil { + return + } + if *err == nil { + *err = errors.Errorf("encountered a panic: %+v", r) + } +} + +// RunAsync safely runs a RunFunc ansyncronously. It handles any errors that +// are returned by the RunFunc, and recovers from any panics in the RunFunc. +// The return value SyncFunc is a function that blocks until the RunFunc has +// completed execution. +func (w workflowHandler) RunAsync(f exceptions.RunFunc) exceptions.SyncFunc { + done := make(chan error) + go func() { + var err error + defer func() { + done <- err + }() + defer w.HandlePanic(&err) + err = f() + w.HandleError(err) + }() + return func() error { + return <-done + } +} + +// NewHandler makes a Handler using the supplied logger. +func NewHandler(logger exceptions.Logger) exceptions.Handler { + return workflowHandler{logger: logger} +} diff --git a/orcareduce/exceptions/handler/handler_test.go b/orcareduce/exceptions/handler/handler_test.go new file mode 100644 index 0000000..c55adac --- /dev/null +++ b/orcareduce/exceptions/handler/handler_test.go @@ -0,0 +1,147 @@ +package exceptions + +import ( + "fmt" + "testing" + "time" + + "github.com/golang/mock/gomock" + "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" + "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions/mock" + "github.com/stretchr/testify/assert" +) + +var errGeneric = fmt.Errorf("error") + +func TestHandler_RunAsync(t *testing.T) { + t.Parallel() + + t.Run("SyncFunc Synchronizes", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockLogger := mock.NewMockLogger(mockCtrl) + handler := NewHandler(mockLogger) + + i := 0 + runFunc := func() error { + time.Sleep(10 * time.Millisecond) + i = 1 + return nil + } + + sync := handler.RunAsync(runFunc) + assert.Equal(t, 0, i) + sync() + assert.Equal(t, 1, i) + }) + + t.Run("Panic Handled and Logged", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + logs := mock.NewMockLogger(mockCtrl) + logs.EXPECT().Errorf("encountered a panic: %+v", gomock.Not(nil)).Times(1) + handler := NewHandler(logs) + + runFunc := func() error { + panic("") + } + sync := handler.RunAsync(runFunc) + sync() + }) +} + +func TestHandler_HandlePanic(t *testing.T) { + t.Parallel() + + t.Run("Function Does Not Panic", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockLogger := mock.NewMockLogger(mockCtrl) + handler := NewHandler(mockLogger) + + noOpFunction := func() error { return nil } + sync := handler.RunAsync(noOpFunction) + assert.NoError(t, sync()) + }) + + t.Run("Panic Logs and Returns Error", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + logs := mock.NewMockLogger(mockCtrl) + logs.EXPECT().Errorf("encountered a panic: %+v", gomock.Not(nil)).Times(1) + handler := NewHandler(logs) + + runFunc := func() error { + panic("") + } + sync := handler.RunAsync(runFunc) + err := sync() + assert.Error(t, err) + }) + + t.Run("Panic Populates Return Error and Logs Error", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + logs := mock.NewMockLogger(mockCtrl) + logs.EXPECT().Error(errGeneric, "encountered an error").Times(1) + handler := NewHandler(logs) + + runFunc := func() error { + return errGeneric + } + sync := handler.RunAsync(runFunc) + assert.Equal(t, errGeneric, sync()) + }) + + t.Run("Panic Logs Error Nil Error", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + logs := mock.NewMockLogger(mockCtrl) + logs.EXPECT().Errorf("encountered a panic: %+v", gomock.Not(nil)).Times(1) + handler := NewHandler(logs) + + runFunc := func() error { + panic("") + } + done := make(chan bool) + go func() { + defer func() { + done <- true + }() + defer handler.HandlePanic(nil) + _ = runFunc() + }() + <-done + }) +} + +func TestHandler_HandleError(t *testing.T) { + t.Parallel() + + t.Run("Precondition Error Logged as Info", func(t *testing.T) { + t.Parallel() + + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockLogger := mock.NewMockLogger(mockCtrl) + mockLogger.EXPECT().Infof("preconditions not met: error").Times(1) + handler := NewHandler(mockLogger) + + sourceError := exceptions.PreconditionError(errGeneric.Error()) + err := handler.HandleError(sourceError) + assert.Equal(t, sourceError, err) + }) + +} diff --git a/orcareduce/exceptions/logger/logger.go b/orcareduce/exceptions/logger/logger.go new file mode 100644 index 0000000..dad971e --- /dev/null +++ b/orcareduce/exceptions/logger/logger.go @@ -0,0 +1,35 @@ +package exceptions + +import ( + "github.com/golang/glog" + "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" +) + +// DefaultLogger fetches a simple default logger. +// The logger it returns uses glog as a logger backend. +func DefaultLogger() exceptions.Logger { + return logger{ + errorf: glog.Errorf, + infof: glog.Infof, + } +} + +type logger struct { + errorf func(string, ...interface{}) + infof func(string, ...interface{}) +} + +// Error logs the error and message as severity Error. +func (l logger) Error(err error, msg string) { + l.Errorf("%s: %+v", msg, err) +} + +// Infof logs the format string and args as severity Info. +func (l logger) Infof(format string, args ...interface{}) { + l.infof(format, args...) +} + +// Errorf logs the format string and args as severity Error +func (l logger) Errorf(format string, args ...interface{}) { + l.errorf(format, args...) +} diff --git a/orcareduce/exceptions/logger/logger_test.go b/orcareduce/exceptions/logger/logger_test.go new file mode 100644 index 0000000..978dbd9 --- /dev/null +++ b/orcareduce/exceptions/logger/logger_test.go @@ -0,0 +1,56 @@ +package exceptions + +import ( + "fmt" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestLogger_Errorf(t *testing.T) { + expectedFormat := "format %s" + arg := "arg" + + logger := logger{ + errorf: func(format string, args ...interface{}) { + assert.Equal(t, expectedFormat, format) + require.Equal(t, 1, len(args)) + assert.Equal(t, "arg", args[0].(string)) + }, + } + logger.Errorf(expectedFormat, arg) + DefaultLogger().Errorf(expectedFormat, arg) +} + +func TestLogger_Infof(t *testing.T) { + expectedFormat := "format %s" + arg := "arg" + + logger := logger{ + infof: func(format string, args ...interface{}) { + assert.Equal(t, expectedFormat, format) + require.Equal(t, 1, len(args)) + assert.Equal(t, "arg", args[0].(string)) + }, + } + logger.Infof(expectedFormat, arg) + DefaultLogger().Infof(expectedFormat, arg) +} + +func TestLogger_Error(t *testing.T) { + expectedError := fmt.Errorf("error") + expectedFormat := "%s: %+v" + expectedMessage := "msg" + + logger := logger{ + errorf: func(format string, args ...interface{}) { + assert.Equal(t, expectedFormat, format) + require.Equal(t, 2, len(args)) + assert.Equal(t, expectedMessage, args[0].(string)) + assert.Equal(t, expectedError, args[1].(error)) + }, + } + logger.Error(expectedError, expectedMessage) + DefaultLogger().Error(expectedError, expectedMessage) +} diff --git a/orcareduce/exceptions/mock/mock.go b/orcareduce/exceptions/mock/mock.go new file mode 100644 index 0000000..94f321e --- /dev/null +++ b/orcareduce/exceptions/mock/mock.go @@ -0,0 +1,143 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/mkuchenbecker/orcareduce/orcareduce/exceptions (interfaces: Logger,Handler) + +// Package mock is a generated GoMock package. +package mock + +import ( + gomock "github.com/golang/mock/gomock" + exceptions "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" + reflect "reflect" +) + +// MockLogger is a mock of Logger interface +type MockLogger struct { + ctrl *gomock.Controller + recorder *MockLoggerMockRecorder +} + +// MockLoggerMockRecorder is the mock recorder for MockLogger +type MockLoggerMockRecorder struct { + mock *MockLogger +} + +// NewMockLogger creates a new mock instance +func NewMockLogger(ctrl *gomock.Controller) *MockLogger { + mock := &MockLogger{ctrl: ctrl} + mock.recorder = &MockLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { + return m.recorder +} + +// Error mocks base method +func (m *MockLogger) Error(arg0 error, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Error", arg0, arg1) +} + +// Error indicates an expected call of Error +func (mr *MockLoggerMockRecorder) Error(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0, arg1) +} + +// Errorf mocks base method +func (m *MockLogger) Errorf(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf +func (mr *MockLoggerMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) +} + +// Infof mocks base method +func (m *MockLogger) Infof(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Infof", varargs...) +} + +// Infof indicates an expected call of Infof +func (mr *MockLoggerMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...) +} + +// MockHandler is a mock of Handler interface +type MockHandler struct { + ctrl *gomock.Controller + recorder *MockHandlerMockRecorder +} + +// MockHandlerMockRecorder is the mock recorder for MockHandler +type MockHandlerMockRecorder struct { + mock *MockHandler +} + +// NewMockHandler creates a new mock instance +func NewMockHandler(ctrl *gomock.Controller) *MockHandler { + mock := &MockHandler{ctrl: ctrl} + mock.recorder = &MockHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockHandler) EXPECT() *MockHandlerMockRecorder { + return m.recorder +} + +// HandleError mocks base method +func (m *MockHandler) HandleError(arg0 error) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleError", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleError indicates an expected call of HandleError +func (mr *MockHandlerMockRecorder) HandleError(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleError", reflect.TypeOf((*MockHandler)(nil).HandleError), arg0) +} + +// HandlePanic mocks base method +func (m *MockHandler) HandlePanic(arg0 *error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "HandlePanic", arg0) +} + +// HandlePanic indicates an expected call of HandlePanic +func (mr *MockHandlerMockRecorder) HandlePanic(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockHandler)(nil).HandlePanic), arg0) +} + +// RunAsync mocks base method +func (m *MockHandler) RunAsync(arg0 exceptions.RunFunc) exceptions.SyncFunc { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunAsync", arg0) + ret0, _ := ret[0].(exceptions.SyncFunc) + return ret0 +} + +// RunAsync indicates an expected call of RunAsync +func (mr *MockHandlerMockRecorder) RunAsync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunAsync", reflect.TypeOf((*MockHandler)(nil).RunAsync), arg0) +} diff --git a/orcareduce/exceptions/types.go b/orcareduce/exceptions/types.go new file mode 100644 index 0000000..4e96a4a --- /dev/null +++ b/orcareduce/exceptions/types.go @@ -0,0 +1,78 @@ +package exceptions + +import ( + "fmt" +) + +// PreconditionError is a runtime error that indicates all the preconditions to run a function are not yet satisfied. +// It should generally be used and regarded as a non-serious error that is expected during the normal operation +// of a service or state machine. For example, while its possible to guarentee all preconditions for a function are +// met at the time the function is called it's not possible to guarentee they will still be met at the time of +// preconditions are checked. +type PreconditionError string + +// Error implements the error interface function so PreconditionError can be used +// as an error object. +func (err PreconditionError) Error() string { + return fmt.Sprintf("preconditions not met: %s", string(err)) +} + +//go:generate mockgen -destination=./mock/mock.go -package=mock github.com/mkuchenbecker/orcareduce/orcareduce/exceptions Logger,Handler +// Logger is an abstraction over a logging library. Its simple as to remain unopinionated on +// the logging mechanism. +type Logger interface { + // Errorf logs the format string and args as severity ERROR. + Errorf(format string, args ...interface{}) + // Error logs an error and message. + Error(err error, msg string) + // Infof logs a format string and args as severity INFO. + Infof(format string, args ...interface{}) +} + +type Handler interface { + // HandleError logs and stats the parameter error and returns that same error to the caller. + // Supplying a nil error is a no-op. The intent is to be able to have the following: + // + // func foo() error { + // err := bar() + // return handler.HandleError(err) + // } + // + HandleError(error) error + + // HandlePanic captures any panics and populates the parameter err pointer with details about the panic if the + // error is not already set. HandlePanic should be called via defer. + // + // func foo() error { + // var err error + // done := make(chan bool) + // runFunc := func () error { + // defer handler.HandlePanic(&err) // called via defer + // err := bar() // might panic + // done <- true + // } + // go runFunc() + // <- done + // return err + // } + // + HandlePanic(err *error) + + // RunAsync safely runs a RunFunc via a goroutine and returns a SyncFunc. + // + // runFunc := func () error { + // return bar("baz") + // } + // + // syncFunc := handler.RunAsync(runFunc) + // err := syncFunc() + // + // + RunAsync(f RunFunc) SyncFunc +} + +// A SyncFunc is a function with no parameters that returns an error. +type SyncFunc func() error + +// A RunFunc is a function with no parameters that returns an error. +type RunFunc func() error From 5a653bf911507496d7698ff4504f3ad431d33def Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Mon, 22 Jun 2020 08:59:12 -0700 Subject: [PATCH 06/11] refactor and increase coverage --- orcareduce/{chaos/iface.go => chaos.go} | 2 +- orcareduce/chaos/chaos.go | 52 +- orcareduce/chaos/chaos_test.go | 49 +- orcareduce/chaos/latency.go | 64 ++ orcareduce/chaos/latency_test.go | 34 + orcareduce/exceptions/doc.go | 14 - orcareduce/exceptions/mock/mock.go | 143 ---- orcareduce/exceptions/types.go | 60 -- orcareduce/exceptions/types_test.go | 12 + orcareduce/handler.go | 51 ++ .../{exceptions => }/handler/handler.go | 9 +- .../{exceptions => }/handler/handler_test.go | 5 +- orcareduce/identifier/identifier.go | 69 ++ orcareduce/identifier/identifier_test.go | 1 + orcareduce/iface.go | 104 --- orcareduce/logger.go | 12 + orcareduce/{exceptions => }/logger/logger.go | 6 +- .../{exceptions => }/logger/logger_test.go | 2 +- orcareduce/mock/mock.go | 627 ++++++++++++++++++ orcareduce/mockgen.go | 3 + orcareduce/orcareduce.go | 38 ++ 21 files changed, 960 insertions(+), 397 deletions(-) rename orcareduce/{chaos/iface.go => chaos.go} (88%) create mode 100644 orcareduce/chaos/latency.go create mode 100644 orcareduce/chaos/latency_test.go delete mode 100644 orcareduce/exceptions/doc.go delete mode 100644 orcareduce/exceptions/mock/mock.go create mode 100644 orcareduce/exceptions/types_test.go create mode 100644 orcareduce/handler.go rename orcareduce/{exceptions => }/handler/handler.go (88%) rename orcareduce/{exceptions => }/handler/handler_test.go (97%) create mode 100644 orcareduce/identifier/identifier.go create mode 100644 orcareduce/identifier/identifier_test.go delete mode 100644 orcareduce/iface.go create mode 100644 orcareduce/logger.go rename orcareduce/{exceptions => }/logger/logger.go (86%) rename orcareduce/{exceptions => }/logger/logger_test.go (98%) create mode 100644 orcareduce/mock/mock.go create mode 100644 orcareduce/mockgen.go create mode 100644 orcareduce/orcareduce.go diff --git a/orcareduce/chaos/iface.go b/orcareduce/chaos.go similarity index 88% rename from orcareduce/chaos/iface.go rename to orcareduce/chaos.go index c188d10..e6764b3 100644 --- a/orcareduce/chaos/iface.go +++ b/orcareduce/chaos.go @@ -1,4 +1,4 @@ -package chaos +package orcareduce type Injector interface { Latency() diff --git a/orcareduce/chaos/chaos.go b/orcareduce/chaos/chaos.go index d5c3f0a..67e0b35 100644 --- a/orcareduce/chaos/chaos.go +++ b/orcareduce/chaos/chaos.go @@ -4,6 +4,8 @@ import ( "fmt" "math/rand" "time" + + "github.com/mkuchenbecker/orcareduce/orcareduce" ) type randomStaticErrors struct { @@ -18,12 +20,8 @@ func (cfg *randomStaticErrors) Error() error { return nil } -type staticLatency struct { - latency time.Duration -} - type metaErrors struct { - errors []ErrorInjector + errors []orcareduce.ErrorInjector } func (cfg *metaErrors) Error() error { @@ -36,43 +34,9 @@ func (cfg *metaErrors) Error() error { return nil } -func (cfg *staticLatency) Latency() { - time.Sleep(cfg.latency) -} - -type dynamicLatency struct { - maxLatency time.Duration -} - -func (cfg *dynamicLatency) Latency() { - val := rand.Int63n(int64(cfg.maxLatency)) - time.Sleep(time.Duration(val)) -} - -type randomLatency struct { - latency LatencyInjector - percent float64 -} - -func (cfg *randomLatency) Latency() { - if rand.Float64() < cfg.percent { - cfg.latency.Latency() - } -} - -type metaLatency struct { - latency []LatencyInjector -} - -func (this *metaLatency) Latency() { - for _, latency := range this.latency { - latency.Latency() - } -} - type metaInjector struct { - latency LatencyInjector - errors ErrorInjector + latency orcareduce.LatencyInjector + errors orcareduce.ErrorInjector } func (cfg *metaInjector) Latency() { @@ -83,10 +47,10 @@ func (cfg *metaInjector) Error() error { return cfg.errors.Error() } -func NewDefault() Injector { +func NewDefault() orcareduce.Injector { return &metaInjector{ latency: &metaLatency{ - latency: []LatencyInjector{ + latency: []orcareduce.LatencyInjector{ &staticLatency{latency: 20 * time.Millisecond}, &dynamicLatency{maxLatency: 20 * time.Millisecond}, &randomLatency{percent: 0.1, latency: &dynamicLatency{maxLatency: 100 * time.Millisecond}}, @@ -96,7 +60,7 @@ func NewDefault() Injector { }, }, errors: &metaErrors{ - errors: []ErrorInjector{ + errors: []orcareduce.ErrorInjector{ &randomStaticErrors{err: fmt.Errorf("[chaos] encountered an error"), errorRate: 0.1}, }, }, diff --git a/orcareduce/chaos/chaos_test.go b/orcareduce/chaos/chaos_test.go index ce88824..1af766d 100644 --- a/orcareduce/chaos/chaos_test.go +++ b/orcareduce/chaos/chaos_test.go @@ -1,26 +1,35 @@ package chaos -import ( - "math/rand" - "testing" - "time" +// func TestDefaultChaos(t *testing.T) { +// rand.Seed(5) // Static seed so the test is deterministic. +// chaos := NewDefault() - "github.com/stretchr/testify/assert" -) +// now := time.Now() +// chaos.Latency() +// assert.True(t, time.Since(now) >= time.Millisecond*20) -func TestDefaultChaos(t *testing.T) { - rand.Seed(5) // Static seed so the test is deterministic. - chaos := NewDefault() +// errCount := 0 +// for i := 0; i < 1000; i++ { +// if err := chaos.Error(); err != nil { +// errCount++ +// } +// } +// assert.Equal(t, 105, errCount) +// } - now := time.Now() - chaos.Latency() - assert.True(t, time.Since(now) >= time.Millisecond*20) +// func TestStaticLatency(t *testing.T) { +// rand.Seed(5) // Static seed so the test is deterministic. +// chaos := NewDefault() - errCount := 0 - for i := 0; i < 1000; i++ { - if err := chaos.Error(); err != nil { - errCount++ - } - } - assert.Equal(t, 105, errCount) -} +// now := time.Now() +// chaos.Latency() +// assert.True(t, time.Since(now) >= time.Millisecond*20) + +// errCount := 0 +// for i := 0; i < 1000; i++ { +// if err := chaos.Error(); err != nil { +// errCount++ +// } +// } +// assert.Equal(t, 105, errCount) +// } diff --git a/orcareduce/chaos/latency.go b/orcareduce/chaos/latency.go new file mode 100644 index 0000000..b62a6c3 --- /dev/null +++ b/orcareduce/chaos/latency.go @@ -0,0 +1,64 @@ +package chaos + +import ( + "math/rand" + "time" + + "github.com/mkuchenbecker/orcareduce/orcareduce" +) + +type sleepFunction func(time.Duration) + +type staticLatency struct { + latency time.Duration + sleep sleepFunction +} + +func (cfg *staticLatency) Latency() { + time.Sleep(cfg.latency) +} + +func NewStaticLatency(latency time.Duration) orcareduce.LatencyInjector { + return &staticLatency{ + sleep: time.Sleep, + latency: latency, + } +} + +type dynamicLatency struct { + maxLatency time.Duration + sleep sleepFunction +} + +func (cfg *dynamicLatency) Latency() { + val := rand.Int63n(int64(cfg.maxLatency)) + cfg.sleep(time.Duration(val)) +} + +func NewDynamicLatency(maxLatency time.Duration) orcareduce.LatencyInjector { + return &dynamicLatency{ + sleep: time.Sleep, + maxLatency: maxLatency, + } +} + +type randomLatency struct { + latency orcareduce.LatencyInjector + percent float64 +} + +func (cfg *randomLatency) Latency() { + if rand.Float64() < cfg.percent { + cfg.latency.Latency() + } +} + +type metaLatency struct { + latency []orcareduce.LatencyInjector +} + +func (this *metaLatency) Latency() { + for _, latency := range this.latency { + latency.Latency() + } +} diff --git a/orcareduce/chaos/latency_test.go b/orcareduce/chaos/latency_test.go new file mode 100644 index 0000000..bf5028c --- /dev/null +++ b/orcareduce/chaos/latency_test.go @@ -0,0 +1,34 @@ +package chaos + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestStaticLatency(t *testing.T) { + t.Parallel() + latency := 100 * time.Millisecond + static := NewStaticLatency(latency).(*staticLatency) + + static.sleep = func(duration time.Duration) { + assert.Equal(t, latency, duration) + } + + static.Latency() +} + +func TestDynamicLatency(t *testing.T) { + t.Parallel() + rand.Seed(1) + maxLatency := 100 * time.Millisecond + dynamic := NewDynamicLatency(maxLatency).(*dynamicLatency) + + dynamic.sleep = func(duration time.Duration) { + assert.True(t, maxLatency >= duration) + } + + dynamic.Latency() +} diff --git a/orcareduce/exceptions/doc.go b/orcareduce/exceptions/doc.go deleted file mode 100644 index b87641c..0000000 --- a/orcareduce/exceptions/doc.go +++ /dev/null @@ -1,14 +0,0 @@ -package exceptions - -/* - -exceptions is a package dedicated to the handling and logging of errors and messages in the system, -as well as functionality to safely run asycronous go code in a manor that is visible and protected -from exceptions bringing down a service. - -The core functionality works around a Handler object which handles the execution of asyncrounous -tasks and has the ability to consistently log across the codebase. The intended use of a handler -is all processes have access to a Handler, which acts as a common method of running ansyc tasks -and structured logging of errors. - -*/ diff --git a/orcareduce/exceptions/mock/mock.go b/orcareduce/exceptions/mock/mock.go deleted file mode 100644 index 94f321e..0000000 --- a/orcareduce/exceptions/mock/mock.go +++ /dev/null @@ -1,143 +0,0 @@ -// Code generated by MockGen. DO NOT EDIT. -// Source: github.com/mkuchenbecker/orcareduce/orcareduce/exceptions (interfaces: Logger,Handler) - -// Package mock is a generated GoMock package. -package mock - -import ( - gomock "github.com/golang/mock/gomock" - exceptions "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" - reflect "reflect" -) - -// MockLogger is a mock of Logger interface -type MockLogger struct { - ctrl *gomock.Controller - recorder *MockLoggerMockRecorder -} - -// MockLoggerMockRecorder is the mock recorder for MockLogger -type MockLoggerMockRecorder struct { - mock *MockLogger -} - -// NewMockLogger creates a new mock instance -func NewMockLogger(ctrl *gomock.Controller) *MockLogger { - mock := &MockLogger{ctrl: ctrl} - mock.recorder = &MockLoggerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use -func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { - return m.recorder -} - -// Error mocks base method -func (m *MockLogger) Error(arg0 error, arg1 string) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "Error", arg0, arg1) -} - -// Error indicates an expected call of Error -func (mr *MockLoggerMockRecorder) Error(arg0, arg1 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0, arg1) -} - -// Errorf mocks base method -func (m *MockLogger) Errorf(arg0 string, arg1 ...interface{}) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0} - for _, a := range arg1 { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "Errorf", varargs...) -} - -// Errorf indicates an expected call of Errorf -func (mr *MockLoggerMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) -} - -// Infof mocks base method -func (m *MockLogger) Infof(arg0 string, arg1 ...interface{}) { - m.ctrl.T.Helper() - varargs := []interface{}{arg0} - for _, a := range arg1 { - varargs = append(varargs, a) - } - m.ctrl.Call(m, "Infof", varargs...) -} - -// Infof indicates an expected call of Infof -func (mr *MockLoggerMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - varargs := append([]interface{}{arg0}, arg1...) - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...) -} - -// MockHandler is a mock of Handler interface -type MockHandler struct { - ctrl *gomock.Controller - recorder *MockHandlerMockRecorder -} - -// MockHandlerMockRecorder is the mock recorder for MockHandler -type MockHandlerMockRecorder struct { - mock *MockHandler -} - -// NewMockHandler creates a new mock instance -func NewMockHandler(ctrl *gomock.Controller) *MockHandler { - mock := &MockHandler{ctrl: ctrl} - mock.recorder = &MockHandlerMockRecorder{mock} - return mock -} - -// EXPECT returns an object that allows the caller to indicate expected use -func (m *MockHandler) EXPECT() *MockHandlerMockRecorder { - return m.recorder -} - -// HandleError mocks base method -func (m *MockHandler) HandleError(arg0 error) error { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "HandleError", arg0) - ret0, _ := ret[0].(error) - return ret0 -} - -// HandleError indicates an expected call of HandleError -func (mr *MockHandlerMockRecorder) HandleError(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleError", reflect.TypeOf((*MockHandler)(nil).HandleError), arg0) -} - -// HandlePanic mocks base method -func (m *MockHandler) HandlePanic(arg0 *error) { - m.ctrl.T.Helper() - m.ctrl.Call(m, "HandlePanic", arg0) -} - -// HandlePanic indicates an expected call of HandlePanic -func (mr *MockHandlerMockRecorder) HandlePanic(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockHandler)(nil).HandlePanic), arg0) -} - -// RunAsync mocks base method -func (m *MockHandler) RunAsync(arg0 exceptions.RunFunc) exceptions.SyncFunc { - m.ctrl.T.Helper() - ret := m.ctrl.Call(m, "RunAsync", arg0) - ret0, _ := ret[0].(exceptions.SyncFunc) - return ret0 -} - -// RunAsync indicates an expected call of RunAsync -func (mr *MockHandlerMockRecorder) RunAsync(arg0 interface{}) *gomock.Call { - mr.mock.ctrl.T.Helper() - return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunAsync", reflect.TypeOf((*MockHandler)(nil).RunAsync), arg0) -} diff --git a/orcareduce/exceptions/types.go b/orcareduce/exceptions/types.go index 4e96a4a..db5f695 100644 --- a/orcareduce/exceptions/types.go +++ b/orcareduce/exceptions/types.go @@ -16,63 +16,3 @@ type PreconditionError string func (err PreconditionError) Error() string { return fmt.Sprintf("preconditions not met: %s", string(err)) } - -//go:generate mockgen -destination=./mock/mock.go -package=mock github.com/mkuchenbecker/orcareduce/orcareduce/exceptions Logger,Handler -// Logger is an abstraction over a logging library. Its simple as to remain unopinionated on -// the logging mechanism. -type Logger interface { - // Errorf logs the format string and args as severity ERROR. - Errorf(format string, args ...interface{}) - // Error logs an error and message. - Error(err error, msg string) - // Infof logs a format string and args as severity INFO. - Infof(format string, args ...interface{}) -} - -type Handler interface { - // HandleError logs and stats the parameter error and returns that same error to the caller. - // Supplying a nil error is a no-op. The intent is to be able to have the following: - // - // func foo() error { - // err := bar() - // return handler.HandleError(err) - // } - // - HandleError(error) error - - // HandlePanic captures any panics and populates the parameter err pointer with details about the panic if the - // error is not already set. HandlePanic should be called via defer. - // - // func foo() error { - // var err error - // done := make(chan bool) - // runFunc := func () error { - // defer handler.HandlePanic(&err) // called via defer - // err := bar() // might panic - // done <- true - // } - // go runFunc() - // <- done - // return err - // } - // - HandlePanic(err *error) - - // RunAsync safely runs a RunFunc via a goroutine and returns a SyncFunc. - // - // runFunc := func () error { - // return bar("baz") - // } - // - // syncFunc := handler.RunAsync(runFunc) - // err := syncFunc() - // - // - RunAsync(f RunFunc) SyncFunc -} - -// A SyncFunc is a function with no parameters that returns an error. -type SyncFunc func() error - -// A RunFunc is a function with no parameters that returns an error. -type RunFunc func() error diff --git a/orcareduce/exceptions/types_test.go b/orcareduce/exceptions/types_test.go new file mode 100644 index 0000000..39e0970 --- /dev/null +++ b/orcareduce/exceptions/types_test.go @@ -0,0 +1,12 @@ +package exceptions + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestPreconditionError(t *testing.T) { + err := PreconditionError("error") + assert.Equal(t, "preconditions not met: error", err.Error()) +} diff --git a/orcareduce/handler.go b/orcareduce/handler.go new file mode 100644 index 0000000..2025901 --- /dev/null +++ b/orcareduce/handler.go @@ -0,0 +1,51 @@ +package orcareduce + +// Handler is an object that handles async tasks and the standard processing of errors accross an application +// and safe running of async tasks in the system. +type Handler interface { + // HandleError logs and stats the parameter error and returns that same error to the caller. + // Supplying a nil error is a no-op. The intent is to be able to have the following: + // + // func foo() error { + // err := bar() + // return handler.HandleError(err) + // } + // + HandleError(error) error + + // HandlePanic captures any panics and populates the parameter err pointer with details about the panic if the + // error is not already set. HandlePanic should be called via defer. + // + // func foo() error { + // var err error + // done := make(chan bool) + // runFunc := func () error { + // defer handler.HandlePanic(&err) // called via defer + // err := bar() // might panic + // done <- true + // } + // go runFunc() + // <- done + // return err + // } + // + HandlePanic(err *error) + + // RunAsync safely runs a RunFunc via a goroutine and returns a SyncFunc. + // + // runFunc := func () error { + // return bar("baz") + // } + // + // syncFunc := handler.RunAsync(runFunc) + // err := syncFunc() + // + // + RunAsync(f RunFunc) SyncFunc +} + +// A SyncFunc is a function with no parameters that returns an error. +type SyncFunc func() error + +// A RunFunc is a function with no parameters that returns an error. +type RunFunc func() error diff --git a/orcareduce/exceptions/handler/handler.go b/orcareduce/handler/handler.go similarity index 88% rename from orcareduce/exceptions/handler/handler.go rename to orcareduce/handler/handler.go index 6f2ca10..23a5b63 100644 --- a/orcareduce/exceptions/handler/handler.go +++ b/orcareduce/handler/handler.go @@ -1,6 +1,7 @@ -package exceptions +package handler import ( + "github.com/mkuchenbecker/orcareduce/orcareduce" "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" "github.com/pkg/errors" ) @@ -9,7 +10,7 @@ import ( // It has basic functionality and an internal logger so it can log // errors it encountners. type workflowHandler struct { - logger exceptions.Logger + logger orcareduce.Logger } // HandleError logs an error at the appropriate level and returns @@ -52,7 +53,7 @@ func (w workflowHandler) HandlePanic(err *error) { // are returned by the RunFunc, and recovers from any panics in the RunFunc. // The return value SyncFunc is a function that blocks until the RunFunc has // completed execution. -func (w workflowHandler) RunAsync(f exceptions.RunFunc) exceptions.SyncFunc { +func (w workflowHandler) RunAsync(f orcareduce.RunFunc) orcareduce.SyncFunc { done := make(chan error) go func() { var err error @@ -69,6 +70,6 @@ func (w workflowHandler) RunAsync(f exceptions.RunFunc) exceptions.SyncFunc { } // NewHandler makes a Handler using the supplied logger. -func NewHandler(logger exceptions.Logger) exceptions.Handler { +func NewHandler(logger orcareduce.Logger) orcareduce.Handler { return workflowHandler{logger: logger} } diff --git a/orcareduce/exceptions/handler/handler_test.go b/orcareduce/handler/handler_test.go similarity index 97% rename from orcareduce/exceptions/handler/handler_test.go rename to orcareduce/handler/handler_test.go index c55adac..46b9da1 100644 --- a/orcareduce/exceptions/handler/handler_test.go +++ b/orcareduce/handler/handler_test.go @@ -1,4 +1,4 @@ -package exceptions +package handler import ( "fmt" @@ -7,7 +7,7 @@ import ( "github.com/golang/mock/gomock" "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" - "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions/mock" + "github.com/mkuchenbecker/orcareduce/orcareduce/mock" "github.com/stretchr/testify/assert" ) @@ -143,5 +143,4 @@ func TestHandler_HandleError(t *testing.T) { err := handler.HandleError(sourceError) assert.Equal(t, sourceError, err) }) - } diff --git a/orcareduce/identifier/identifier.go b/orcareduce/identifier/identifier.go new file mode 100644 index 0000000..4d32553 --- /dev/null +++ b/orcareduce/identifier/identifier.go @@ -0,0 +1,69 @@ +package identifier + +import ( + "bytes" + "crypto/sha256" + "time" + + "github.com/mkuchenbecker/orcareduce/orcareduce" +) + +type identifier struct { + id string + scope orcareduce.Scope + level int + parent *identifier +} + +func (this *identifier) Lineage() []orcareduce.ID { + out := make([]orcareduce.ID, 0) + curr := this + for { + out = append(out, curr) + if curr.parent == nil { + break + } + curr = curr.parent + } + return out +} + +func (this *identifier) String() string { + lineage := this.Lineage() + var buf bytes.Buffer + for i := len(lineage) - 1; i >= 0; i++ { + buf.WriteString(lineage[i].Value()) + } + return buf.String() +} + +func (this *identifier) Value() string { + return this.id +} + +func (this *identifier) Parent() orcareduce.ID { + return this.parent +} + +func (this *identifier) NewChild() orcareduce.ID { + out := New() + out.level = this.level + 1 + out.parent = this + return out +} + +func (this *identifier) NewScopedChild(scope orcareduce.Scope) orcareduce.ID { + out := New() + out.scope = scope + out.level = this.level + 1 + out.parent = this + return out +} + +func New() *identifier { + sha := sha256.New() + val := sha.Sum([]byte(time.Now().String())) // Re-hash the parent ID. + return &identifier{ + id: string(val), + } +} diff --git a/orcareduce/identifier/identifier_test.go b/orcareduce/identifier/identifier_test.go new file mode 100644 index 0000000..3aac621 --- /dev/null +++ b/orcareduce/identifier/identifier_test.go @@ -0,0 +1 @@ +package identifier diff --git a/orcareduce/iface.go b/orcareduce/iface.go deleted file mode 100644 index a25aba0..0000000 --- a/orcareduce/iface.go +++ /dev/null @@ -1,104 +0,0 @@ -package orcareduce - -import ( - "bytes" - "crypto/sha256" - "time" -) - -// Reactor is a repeatable actor. -type Reactor interface { - Preconditions() error - Act() error - SignalSuccess() error - Notify() - ID() ID -} - -type Precondition interface { - Check() error -} - -// ID is a generalized interface for identifying reactors. -type ID interface { - String() string - Value() string - Lineage() []ID - Parent() ID - NewChild() ID - NewScopedChild(scope Scope) ID -} - -type Director interface { - GetNextActor() error - Act() error - ID() ID -} - -type ActorDataSink interface { - Success(Reactor) error - Failure(Reactor) - Attempt(Reactor) error -} - -type Scope string - -type identifier struct { - id string - scope Scope - level int - parent *identifier -} - -func (this *identifier) Lineage() []ID { - out := make([]ID, 0) - curr := this - for { - out = append(out, curr) - if curr.parent == nil { - break - } - curr = curr.parent - } - return out -} - -func (this *identifier) String() string { - lineage := this.Lineage() - var buf bytes.Buffer - for i := len(lineage) - 1; i >= 0; i++ { - buf.WriteString(lineage[i].Value()) - } - return buf.String() -} - -func (this *identifier) Value() string { - return this.id -} - -func (this *identifier) Parent() ID { - return this.parent -} - -func (this *identifier) NewChild() ID { - out := NewID() - out.level = this.level + 1 - out.parent = this - return out -} - -func (this *identifier) NewScopedChild(scope Scope) ID { - out := NewID() - out.scope = scope - out.level = this.level + 1 - out.parent = this - return out -} - -func NewID() *identifier { - sha := sha256.New() - val := sha.Sum([]byte(time.Now().String())) // Re-hash the parent ID. - return &identifier{ - id: string(val), - } -} diff --git a/orcareduce/logger.go b/orcareduce/logger.go new file mode 100644 index 0000000..a71abdc --- /dev/null +++ b/orcareduce/logger.go @@ -0,0 +1,12 @@ +package orcareduce + +// Logger is an abstraction over a logging library. Its simple as to remain unopinionated on +// the logging mechanism. +type Logger interface { + // Errorf logs the format string and args as severity ERROR. + Errorf(format string, args ...interface{}) + // Error logs an error and message. + Error(err error, msg string) + // Infof logs a format string and args as severity INFO. + Infof(format string, args ...interface{}) +} diff --git a/orcareduce/exceptions/logger/logger.go b/orcareduce/logger/logger.go similarity index 86% rename from orcareduce/exceptions/logger/logger.go rename to orcareduce/logger/logger.go index dad971e..6212b4f 100644 --- a/orcareduce/exceptions/logger/logger.go +++ b/orcareduce/logger/logger.go @@ -1,13 +1,13 @@ -package exceptions +package logger import ( "github.com/golang/glog" - "github.com/mkuchenbecker/orcareduce/orcareduce/exceptions" + "github.com/mkuchenbecker/orcareduce/orcareduce" ) // DefaultLogger fetches a simple default logger. // The logger it returns uses glog as a logger backend. -func DefaultLogger() exceptions.Logger { +func DefaultLogger() orcareduce.Logger { return logger{ errorf: glog.Errorf, infof: glog.Infof, diff --git a/orcareduce/exceptions/logger/logger_test.go b/orcareduce/logger/logger_test.go similarity index 98% rename from orcareduce/exceptions/logger/logger_test.go rename to orcareduce/logger/logger_test.go index 978dbd9..4d137c8 100644 --- a/orcareduce/exceptions/logger/logger_test.go +++ b/orcareduce/logger/logger_test.go @@ -1,4 +1,4 @@ -package exceptions +package logger import ( "fmt" diff --git a/orcareduce/mock/mock.go b/orcareduce/mock/mock.go new file mode 100644 index 0000000..9f8eed4 --- /dev/null +++ b/orcareduce/mock/mock.go @@ -0,0 +1,627 @@ +// Code generated by MockGen. DO NOT EDIT. +// Source: github.com/mkuchenbecker/orcareduce/orcareduce (interfaces: Reactor,Logger,Handler,Precondition,ID,Director,ActorDataSink,Injector,ErrorInjector,LatencyInjector) + +// Package mock is a generated GoMock package. +package mock + +import ( + gomock "github.com/golang/mock/gomock" + orcareduce "github.com/mkuchenbecker/orcareduce/orcareduce" + reflect "reflect" +) + +// MockReactor is a mock of Reactor interface +type MockReactor struct { + ctrl *gomock.Controller + recorder *MockReactorMockRecorder +} + +// MockReactorMockRecorder is the mock recorder for MockReactor +type MockReactorMockRecorder struct { + mock *MockReactor +} + +// NewMockReactor creates a new mock instance +func NewMockReactor(ctrl *gomock.Controller) *MockReactor { + mock := &MockReactor{ctrl: ctrl} + mock.recorder = &MockReactorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockReactor) EXPECT() *MockReactorMockRecorder { + return m.recorder +} + +// Act mocks base method +func (m *MockReactor) Act() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Act") + ret0, _ := ret[0].(error) + return ret0 +} + +// Act indicates an expected call of Act +func (mr *MockReactorMockRecorder) Act() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Act", reflect.TypeOf((*MockReactor)(nil).Act)) +} + +// ID mocks base method +func (m *MockReactor) ID() orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(orcareduce.ID) + return ret0 +} + +// ID indicates an expected call of ID +func (mr *MockReactorMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockReactor)(nil).ID)) +} + +// Notify mocks base method +func (m *MockReactor) Notify() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Notify") +} + +// Notify indicates an expected call of Notify +func (mr *MockReactorMockRecorder) Notify() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Notify", reflect.TypeOf((*MockReactor)(nil).Notify)) +} + +// Preconditions mocks base method +func (m *MockReactor) Preconditions() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Preconditions") + ret0, _ := ret[0].(error) + return ret0 +} + +// Preconditions indicates an expected call of Preconditions +func (mr *MockReactorMockRecorder) Preconditions() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Preconditions", reflect.TypeOf((*MockReactor)(nil).Preconditions)) +} + +// SignalSuccess mocks base method +func (m *MockReactor) SignalSuccess() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "SignalSuccess") + ret0, _ := ret[0].(error) + return ret0 +} + +// SignalSuccess indicates an expected call of SignalSuccess +func (mr *MockReactorMockRecorder) SignalSuccess() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "SignalSuccess", reflect.TypeOf((*MockReactor)(nil).SignalSuccess)) +} + +// MockLogger is a mock of Logger interface +type MockLogger struct { + ctrl *gomock.Controller + recorder *MockLoggerMockRecorder +} + +// MockLoggerMockRecorder is the mock recorder for MockLogger +type MockLoggerMockRecorder struct { + mock *MockLogger +} + +// NewMockLogger creates a new mock instance +func NewMockLogger(ctrl *gomock.Controller) *MockLogger { + mock := &MockLogger{ctrl: ctrl} + mock.recorder = &MockLoggerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockLogger) EXPECT() *MockLoggerMockRecorder { + return m.recorder +} + +// Error mocks base method +func (m *MockLogger) Error(arg0 error, arg1 string) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Error", arg0, arg1) +} + +// Error indicates an expected call of Error +func (mr *MockLoggerMockRecorder) Error(arg0, arg1 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockLogger)(nil).Error), arg0, arg1) +} + +// Errorf mocks base method +func (m *MockLogger) Errorf(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Errorf", varargs...) +} + +// Errorf indicates an expected call of Errorf +func (mr *MockLoggerMockRecorder) Errorf(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Errorf", reflect.TypeOf((*MockLogger)(nil).Errorf), varargs...) +} + +// Infof mocks base method +func (m *MockLogger) Infof(arg0 string, arg1 ...interface{}) { + m.ctrl.T.Helper() + varargs := []interface{}{arg0} + for _, a := range arg1 { + varargs = append(varargs, a) + } + m.ctrl.Call(m, "Infof", varargs...) +} + +// Infof indicates an expected call of Infof +func (mr *MockLoggerMockRecorder) Infof(arg0 interface{}, arg1 ...interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + varargs := append([]interface{}{arg0}, arg1...) + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Infof", reflect.TypeOf((*MockLogger)(nil).Infof), varargs...) +} + +// MockHandler is a mock of Handler interface +type MockHandler struct { + ctrl *gomock.Controller + recorder *MockHandlerMockRecorder +} + +// MockHandlerMockRecorder is the mock recorder for MockHandler +type MockHandlerMockRecorder struct { + mock *MockHandler +} + +// NewMockHandler creates a new mock instance +func NewMockHandler(ctrl *gomock.Controller) *MockHandler { + mock := &MockHandler{ctrl: ctrl} + mock.recorder = &MockHandlerMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockHandler) EXPECT() *MockHandlerMockRecorder { + return m.recorder +} + +// HandleError mocks base method +func (m *MockHandler) HandleError(arg0 error) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "HandleError", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// HandleError indicates an expected call of HandleError +func (mr *MockHandlerMockRecorder) HandleError(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandleError", reflect.TypeOf((*MockHandler)(nil).HandleError), arg0) +} + +// HandlePanic mocks base method +func (m *MockHandler) HandlePanic(arg0 *error) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "HandlePanic", arg0) +} + +// HandlePanic indicates an expected call of HandlePanic +func (mr *MockHandlerMockRecorder) HandlePanic(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "HandlePanic", reflect.TypeOf((*MockHandler)(nil).HandlePanic), arg0) +} + +// RunAsync mocks base method +func (m *MockHandler) RunAsync(arg0 orcareduce.RunFunc) orcareduce.SyncFunc { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "RunAsync", arg0) + ret0, _ := ret[0].(orcareduce.SyncFunc) + return ret0 +} + +// RunAsync indicates an expected call of RunAsync +func (mr *MockHandlerMockRecorder) RunAsync(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "RunAsync", reflect.TypeOf((*MockHandler)(nil).RunAsync), arg0) +} + +// MockPrecondition is a mock of Precondition interface +type MockPrecondition struct { + ctrl *gomock.Controller + recorder *MockPreconditionMockRecorder +} + +// MockPreconditionMockRecorder is the mock recorder for MockPrecondition +type MockPreconditionMockRecorder struct { + mock *MockPrecondition +} + +// NewMockPrecondition creates a new mock instance +func NewMockPrecondition(ctrl *gomock.Controller) *MockPrecondition { + mock := &MockPrecondition{ctrl: ctrl} + mock.recorder = &MockPreconditionMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockPrecondition) EXPECT() *MockPreconditionMockRecorder { + return m.recorder +} + +// Check mocks base method +func (m *MockPrecondition) Check() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Check") + ret0, _ := ret[0].(error) + return ret0 +} + +// Check indicates an expected call of Check +func (mr *MockPreconditionMockRecorder) Check() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Check", reflect.TypeOf((*MockPrecondition)(nil).Check)) +} + +// MockID is a mock of ID interface +type MockID struct { + ctrl *gomock.Controller + recorder *MockIDMockRecorder +} + +// MockIDMockRecorder is the mock recorder for MockID +type MockIDMockRecorder struct { + mock *MockID +} + +// NewMockID creates a new mock instance +func NewMockID(ctrl *gomock.Controller) *MockID { + mock := &MockID{ctrl: ctrl} + mock.recorder = &MockIDMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockID) EXPECT() *MockIDMockRecorder { + return m.recorder +} + +// Lineage mocks base method +func (m *MockID) Lineage() []orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Lineage") + ret0, _ := ret[0].([]orcareduce.ID) + return ret0 +} + +// Lineage indicates an expected call of Lineage +func (mr *MockIDMockRecorder) Lineage() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Lineage", reflect.TypeOf((*MockID)(nil).Lineage)) +} + +// NewChild mocks base method +func (m *MockID) NewChild() orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewChild") + ret0, _ := ret[0].(orcareduce.ID) + return ret0 +} + +// NewChild indicates an expected call of NewChild +func (mr *MockIDMockRecorder) NewChild() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewChild", reflect.TypeOf((*MockID)(nil).NewChild)) +} + +// NewScopedChild mocks base method +func (m *MockID) NewScopedChild(arg0 orcareduce.Scope) orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "NewScopedChild", arg0) + ret0, _ := ret[0].(orcareduce.ID) + return ret0 +} + +// NewScopedChild indicates an expected call of NewScopedChild +func (mr *MockIDMockRecorder) NewScopedChild(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "NewScopedChild", reflect.TypeOf((*MockID)(nil).NewScopedChild), arg0) +} + +// Parent mocks base method +func (m *MockID) Parent() orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Parent") + ret0, _ := ret[0].(orcareduce.ID) + return ret0 +} + +// Parent indicates an expected call of Parent +func (mr *MockIDMockRecorder) Parent() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Parent", reflect.TypeOf((*MockID)(nil).Parent)) +} + +// String mocks base method +func (m *MockID) String() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "String") + ret0, _ := ret[0].(string) + return ret0 +} + +// String indicates an expected call of String +func (mr *MockIDMockRecorder) String() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "String", reflect.TypeOf((*MockID)(nil).String)) +} + +// Value mocks base method +func (m *MockID) Value() string { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Value") + ret0, _ := ret[0].(string) + return ret0 +} + +// Value indicates an expected call of Value +func (mr *MockIDMockRecorder) Value() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Value", reflect.TypeOf((*MockID)(nil).Value)) +} + +// MockDirector is a mock of Director interface +type MockDirector struct { + ctrl *gomock.Controller + recorder *MockDirectorMockRecorder +} + +// MockDirectorMockRecorder is the mock recorder for MockDirector +type MockDirectorMockRecorder struct { + mock *MockDirector +} + +// NewMockDirector creates a new mock instance +func NewMockDirector(ctrl *gomock.Controller) *MockDirector { + mock := &MockDirector{ctrl: ctrl} + mock.recorder = &MockDirectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockDirector) EXPECT() *MockDirectorMockRecorder { + return m.recorder +} + +// Act mocks base method +func (m *MockDirector) Act() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Act") + ret0, _ := ret[0].(error) + return ret0 +} + +// Act indicates an expected call of Act +func (mr *MockDirectorMockRecorder) Act() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Act", reflect.TypeOf((*MockDirector)(nil).Act)) +} + +// GetNextActor mocks base method +func (m *MockDirector) GetNextActor() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "GetNextActor") + ret0, _ := ret[0].(error) + return ret0 +} + +// GetNextActor indicates an expected call of GetNextActor +func (mr *MockDirectorMockRecorder) GetNextActor() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "GetNextActor", reflect.TypeOf((*MockDirector)(nil).GetNextActor)) +} + +// ID mocks base method +func (m *MockDirector) ID() orcareduce.ID { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "ID") + ret0, _ := ret[0].(orcareduce.ID) + return ret0 +} + +// ID indicates an expected call of ID +func (mr *MockDirectorMockRecorder) ID() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "ID", reflect.TypeOf((*MockDirector)(nil).ID)) +} + +// MockActorDataSink is a mock of ActorDataSink interface +type MockActorDataSink struct { + ctrl *gomock.Controller + recorder *MockActorDataSinkMockRecorder +} + +// MockActorDataSinkMockRecorder is the mock recorder for MockActorDataSink +type MockActorDataSinkMockRecorder struct { + mock *MockActorDataSink +} + +// NewMockActorDataSink creates a new mock instance +func NewMockActorDataSink(ctrl *gomock.Controller) *MockActorDataSink { + mock := &MockActorDataSink{ctrl: ctrl} + mock.recorder = &MockActorDataSinkMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockActorDataSink) EXPECT() *MockActorDataSinkMockRecorder { + return m.recorder +} + +// Attempt mocks base method +func (m *MockActorDataSink) Attempt(arg0 orcareduce.Reactor) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Attempt", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Attempt indicates an expected call of Attempt +func (mr *MockActorDataSinkMockRecorder) Attempt(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Attempt", reflect.TypeOf((*MockActorDataSink)(nil).Attempt), arg0) +} + +// Failure mocks base method +func (m *MockActorDataSink) Failure(arg0 orcareduce.Reactor) { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Failure", arg0) +} + +// Failure indicates an expected call of Failure +func (mr *MockActorDataSinkMockRecorder) Failure(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Failure", reflect.TypeOf((*MockActorDataSink)(nil).Failure), arg0) +} + +// Success mocks base method +func (m *MockActorDataSink) Success(arg0 orcareduce.Reactor) error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Success", arg0) + ret0, _ := ret[0].(error) + return ret0 +} + +// Success indicates an expected call of Success +func (mr *MockActorDataSinkMockRecorder) Success(arg0 interface{}) *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Success", reflect.TypeOf((*MockActorDataSink)(nil).Success), arg0) +} + +// MockInjector is a mock of Injector interface +type MockInjector struct { + ctrl *gomock.Controller + recorder *MockInjectorMockRecorder +} + +// MockInjectorMockRecorder is the mock recorder for MockInjector +type MockInjectorMockRecorder struct { + mock *MockInjector +} + +// NewMockInjector creates a new mock instance +func NewMockInjector(ctrl *gomock.Controller) *MockInjector { + mock := &MockInjector{ctrl: ctrl} + mock.recorder = &MockInjectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockInjector) EXPECT() *MockInjectorMockRecorder { + return m.recorder +} + +// Error mocks base method +func (m *MockInjector) Error() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 +} + +// Error indicates an expected call of Error +func (mr *MockInjectorMockRecorder) Error() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockInjector)(nil).Error)) +} + +// Latency mocks base method +func (m *MockInjector) Latency() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Latency") +} + +// Latency indicates an expected call of Latency +func (mr *MockInjectorMockRecorder) Latency() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Latency", reflect.TypeOf((*MockInjector)(nil).Latency)) +} + +// MockErrorInjector is a mock of ErrorInjector interface +type MockErrorInjector struct { + ctrl *gomock.Controller + recorder *MockErrorInjectorMockRecorder +} + +// MockErrorInjectorMockRecorder is the mock recorder for MockErrorInjector +type MockErrorInjectorMockRecorder struct { + mock *MockErrorInjector +} + +// NewMockErrorInjector creates a new mock instance +func NewMockErrorInjector(ctrl *gomock.Controller) *MockErrorInjector { + mock := &MockErrorInjector{ctrl: ctrl} + mock.recorder = &MockErrorInjectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockErrorInjector) EXPECT() *MockErrorInjectorMockRecorder { + return m.recorder +} + +// Error mocks base method +func (m *MockErrorInjector) Error() error { + m.ctrl.T.Helper() + ret := m.ctrl.Call(m, "Error") + ret0, _ := ret[0].(error) + return ret0 +} + +// Error indicates an expected call of Error +func (mr *MockErrorInjectorMockRecorder) Error() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Error", reflect.TypeOf((*MockErrorInjector)(nil).Error)) +} + +// MockLatencyInjector is a mock of LatencyInjector interface +type MockLatencyInjector struct { + ctrl *gomock.Controller + recorder *MockLatencyInjectorMockRecorder +} + +// MockLatencyInjectorMockRecorder is the mock recorder for MockLatencyInjector +type MockLatencyInjectorMockRecorder struct { + mock *MockLatencyInjector +} + +// NewMockLatencyInjector creates a new mock instance +func NewMockLatencyInjector(ctrl *gomock.Controller) *MockLatencyInjector { + mock := &MockLatencyInjector{ctrl: ctrl} + mock.recorder = &MockLatencyInjectorMockRecorder{mock} + return mock +} + +// EXPECT returns an object that allows the caller to indicate expected use +func (m *MockLatencyInjector) EXPECT() *MockLatencyInjectorMockRecorder { + return m.recorder +} + +// Latency mocks base method +func (m *MockLatencyInjector) Latency() { + m.ctrl.T.Helper() + m.ctrl.Call(m, "Latency") +} + +// Latency indicates an expected call of Latency +func (mr *MockLatencyInjectorMockRecorder) Latency() *gomock.Call { + mr.mock.ctrl.T.Helper() + return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Latency", reflect.TypeOf((*MockLatencyInjector)(nil).Latency)) +} diff --git a/orcareduce/mockgen.go b/orcareduce/mockgen.go new file mode 100644 index 0000000..8e77b71 --- /dev/null +++ b/orcareduce/mockgen.go @@ -0,0 +1,3 @@ +package orcareduce + +//go:generate mockgen -destination=./mock/mock.go -package=mock github.com/mkuchenbecker/orcareduce/orcareduce Reactor,Logger,Handler,Precondition,ID,Director,ActorDataSink,Injector,ErrorInjector,LatencyInjector diff --git a/orcareduce/orcareduce.go b/orcareduce/orcareduce.go new file mode 100644 index 0000000..11870b6 --- /dev/null +++ b/orcareduce/orcareduce.go @@ -0,0 +1,38 @@ +package orcareduce + +// Reactor is a repeatable actor. +type Reactor interface { + Preconditions() error + Act() error + SignalSuccess() error + Notify() + ID() ID +} + +type Precondition interface { + Check() error +} + +// ID is a generalized interface for identifying reactors. +type ID interface { + String() string + Value() string + Lineage() []ID + Parent() ID + NewChild() ID + NewScopedChild(scope Scope) ID +} + +type Director interface { + GetNextActor() error + Act() error + ID() ID +} + +type ActorDataSink interface { + Success(Reactor) error + Failure(Reactor) + Attempt(Reactor) error +} + +type Scope string From 1e00b89f6bdb2aa08406d02b6da484e37cf49c46 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Mon, 22 Jun 2020 12:43:19 -0700 Subject: [PATCH 07/11] Chaos Fully Tested --- orcareduce/chaos/chaos.go | 68 -------------------------------- orcareduce/chaos/chaos_test.go | 35 ---------------- orcareduce/chaos/errors.go | 41 +++++++++++++++++++ orcareduce/chaos/errors_test.go | 43 ++++++++++++++++++++ orcareduce/chaos/latency.go | 8 ++++ orcareduce/chaos/latency_test.go | 32 +++++++++++++++ orcareduce/chaos/meta.go | 41 +++++++++++++++++++ orcareduce/chaos/meta_test.go | 26 ++++++++++++ 8 files changed, 191 insertions(+), 103 deletions(-) delete mode 100644 orcareduce/chaos/chaos.go delete mode 100644 orcareduce/chaos/chaos_test.go create mode 100644 orcareduce/chaos/errors.go create mode 100644 orcareduce/chaos/errors_test.go create mode 100644 orcareduce/chaos/meta.go create mode 100644 orcareduce/chaos/meta_test.go diff --git a/orcareduce/chaos/chaos.go b/orcareduce/chaos/chaos.go deleted file mode 100644 index 67e0b35..0000000 --- a/orcareduce/chaos/chaos.go +++ /dev/null @@ -1,68 +0,0 @@ -package chaos - -import ( - "fmt" - "math/rand" - "time" - - "github.com/mkuchenbecker/orcareduce/orcareduce" -) - -type randomStaticErrors struct { - err error - errorRate float64 -} - -func (cfg *randomStaticErrors) Error() error { - if rand.Float64() <= cfg.errorRate { - return cfg.err - } - return nil -} - -type metaErrors struct { - errors []orcareduce.ErrorInjector -} - -func (cfg *metaErrors) Error() error { - for _, injector := range cfg.errors { - err := injector.Error() - if err != nil { - return err - } - } - return nil -} - -type metaInjector struct { - latency orcareduce.LatencyInjector - errors orcareduce.ErrorInjector -} - -func (cfg *metaInjector) Latency() { - cfg.latency.Latency() -} - -func (cfg *metaInjector) Error() error { - return cfg.errors.Error() -} - -func NewDefault() orcareduce.Injector { - return &metaInjector{ - latency: &metaLatency{ - latency: []orcareduce.LatencyInjector{ - &staticLatency{latency: 20 * time.Millisecond}, - &dynamicLatency{maxLatency: 20 * time.Millisecond}, - &randomLatency{percent: 0.1, latency: &dynamicLatency{maxLatency: 100 * time.Millisecond}}, - &randomLatency{percent: 0.01, latency: &dynamicLatency{maxLatency: 1000 * time.Millisecond}}, - &randomLatency{percent: 0.001, latency: &dynamicLatency{maxLatency: 5000 * time.Millisecond}}, - &randomLatency{percent: 0.0001, latency: &dynamicLatency{maxLatency: 30 * time.Second}}, - }, - }, - errors: &metaErrors{ - errors: []orcareduce.ErrorInjector{ - &randomStaticErrors{err: fmt.Errorf("[chaos] encountered an error"), errorRate: 0.1}, - }, - }, - } -} diff --git a/orcareduce/chaos/chaos_test.go b/orcareduce/chaos/chaos_test.go deleted file mode 100644 index 1af766d..0000000 --- a/orcareduce/chaos/chaos_test.go +++ /dev/null @@ -1,35 +0,0 @@ -package chaos - -// func TestDefaultChaos(t *testing.T) { -// rand.Seed(5) // Static seed so the test is deterministic. -// chaos := NewDefault() - -// now := time.Now() -// chaos.Latency() -// assert.True(t, time.Since(now) >= time.Millisecond*20) - -// errCount := 0 -// for i := 0; i < 1000; i++ { -// if err := chaos.Error(); err != nil { -// errCount++ -// } -// } -// assert.Equal(t, 105, errCount) -// } - -// func TestStaticLatency(t *testing.T) { -// rand.Seed(5) // Static seed so the test is deterministic. -// chaos := NewDefault() - -// now := time.Now() -// chaos.Latency() -// assert.True(t, time.Since(now) >= time.Millisecond*20) - -// errCount := 0 -// for i := 0; i < 1000; i++ { -// if err := chaos.Error(); err != nil { -// errCount++ -// } -// } -// assert.Equal(t, 105, errCount) -// } diff --git a/orcareduce/chaos/errors.go b/orcareduce/chaos/errors.go new file mode 100644 index 0000000..8d1ebdc --- /dev/null +++ b/orcareduce/chaos/errors.go @@ -0,0 +1,41 @@ +package chaos + +import ( + "math/rand" + + "github.com/mkuchenbecker/orcareduce/orcareduce" +) + +type randomStaticErrors struct { + err error + errorRate float64 +} + +func (cfg *randomStaticErrors) Error() error { + if rand.Float64() <= cfg.errorRate { + return cfg.err + } + return nil +} + +func NewRandomStaticErrorInjector(err error, rate float64) orcareduce.ErrorInjector { + return &randomStaticErrors{err: err, errorRate: rate} +} + +type metaErrors struct { + errors []orcareduce.ErrorInjector +} + +func (cfg *metaErrors) Error() error { + for _, injector := range cfg.errors { + err := injector.Error() + if err != nil { + return err + } + } + return nil +} + +func NewMetaErrorInjector(errors []orcareduce.ErrorInjector) orcareduce.ErrorInjector { + return &metaErrors{errors: errors} +} diff --git a/orcareduce/chaos/errors_test.go b/orcareduce/chaos/errors_test.go new file mode 100644 index 0000000..b9b5518 --- /dev/null +++ b/orcareduce/chaos/errors_test.go @@ -0,0 +1,43 @@ +package chaos + +import ( + "fmt" + "math/rand" + "testing" + + "github.com/golang/mock/gomock" + "github.com/mkuchenbecker/orcareduce/orcareduce" + "github.com/mkuchenbecker/orcareduce/orcareduce/mock" + "github.com/stretchr/testify/assert" +) + +func TestRandomStaticErrors_100Percent(t *testing.T) { + errGeneric := fmt.Errorf("error") + errorInjector := NewRandomStaticErrorInjector(errGeneric, 1) + for i := 0; i < 100; i++ { + assert.Equal(t, errGeneric, errorInjector.Error()) + } +} + +func TestRandomStaticErrors_ZeroPercent(t *testing.T) { + errGeneric := fmt.Errorf("error") + errorInjector := NewRandomStaticErrorInjector(errGeneric, 0) + for i := 0; i < 100; i++ { + assert.Equal(t, nil, errorInjector.Error()) + } +} + +func TestMetaErrors(t *testing.T) { + errGeneric := fmt.Errorf("error") + t.Parallel() + rand.Seed(1) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockError0 := mock.NewMockErrorInjector(mockCtrl) + mockError0.EXPECT().Error().Return(nil).Times(1) + mockError1 := mock.NewMockErrorInjector(mockCtrl) + mockError1.EXPECT().Error().Return(errGeneric).Times(1) + + meta := NewMetaErrorInjector([]orcareduce.ErrorInjector{mockError0, mockError1}) + assert.Equal(t, errGeneric, meta.Error()) +} diff --git a/orcareduce/chaos/latency.go b/orcareduce/chaos/latency.go index b62a6c3..a706ffa 100644 --- a/orcareduce/chaos/latency.go +++ b/orcareduce/chaos/latency.go @@ -53,6 +53,10 @@ func (cfg *randomLatency) Latency() { } } +func NewRandomLatency(latency orcareduce.LatencyInjector, percent float64) orcareduce.LatencyInjector { + return &randomLatency{latency: latency, percent: percent} +} + type metaLatency struct { latency []orcareduce.LatencyInjector } @@ -62,3 +66,7 @@ func (this *metaLatency) Latency() { latency.Latency() } } + +func NewMetaLatency(latency []orcareduce.LatencyInjector) orcareduce.LatencyInjector { + return &metaLatency{latency: latency} +} diff --git a/orcareduce/chaos/latency_test.go b/orcareduce/chaos/latency_test.go index bf5028c..131c2a2 100644 --- a/orcareduce/chaos/latency_test.go +++ b/orcareduce/chaos/latency_test.go @@ -5,6 +5,9 @@ import ( "testing" "time" + "github.com/golang/mock/gomock" + "github.com/mkuchenbecker/orcareduce/orcareduce" + "github.com/mkuchenbecker/orcareduce/orcareduce/mock" "github.com/stretchr/testify/assert" ) @@ -32,3 +35,32 @@ func TestDynamicLatency(t *testing.T) { dynamic.Latency() } + +func TestRandomLatency(t *testing.T) { + t.Parallel() + rand.Seed(1) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockLatency := mock.NewMockLatencyInjector(mockCtrl) + + random := NewRandomLatency(mockLatency, 1) + mockLatency.EXPECT().Latency().Times(1) + random.Latency() + + random = NewRandomLatency(mockLatency, 0) + random.Latency() +} + +func TestMetaLatency(t *testing.T) { + t.Parallel() + rand.Seed(1) + mockCtrl := gomock.NewController(t) + defer mockCtrl.Finish() + mockLatency0 := mock.NewMockLatencyInjector(mockCtrl) + mockLatency0.EXPECT().Latency().Times(1) + mockLatency1 := mock.NewMockLatencyInjector(mockCtrl) + mockLatency1.EXPECT().Latency().Times(1) + + meta := NewMetaLatency([]orcareduce.LatencyInjector{mockLatency0, mockLatency1}) + meta.Latency() +} diff --git a/orcareduce/chaos/meta.go b/orcareduce/chaos/meta.go new file mode 100644 index 0000000..7b7746b --- /dev/null +++ b/orcareduce/chaos/meta.go @@ -0,0 +1,41 @@ +package chaos + +import ( + "fmt" + "time" + + "github.com/mkuchenbecker/orcareduce/orcareduce" +) + +type metaInjector struct { + latency orcareduce.LatencyInjector + errors orcareduce.ErrorInjector +} + +func (cfg *metaInjector) Latency() { + cfg.latency.Latency() +} + +func (cfg *metaInjector) Error() error { + return cfg.errors.Error() +} + +func NewDefault() orcareduce.Injector { + return &metaInjector{ + latency: &metaLatency{ + latency: []orcareduce.LatencyInjector{ + NewStaticLatency(20 * time.Millisecond), + NewDynamicLatency(20 * time.Millisecond), + NewRandomLatency(NewDynamicLatency(100*time.Millisecond), 0.1), + NewRandomLatency(NewDynamicLatency(1000*time.Millisecond), 0.01), + NewRandomLatency(NewDynamicLatency(5000*time.Millisecond), 0.001), + NewRandomLatency(NewDynamicLatency(30*time.Second), 0.0001), + }, + }, + errors: &metaErrors{ + errors: []orcareduce.ErrorInjector{ + NewRandomStaticErrorInjector(fmt.Errorf("[chaos] encountered an error"), 0.1), + }, + }, + } +} diff --git a/orcareduce/chaos/meta_test.go b/orcareduce/chaos/meta_test.go new file mode 100644 index 0000000..ce88824 --- /dev/null +++ b/orcareduce/chaos/meta_test.go @@ -0,0 +1,26 @@ +package chaos + +import ( + "math/rand" + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestDefaultChaos(t *testing.T) { + rand.Seed(5) // Static seed so the test is deterministic. + chaos := NewDefault() + + now := time.Now() + chaos.Latency() + assert.True(t, time.Since(now) >= time.Millisecond*20) + + errCount := 0 + for i := 0; i < 1000; i++ { + if err := chaos.Error(); err != nil { + errCount++ + } + } + assert.Equal(t, 105, errCount) +} From 9eca2556de7cf6b8fc867b8cf2e77dbc2a70fbe0 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Mon, 22 Jun 2020 12:48:54 -0700 Subject: [PATCH 08/11] chaos/doc.go --- orcareduce/chaos/doc.go | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) create mode 100644 orcareduce/chaos/doc.go diff --git a/orcareduce/chaos/doc.go b/orcareduce/chaos/doc.go new file mode 100644 index 0000000..5b81ac9 --- /dev/null +++ b/orcareduce/chaos/doc.go @@ -0,0 +1,18 @@ +package chaos + +/* +chaos is a package to allow the random insertion of errors and latetency. The purpose of injecting latency and errors +is to build a system with the expectation that any function, no matter how reliable, can become transiently unreliable +and should be tested as such. + +NewDefault() is a basic meta-injector that will both inject chaos errors and latency. Use of this package would be: + +func (foo *Foo) DoSomethingReliable() error { + if err := foo.ChaosInjector.Error(); err != nil { + return err + } + foo.ChaosInjector.Latency() // Blocks the thread for a period of time. + ... (remainder of function) +} + +*/ From 37b5fa116017265866dfe95657bc47d815f05af4 Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Mon, 22 Jun 2020 12:55:36 -0700 Subject: [PATCH 09/11] documentation --- orcareduce/chaos.go | 15 +++++++++++++++ orcareduce/handler.go | 1 + orcareduce/logger.go | 2 +- 3 files changed, 17 insertions(+), 1 deletion(-) diff --git a/orcareduce/chaos.go b/orcareduce/chaos.go index e6764b3..a23b811 100644 --- a/orcareduce/chaos.go +++ b/orcareduce/chaos.go @@ -1,14 +1,29 @@ package orcareduce +// Injector is an object capable of both injecting latency and errors. It's primary use is to +// artificially increase the error rate and latency during testing to help simulate degraded +// performance. +// +// func (foo *Foo) DoSomethingReliable() error { +// if err := foo.ChaosInjector.Error(); err != nil { +// return err +// } +// foo.ChaosInjector.Latency() // Blocks the thread for a period of time. +// ... (remainder of function) +// } type Injector interface { Latency() Error() error } +// ErrorInjector is an object that can inject errors into a process or function. It's primary +// use is to inject errors into otherwise reliable functions for testing purposes. type ErrorInjector interface { Error() error } +// LatencyInjector is an object that blocks the thread for a period of time. It's primary +// use is to inject latency into otherwise performant functions. type LatencyInjector interface { Latency() } diff --git a/orcareduce/handler.go b/orcareduce/handler.go index 2025901..4ff0eff 100644 --- a/orcareduce/handler.go +++ b/orcareduce/handler.go @@ -45,6 +45,7 @@ type Handler interface { } // A SyncFunc is a function with no parameters that returns an error. +// Calling a SyncFunc blocks the thread until the function is called. type SyncFunc func() error // A RunFunc is a function with no parameters that returns an error. diff --git a/orcareduce/logger.go b/orcareduce/logger.go index a71abdc..03120af 100644 --- a/orcareduce/logger.go +++ b/orcareduce/logger.go @@ -5,7 +5,7 @@ package orcareduce type Logger interface { // Errorf logs the format string and args as severity ERROR. Errorf(format string, args ...interface{}) - // Error logs an error and message. + // Error logs an error and message as severity ERROR. Error(err error, msg string) // Infof logs a format string and args as severity INFO. Infof(format string, args ...interface{}) From 16e62fb886739c02e755ed9ec1b2009554fe65cc Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Mon, 22 Jun 2020 14:27:55 -0700 Subject: [PATCH 10/11] Identifier coverage --- orcareduce/identifier/identifier.go | 30 +++++++++------ orcareduce/identifier/identifier_test.go | 49 ++++++++++++++++++++++++ orcareduce/orcareduce.go | 4 +- 3 files changed, 71 insertions(+), 12 deletions(-) diff --git a/orcareduce/identifier/identifier.go b/orcareduce/identifier/identifier.go index 4d32553..39309e5 100644 --- a/orcareduce/identifier/identifier.go +++ b/orcareduce/identifier/identifier.go @@ -3,6 +3,8 @@ package identifier import ( "bytes" "crypto/sha256" + "fmt" + "strings" "time" "github.com/mkuchenbecker/orcareduce/orcareduce" @@ -11,7 +13,7 @@ import ( type identifier struct { id string scope orcareduce.Scope - level int + depth int parent *identifier } @@ -31,10 +33,11 @@ func (this *identifier) Lineage() []orcareduce.ID { func (this *identifier) String() string { lineage := this.Lineage() var buf bytes.Buffer - for i := len(lineage) - 1; i >= 0; i++ { - buf.WriteString(lineage[i].Value()) + for i := len(lineage) - 1; i >= 0; i-- { + buf.WriteString(fmt.Sprintf("%s(%s)", lineage[i].Scope(), lineage[i].Value())) + buf.WriteString(".") } - return buf.String() + return strings.Trim(buf.String(), ".") } func (this *identifier) Value() string { @@ -47,17 +50,22 @@ func (this *identifier) Parent() orcareduce.ID { func (this *identifier) NewChild() orcareduce.ID { out := New() - out.level = this.level + 1 + out.depth = this.depth + 1 out.parent = this return out } -func (this *identifier) NewScopedChild(scope orcareduce.Scope) orcareduce.ID { - out := New() - out.scope = scope - out.level = this.level + 1 - out.parent = this - return out +func (this *identifier) Depth() int { + return this.depth +} + +func (this *identifier) Scope() orcareduce.Scope { + return this.scope +} + +func (this *identifier) WithScope(scope orcareduce.Scope) orcareduce.ID { + this.scope = scope + return this } func New() *identifier { diff --git a/orcareduce/identifier/identifier_test.go b/orcareduce/identifier/identifier_test.go index 3aac621..90b07cd 100644 --- a/orcareduce/identifier/identifier_test.go +++ b/orcareduce/identifier/identifier_test.go @@ -1 +1,50 @@ package identifier + +import ( + "fmt" + "testing" + + "github.com/mkuchenbecker/orcareduce/orcareduce" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestIdentifierLineage(t *testing.T) { + id := New().WithScope("parent_scope") + child := id.NewChild().WithScope("child_scope") + grandchild := child.NewChild().WithScope("grandchild_scope") + + lineage := grandchild.Lineage() + require.Equal(t, 3, len(lineage)) + assert.Equal(t, id, lineage[2]) + assert.Equal(t, child, lineage[1]) + assert.Equal(t, grandchild, lineage[0]) +} + +func TestIdentifierValueStringEquivalence(t *testing.T) { + id := identifier{ + id: "bar", + scope: orcareduce.Scope("foo"), + } + assert.Equal(t, "foo(bar)", id.String()) +} + +func TestIdentifierNewChild(t *testing.T) { + id := New().WithScope("parent_scope") + child := id.NewChild().WithScope("child_scope") + grandchild := child.NewChild().WithScope("grandchild_scope") + assert.Equal(t, 0, id.Depth()) + assert.Equal(t, 1, child.Depth()) + assert.Equal(t, 2, grandchild.Depth()) + + assert.Equal(t, id, child.Parent()) + assert.Equal(t, child, grandchild.Parent()) + + assert.Equal(t, fmt.Sprintf("parent_scope(%s).child_scope(%s).grandchild_scope(%s)", + id.Value(), + child.Value(), + grandchild.Value(), + ), + grandchild.String(), + ) +} diff --git a/orcareduce/orcareduce.go b/orcareduce/orcareduce.go index 11870b6..669acce 100644 --- a/orcareduce/orcareduce.go +++ b/orcareduce/orcareduce.go @@ -20,7 +20,9 @@ type ID interface { Lineage() []ID Parent() ID NewChild() ID - NewScopedChild(scope Scope) ID + Depth() int + Scope() Scope + WithScope(Scope) ID } type Director interface { From aa8dffd3e04e3e02a74137916af0b8f0a4843e7a Mon Sep 17 00:00:00 2001 From: Mike Kuchenbecker Date: Tue, 23 Jun 2020 07:33:38 -0700 Subject: [PATCH 11/11] init --- Makefile | 5 + go.mod | 1 + go.sum | 17 + orcareduce/database.go | 0 orcareduce/main.go | 0 orcareduce/model/datamodel.pb.go | 615 +++++++++++++++++++++++++++++++ orcareduce/model/datamodel.proto | 48 +++ 7 files changed, 686 insertions(+) create mode 100644 orcareduce/database.go create mode 100644 orcareduce/main.go create mode 100644 orcareduce/model/datamodel.pb.go create mode 100644 orcareduce/model/datamodel.proto diff --git a/Makefile b/Makefile index 94c2e47..6ae176a 100644 --- a/Makefile +++ b/Makefile @@ -6,6 +6,7 @@ bootstrap: go get -v github.com/mdempsky/gocode go get -v github.com/uudashr/gopkgs/cmd/gopkgs go get -v golang.org/x/tools/cmd/goimports + go get -v golang.org/x/tools/cmd/goimports .PHONY: lint lint: fmt @@ -20,6 +21,10 @@ test-ci: lint-ci: curl -sfL https://install.goreleaser.com/github.com/golangci/golangci-lint.sh | sh +.PHONY: generate +generate: + protoc --proto_path=orcareduce/model --go_out=orcareduce/model --go_opt=paths=source_relative datamodel.proto + .PHONY: fmt fmt: @echo "fmt:" diff --git a/go.mod b/go.mod index 04dc0d6..e77d2b4 100644 --- a/go.mod +++ b/go.mod @@ -8,4 +8,5 @@ require ( github.com/influxdata/influxdb v1.8.0 github.com/pkg/errors v0.9.1 github.com/stretchr/testify v1.5.1 + google.golang.org/protobuf v1.24.0 // indirect ) diff --git a/go.sum b/go.sum index 4fc882c..e3839d6 100644 --- a/go.sum +++ b/go.sum @@ -72,6 +72,12 @@ github.com/golang/mock v1.3.1/go.mod h1:sBzyDLLjw3U8JLTeZvSv8jJB+tU5PVekmnlKIyFU github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.1/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= github.com/golang/protobuf v1.3.2/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U= +github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8= +github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA= +github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs= +github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w= +github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0= +github.com/golang/protobuf v1.4.1/go.mod h1:U8fpvMrcmy5pZrNK1lt4xCsGvpyWQ/VVv6QDs8UjoX8= github.com/golang/snappy v0.0.0-20180518054509-2e65f85255db/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q= github.com/google/btree v0.0.0-20180813153112-4030bb1f1f0c/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= github.com/google/btree v1.0.0/go.mod h1:lNA+9X1NB3Zf8V7Ke586lFgjr2dZNuvo3lPJSGZ5JPQ= @@ -317,11 +323,22 @@ google.golang.org/genproto v0.0.0-20191115194625-c23dd37a84c9/go.mod h1:n3cpQtvx google.golang.org/genproto v0.0.0-20191216164720-4f79533eabd1/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20191230161307-f3c370f40bfb/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= google.golang.org/genproto v0.0.0-20200108215221-bd8f9a0ef82f/go.mod h1:n3cpQtvxv34hfy77yVDNjmbRyujviMdxYliBSkLhpCc= +google.golang.org/genproto v0.0.0-20200526211855-cb27e3aa2013/go.mod h1:NbSheEEYHJ7i3ixzK3sjbqSGDJWnxyFXZblF3eUsNvo= google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZiDr8c= google.golang.org/grpc v1.20.1/go.mod h1:10oTOabMzJvdu6/UiuZezV6QK5dSlG84ov/aaiqXj38= google.golang.org/grpc v1.21.1/go.mod h1:oYelfM1adQP15Ek0mdvEgi9Df8B9CZIaU1084ijfRaM= google.golang.org/grpc v1.23.0/go.mod h1:Y5yQAOtifL1yxbo5wqy6BxZv8vAUGQwXBOALyacEbxg= google.golang.org/grpc v1.26.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/grpc v1.27.0/go.mod h1:qbnxyOmOxrQa7FizSgH+ReBfzJrCY1pSN7KXBS8abTk= +google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8= +google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0= +google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM= +google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE= +google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo= +google.golang.org/protobuf v1.22.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.23.1-0.20200526195155-81db48ad09cc/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU= +google.golang.org/protobuf v1.24.0 h1:UhZDfRO8JRQru4/+LlLE0BRKGF8L+PICnvYZmx/fEGA= +google.golang.org/protobuf v1.24.0/go.mod h1:r/3tXBNzIEhYS9I1OUVjXDlt8tc493IdKGjtUeSXeh4= gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= diff --git a/orcareduce/database.go b/orcareduce/database.go new file mode 100644 index 0000000..e69de29 diff --git a/orcareduce/main.go b/orcareduce/main.go new file mode 100644 index 0000000..e69de29 diff --git a/orcareduce/model/datamodel.pb.go b/orcareduce/model/datamodel.pb.go new file mode 100644 index 0000000..383e35f --- /dev/null +++ b/orcareduce/model/datamodel.pb.go @@ -0,0 +1,615 @@ +// Code generated by protoc-gen-go. DO NOT EDIT. +// versions: +// protoc-gen-go v1.24.0 +// protoc v3.7.1 +// source: datamodel.proto + +package model + +import ( + proto "github.com/golang/protobuf/proto" + protoreflect "google.golang.org/protobuf/reflect/protoreflect" + protoimpl "google.golang.org/protobuf/runtime/protoimpl" + reflect "reflect" + sync "sync" +) + +const ( + // Verify that this generated code is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion) + // Verify that runtime/protoimpl is sufficiently up-to-date. + _ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20) +) + +// This is a compile-time assertion that a sufficiently up-to-date version +// of the legacy proto package is being used. +const _ = proto.ProtoPackageIsVersion4 + +type ActorStatus int32 + +const ( + ActorStatus_UNKNOWN_ACTOR_STATE ActorStatus = 0 + ActorStatus_PENDING ActorStatus = 1 + ActorStatus_SUCCESS ActorStatus = 2 + ActorStatus_CANCELED ActorStatus = 3 +) + +// Enum value maps for ActorStatus. +var ( + ActorStatus_name = map[int32]string{ + 0: "UNKNOWN_ACTOR_STATE", + 1: "PENDING", + 2: "SUCCESS", + 3: "CANCELED", + } + ActorStatus_value = map[string]int32{ + "UNKNOWN_ACTOR_STATE": 0, + "PENDING": 1, + "SUCCESS": 2, + "CANCELED": 3, + } +) + +func (x ActorStatus) Enum() *ActorStatus { + p := new(ActorStatus) + *p = x + return p +} + +func (x ActorStatus) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (ActorStatus) Descriptor() protoreflect.EnumDescriptor { + return file_datamodel_proto_enumTypes[0].Descriptor() +} + +func (ActorStatus) Type() protoreflect.EnumType { + return &file_datamodel_proto_enumTypes[0] +} + +func (x ActorStatus) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use ActorStatus.Descriptor instead. +func (ActorStatus) EnumDescriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{0} +} + +type Run_Result int32 + +const ( + Run_UNKNOWN Run_Result = 0 + Run_FAILED_PRECONDITION Run_Result = 1 + Run_FAILED_OPERATION Run_Result = 2 + Run_FAILED_SUCCESS_SIGNAL Run_Result = 3 + Run_SUCCESS Run_Result = 4 +) + +// Enum value maps for Run_Result. +var ( + Run_Result_name = map[int32]string{ + 0: "UNKNOWN", + 1: "FAILED_PRECONDITION", + 2: "FAILED_OPERATION", + 3: "FAILED_SUCCESS_SIGNAL", + 4: "SUCCESS", + } + Run_Result_value = map[string]int32{ + "UNKNOWN": 0, + "FAILED_PRECONDITION": 1, + "FAILED_OPERATION": 2, + "FAILED_SUCCESS_SIGNAL": 3, + "SUCCESS": 4, + } +) + +func (x Run_Result) Enum() *Run_Result { + p := new(Run_Result) + *p = x + return p +} + +func (x Run_Result) String() string { + return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x)) +} + +func (Run_Result) Descriptor() protoreflect.EnumDescriptor { + return file_datamodel_proto_enumTypes[1].Descriptor() +} + +func (Run_Result) Type() protoreflect.EnumType { + return &file_datamodel_proto_enumTypes[1] +} + +func (x Run_Result) Number() protoreflect.EnumNumber { + return protoreflect.EnumNumber(x) +} + +// Deprecated: Use Run_Result.Descriptor instead. +func (Run_Result) EnumDescriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{1, 0} +} + +type Key struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Value string `protobuf:"bytes,1,opt,name=value,proto3" json:"value,omitempty"` +} + +func (x *Key) Reset() { + *x = Key{} + if protoimpl.UnsafeEnabled { + mi := &file_datamodel_proto_msgTypes[0] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Key) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Key) ProtoMessage() {} + +func (x *Key) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[0] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Key.ProtoReflect.Descriptor instead. +func (*Key) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{0} +} + +func (x *Key) GetValue() string { + if x != nil { + return x.Value + } + return "" +} + +type Run struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + ActorID *Key `protobuf:"bytes,1,opt,name=ActorID,proto3" json:"ActorID,omitempty"` + DirectorID *Key `protobuf:"bytes,2,opt,name=DirectorID,proto3" json:"DirectorID,omitempty"` + Timestamp uint64 `protobuf:"varint,3,opt,name=timestamp,proto3" json:"timestamp,omitempty"` + Error string `protobuf:"bytes,4,opt,name=error,proto3" json:"error,omitempty"` +} + +func (x *Run) Reset() { + *x = Run{} + if protoimpl.UnsafeEnabled { + mi := &file_datamodel_proto_msgTypes[1] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *Run) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*Run) ProtoMessage() {} + +func (x *Run) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[1] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use Run.ProtoReflect.Descriptor instead. +func (*Run) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{1} +} + +func (x *Run) GetActorID() *Key { + if x != nil { + return x.ActorID + } + return nil +} + +func (x *Run) GetDirectorID() *Key { + if x != nil { + return x.DirectorID + } + return nil +} + +func (x *Run) GetTimestamp() uint64 { + if x != nil { + return x.Timestamp + } + return 0 +} + +func (x *Run) GetError() string { + if x != nil { + return x.Error + } + return "" +} + +type RunMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Runs []*Run `protobuf:"bytes,1,rep,name=runs,proto3" json:"runs,omitempty"` +} + +func (x *RunMetadata) Reset() { + *x = RunMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_datamodel_proto_msgTypes[2] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *RunMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*RunMetadata) ProtoMessage() {} + +func (x *RunMetadata) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[2] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use RunMetadata.ProtoReflect.Descriptor instead. +func (*RunMetadata) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{2} +} + +func (x *RunMetadata) GetRuns() []*Run { + if x != nil { + return x.Runs + } + return nil +} + +type StateMetadata struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + StateId *Key `protobuf:"bytes,1,opt,name=state_id,json=stateId,proto3" json:"state_id,omitempty"` + Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"` + Description string `protobuf:"bytes,3,opt,name=description,proto3" json:"description,omitempty"` +} + +func (x *StateMetadata) Reset() { + *x = StateMetadata{} + if protoimpl.UnsafeEnabled { + mi := &file_datamodel_proto_msgTypes[3] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *StateMetadata) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*StateMetadata) ProtoMessage() {} + +func (x *StateMetadata) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[3] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use StateMetadata.ProtoReflect.Descriptor instead. +func (*StateMetadata) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{3} +} + +func (x *StateMetadata) GetStateId() *Key { + if x != nil { + return x.StateId + } + return nil +} + +func (x *StateMetadata) GetName() string { + if x != nil { + return x.Name + } + return "" +} + +func (x *StateMetadata) GetDescription() string { + if x != nil { + return x.Description + } + return "" +} + +type ActorState struct { + state protoimpl.MessageState + sizeCache protoimpl.SizeCache + unknownFields protoimpl.UnknownFields + + Key *Key `protobuf:"bytes,1,opt,name=key,proto3" json:"key,omitempty"` + Status ActorStatus `protobuf:"varint,2,opt,name=status,proto3,enum=orcareduce.model.ActorStatus" json:"status,omitempty"` + Metadata *RunMetadata `protobuf:"bytes,3,opt,name=metadata,proto3" json:"metadata,omitempty"` + Revision uint64 `protobuf:"varint,4,opt,name=revision,proto3" json:"revision,omitempty"` +} + +func (x *ActorState) Reset() { + *x = ActorState{} + if protoimpl.UnsafeEnabled { + mi := &file_datamodel_proto_msgTypes[4] + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + ms.StoreMessageInfo(mi) + } +} + +func (x *ActorState) String() string { + return protoimpl.X.MessageStringOf(x) +} + +func (*ActorState) ProtoMessage() {} + +func (x *ActorState) ProtoReflect() protoreflect.Message { + mi := &file_datamodel_proto_msgTypes[4] + if protoimpl.UnsafeEnabled && x != nil { + ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x)) + if ms.LoadMessageInfo() == nil { + ms.StoreMessageInfo(mi) + } + return ms + } + return mi.MessageOf(x) +} + +// Deprecated: Use ActorState.ProtoReflect.Descriptor instead. +func (*ActorState) Descriptor() ([]byte, []int) { + return file_datamodel_proto_rawDescGZIP(), []int{4} +} + +func (x *ActorState) GetKey() *Key { + if x != nil { + return x.Key + } + return nil +} + +func (x *ActorState) GetStatus() ActorStatus { + if x != nil { + return x.Status + } + return ActorStatus_UNKNOWN_ACTOR_STATE +} + +func (x *ActorState) GetMetadata() *RunMetadata { + if x != nil { + return x.Metadata + } + return nil +} + +func (x *ActorState) GetRevision() uint64 { + if x != nil { + return x.Revision + } + return 0 +} + +var File_datamodel_proto protoreflect.FileDescriptor + +var file_datamodel_proto_rawDesc = []byte{ + 0x0a, 0x0f, 0x64, 0x61, 0x74, 0x61, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x70, 0x72, 0x6f, 0x74, + 0x6f, 0x12, 0x10, 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, + 0x64, 0x65, 0x6c, 0x22, 0x1b, 0x0a, 0x03, 0x4b, 0x65, 0x79, 0x12, 0x14, 0x0a, 0x05, 0x76, 0x61, + 0x6c, 0x75, 0x65, 0x18, 0x01, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x76, 0x61, 0x6c, 0x75, 0x65, + 0x22, 0x8f, 0x02, 0x0a, 0x03, 0x52, 0x75, 0x6e, 0x12, 0x2f, 0x0a, 0x07, 0x41, 0x63, 0x74, 0x6f, + 0x72, 0x49, 0x44, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x63, 0x61, + 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x65, 0x79, + 0x52, 0x07, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x12, 0x35, 0x0a, 0x0a, 0x44, 0x69, 0x72, + 0x65, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x44, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x15, 0x2e, + 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x0a, 0x44, 0x69, 0x72, 0x65, 0x63, 0x74, 0x6f, 0x72, 0x49, 0x44, + 0x12, 0x1c, 0x0a, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x18, 0x03, 0x20, + 0x01, 0x28, 0x04, 0x52, 0x09, 0x74, 0x69, 0x6d, 0x65, 0x73, 0x74, 0x61, 0x6d, 0x70, 0x12, 0x14, + 0x0a, 0x05, 0x65, 0x72, 0x72, 0x6f, 0x72, 0x18, 0x04, 0x20, 0x01, 0x28, 0x09, 0x52, 0x05, 0x65, + 0x72, 0x72, 0x6f, 0x72, 0x22, 0x6c, 0x0a, 0x06, 0x52, 0x65, 0x73, 0x75, 0x6c, 0x74, 0x12, 0x0b, + 0x0a, 0x07, 0x55, 0x4e, 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x10, 0x00, 0x12, 0x17, 0x0a, 0x13, 0x46, + 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x50, 0x52, 0x45, 0x43, 0x4f, 0x4e, 0x44, 0x49, 0x54, 0x49, + 0x4f, 0x4e, 0x10, 0x01, 0x12, 0x14, 0x0a, 0x10, 0x46, 0x41, 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x4f, + 0x50, 0x45, 0x52, 0x41, 0x54, 0x49, 0x4f, 0x4e, 0x10, 0x02, 0x12, 0x19, 0x0a, 0x15, 0x46, 0x41, + 0x49, 0x4c, 0x45, 0x44, 0x5f, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x5f, 0x53, 0x49, 0x47, + 0x4e, 0x41, 0x4c, 0x10, 0x03, 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, + 0x10, 0x04, 0x22, 0x38, 0x0a, 0x0b, 0x52, 0x75, 0x6e, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, + 0x61, 0x12, 0x29, 0x0a, 0x04, 0x72, 0x75, 0x6e, 0x73, 0x18, 0x01, 0x20, 0x03, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x52, 0x04, 0x72, 0x75, 0x6e, 0x73, 0x22, 0x77, 0x0a, 0x0d, + 0x53, 0x74, 0x61, 0x74, 0x65, 0x4d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, 0x30, 0x0a, + 0x08, 0x73, 0x74, 0x61, 0x74, 0x65, 0x5f, 0x69, 0x64, 0x18, 0x01, 0x20, 0x01, 0x28, 0x0b, 0x32, + 0x15, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, + 0x65, 0x6c, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x07, 0x73, 0x74, 0x61, 0x74, 0x65, 0x49, 0x64, 0x12, + 0x12, 0x0a, 0x04, 0x6e, 0x61, 0x6d, 0x65, 0x18, 0x02, 0x20, 0x01, 0x28, 0x09, 0x52, 0x04, 0x6e, + 0x61, 0x6d, 0x65, 0x12, 0x20, 0x0a, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, 0x70, 0x74, 0x69, + 0x6f, 0x6e, 0x18, 0x03, 0x20, 0x01, 0x28, 0x09, 0x52, 0x0b, 0x64, 0x65, 0x73, 0x63, 0x72, 0x69, + 0x70, 0x74, 0x69, 0x6f, 0x6e, 0x22, 0xc3, 0x01, 0x0a, 0x0a, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53, + 0x74, 0x61, 0x74, 0x65, 0x12, 0x27, 0x0a, 0x03, 0x6b, 0x65, 0x79, 0x18, 0x01, 0x20, 0x01, 0x28, + 0x0b, 0x32, 0x15, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, + 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x4b, 0x65, 0x79, 0x52, 0x03, 0x6b, 0x65, 0x79, 0x12, 0x35, 0x0a, + 0x06, 0x73, 0x74, 0x61, 0x74, 0x75, 0x73, 0x18, 0x02, 0x20, 0x01, 0x28, 0x0e, 0x32, 0x1d, 0x2e, + 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, + 0x2e, 0x41, 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x52, 0x06, 0x73, 0x74, + 0x61, 0x74, 0x75, 0x73, 0x12, 0x39, 0x0a, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, + 0x18, 0x03, 0x20, 0x01, 0x28, 0x0b, 0x32, 0x1d, 0x2e, 0x6f, 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, + 0x75, 0x63, 0x65, 0x2e, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x2e, 0x52, 0x75, 0x6e, 0x4d, 0x65, 0x74, + 0x61, 0x64, 0x61, 0x74, 0x61, 0x52, 0x08, 0x6d, 0x65, 0x74, 0x61, 0x64, 0x61, 0x74, 0x61, 0x12, + 0x1a, 0x0a, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x18, 0x04, 0x20, 0x01, 0x28, + 0x04, 0x52, 0x08, 0x72, 0x65, 0x76, 0x69, 0x73, 0x69, 0x6f, 0x6e, 0x2a, 0x4e, 0x0a, 0x0b, 0x41, + 0x63, 0x74, 0x6f, 0x72, 0x53, 0x74, 0x61, 0x74, 0x75, 0x73, 0x12, 0x17, 0x0a, 0x13, 0x55, 0x4e, + 0x4b, 0x4e, 0x4f, 0x57, 0x4e, 0x5f, 0x41, 0x43, 0x54, 0x4f, 0x52, 0x5f, 0x53, 0x54, 0x41, 0x54, + 0x45, 0x10, 0x00, 0x12, 0x0b, 0x0a, 0x07, 0x50, 0x45, 0x4e, 0x44, 0x49, 0x4e, 0x47, 0x10, 0x01, + 0x12, 0x0b, 0x0a, 0x07, 0x53, 0x55, 0x43, 0x43, 0x45, 0x53, 0x53, 0x10, 0x02, 0x12, 0x0c, 0x0a, + 0x08, 0x43, 0x41, 0x4e, 0x43, 0x45, 0x4c, 0x45, 0x44, 0x10, 0x03, 0x42, 0x12, 0x5a, 0x10, 0x6f, + 0x72, 0x63, 0x61, 0x72, 0x65, 0x64, 0x75, 0x63, 0x65, 0x2f, 0x6d, 0x6f, 0x64, 0x65, 0x6c, 0x62, + 0x06, 0x70, 0x72, 0x6f, 0x74, 0x6f, 0x33, +} + +var ( + file_datamodel_proto_rawDescOnce sync.Once + file_datamodel_proto_rawDescData = file_datamodel_proto_rawDesc +) + +func file_datamodel_proto_rawDescGZIP() []byte { + file_datamodel_proto_rawDescOnce.Do(func() { + file_datamodel_proto_rawDescData = protoimpl.X.CompressGZIP(file_datamodel_proto_rawDescData) + }) + return file_datamodel_proto_rawDescData +} + +var file_datamodel_proto_enumTypes = make([]protoimpl.EnumInfo, 2) +var file_datamodel_proto_msgTypes = make([]protoimpl.MessageInfo, 5) +var file_datamodel_proto_goTypes = []interface{}{ + (ActorStatus)(0), // 0: orcareduce.model.ActorStatus + (Run_Result)(0), // 1: orcareduce.model.Run.Result + (*Key)(nil), // 2: orcareduce.model.Key + (*Run)(nil), // 3: orcareduce.model.Run + (*RunMetadata)(nil), // 4: orcareduce.model.RunMetadata + (*StateMetadata)(nil), // 5: orcareduce.model.StateMetadata + (*ActorState)(nil), // 6: orcareduce.model.ActorState +} +var file_datamodel_proto_depIdxs = []int32{ + 2, // 0: orcareduce.model.Run.ActorID:type_name -> orcareduce.model.Key + 2, // 1: orcareduce.model.Run.DirectorID:type_name -> orcareduce.model.Key + 3, // 2: orcareduce.model.RunMetadata.runs:type_name -> orcareduce.model.Run + 2, // 3: orcareduce.model.StateMetadata.state_id:type_name -> orcareduce.model.Key + 2, // 4: orcareduce.model.ActorState.key:type_name -> orcareduce.model.Key + 0, // 5: orcareduce.model.ActorState.status:type_name -> orcareduce.model.ActorStatus + 4, // 6: orcareduce.model.ActorState.metadata:type_name -> orcareduce.model.RunMetadata + 7, // [7:7] is the sub-list for method output_type + 7, // [7:7] is the sub-list for method input_type + 7, // [7:7] is the sub-list for extension type_name + 7, // [7:7] is the sub-list for extension extendee + 0, // [0:7] is the sub-list for field type_name +} + +func init() { file_datamodel_proto_init() } +func file_datamodel_proto_init() { + if File_datamodel_proto != nil { + return + } + if !protoimpl.UnsafeEnabled { + file_datamodel_proto_msgTypes[0].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Key); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_datamodel_proto_msgTypes[1].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*Run); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_datamodel_proto_msgTypes[2].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*RunMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_datamodel_proto_msgTypes[3].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*StateMetadata); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + file_datamodel_proto_msgTypes[4].Exporter = func(v interface{}, i int) interface{} { + switch v := v.(*ActorState); i { + case 0: + return &v.state + case 1: + return &v.sizeCache + case 2: + return &v.unknownFields + default: + return nil + } + } + } + type x struct{} + out := protoimpl.TypeBuilder{ + File: protoimpl.DescBuilder{ + GoPackagePath: reflect.TypeOf(x{}).PkgPath(), + RawDescriptor: file_datamodel_proto_rawDesc, + NumEnums: 2, + NumMessages: 5, + NumExtensions: 0, + NumServices: 0, + }, + GoTypes: file_datamodel_proto_goTypes, + DependencyIndexes: file_datamodel_proto_depIdxs, + EnumInfos: file_datamodel_proto_enumTypes, + MessageInfos: file_datamodel_proto_msgTypes, + }.Build() + File_datamodel_proto = out.File + file_datamodel_proto_rawDesc = nil + file_datamodel_proto_goTypes = nil + file_datamodel_proto_depIdxs = nil +} diff --git a/orcareduce/model/datamodel.proto b/orcareduce/model/datamodel.proto new file mode 100644 index 0000000..c0e3028 --- /dev/null +++ b/orcareduce/model/datamodel.proto @@ -0,0 +1,48 @@ +syntax = "proto3"; + +package orcareduce.model; + +option go_package = "orcareduce/model"; + +message Key { + string value = 1; +} + +enum ActorStatus { + UNKNOWN_ACTOR_STATE = 0; + PENDING = 1; + SUCCESS = 2; + CANCELED = 3; +} + +message Run { + Key ActorID = 1; + Key DirectorID = 2; + uint64 timestamp = 3; + enum Result { + UNKNOWN = 0; + FAILED_PRECONDITION = 1; + FAILED_OPERATION = 2; + FAILED_SUCCESS_SIGNAL = 3; + SUCCESS = 4; + } + string error = 4; +} + +message RunMetadata { + repeated Run runs = 1; +} + +message StateMetadata { + Key state_id = 1; + string name = 2; + string description = 3; +} + +message ActorState { + Key key = 1; + ActorStatus status = 2; + RunMetadata metadata = 3; + uint64 revision = 4; +} +