From bb0172bc8d901c227a9991f29280f294b2c61cb1 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 18 Sep 2019 10:28:55 +0300 Subject: [PATCH 01/14] resource embedding --- core/engine.go | 9 ++++++++ core/localizer.go | 54 +++++++++++++++++++++++++++++++++++++++++++++-- core/template.go | 21 +++++++++++++++++- go.mod | 1 + go.sum | 42 ++++++++++++++++++++++++++++++++++++ 5 files changed, 124 insertions(+), 3 deletions(-) diff --git a/core/engine.go b/core/engine.go index 25f8b75..8b606cc 100644 --- a/core/engine.go +++ b/core/engine.go @@ -5,6 +5,7 @@ import ( "github.com/gin-gonic/gin" "github.com/op/go-logging" + "github.com/gobuffalo/packr/v2" ) // Engine struct @@ -104,6 +105,14 @@ func (e *Engine) CreateRenderer(callback func(*Renderer), funcs template.FuncMap return renderer } +// CreateRendererFS with translation function and packr box with templates data +func (e *Engine) CreateRendererFS(box *packr.Box, callback func(*Renderer), funcs template.FuncMap) Renderer { + renderer := NewRenderer(e.TemplateFuncMap(funcs)) + renderer.TemplatesBox = box + callback(&renderer) + return renderer +} + // Router will return current gin.Engine or panic if it's not present func (e *Engine) Router() *gin.Engine { if !e.prepared { diff --git a/core/localizer.go b/core/localizer.go index bbb5f9e..a2be40c 100644 --- a/core/localizer.go +++ b/core/localizer.go @@ -6,6 +6,8 @@ import ( "path" "github.com/gin-gonic/gin" + "github.com/gobuffalo/packd" + "github.com/gobuffalo/packr/v2" "github.com/nicksnyder/go-i18n/v2/i18n" "golang.org/x/text/language" "gopkg.in/yaml.v2" @@ -14,6 +16,7 @@ import ( // Localizer struct type Localizer struct { i18n *i18n.Localizer + TranslationsBox *packr.Box LocaleBundle *i18n.Bundle LocaleMatcher language.Matcher LanguageTag language.Tag @@ -86,18 +89,65 @@ func (l *Localizer) getLocaleBundle() *i18n.Bundle { return l.LocaleBundle } -// LoadTranslations will load all translation files from translations directory +// LoadTranslations will load all translation files from translations directory or from embedded box func (l *Localizer) LoadTranslations() { l.getLocaleBundle().RegisterUnmarshalFunc("yml", yaml.Unmarshal) + + switch { + case l.TranslationsPath != "": + if err := l.loadFromDirectory(); err != nil { + panic(err.Error()) + } + case l.TranslationsBox != nil: + if err := l.loadFromFS(); err != nil { + panic(err.Error()) + } + default: + panic("TranslationsPath or TranslationsBox should be specified") + } +} + +// LoadTranslations will load all translation files from translations directory +func (l *Localizer) loadFromDirectory() error { files, err := ioutil.ReadDir(l.TranslationsPath) if err != nil { - panic(err) + return err } + for _, f := range files { if !f.IsDir() { l.getLocaleBundle().MustLoadMessageFile(path.Join(l.TranslationsPath, f.Name())) } } + + return nil +} + +// LoadTranslations will load all translation files from embedded box +func (l *Localizer) loadFromFS() error { + err := l.TranslationsBox.Walk(func(s string, file packd.File) error { + if fileInfo, err := file.FileInfo(); err == nil { + if !fileInfo.IsDir() { + if data, err := ioutil.ReadAll(file); err == nil { + if _, err := l.getLocaleBundle().ParseMessageFileBytes(data, fileInfo.Name()); err != nil { + return err + } + } else { + return err + } + } + } else { + return err + } + + return nil + }) + + if err != nil { + return err + } else { + return nil + } } // SetLocale will change language for current localizer diff --git a/core/template.go b/core/template.go index 62bca8f..3732fbe 100644 --- a/core/template.go +++ b/core/template.go @@ -4,11 +4,13 @@ import ( "html/template" "github.com/gin-contrib/multitemplate" + "github.com/gobuffalo/packr/v2" ) // Renderer wraps multitemplate.Renderer in order to make it easier to use type Renderer struct { multitemplate.Renderer + TemplatesBox *packr.Box FuncMap template.FuncMap } @@ -22,5 +24,22 @@ func NewRenderer(funcMap template.FuncMap) Renderer { // Push is an AddFromFilesFuncs wrapper func (r *Renderer) Push(name string, files ...string) *template.Template { - return r.AddFromFilesFuncs(name, r.FuncMap, files...) + if r.TemplatesBox == nil { + return r.AddFromFilesFuncs(name, r.FuncMap, files...) + } else { + return r.addFromBox(name, r.FuncMap, files...) + } } + +// addFromBox adds embedded template +func (r *Renderer) addFromBox(name string, funcMap template.FuncMap, files ...string) *template.Template { + var filesData []string + + for _, file := range files { + if data, err := r.TemplatesBox.FindString(file); err == nil { + filesData = append(filesData, data) + } + } + + return r.AddFromStringsFuncs(name, funcMap, filesData...) +} \ No newline at end of file diff --git a/go.mod b/go.mod index 78811cd..3e278fd 100644 --- a/go.mod +++ b/go.mod @@ -12,6 +12,7 @@ require ( github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.3.0 github.com/go-sql-driver/mysql v1.4.1 // indirect + github.com/gobuffalo/packr/v2 v2.6.0 github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.0.0 // indirect github.com/jinzhu/gorm v1.9.1 diff --git a/go.sum b/go.sum index a78a223..b0e6ed1 100644 --- a/go.sum +++ b/go.sum @@ -10,12 +10,17 @@ github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMx 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/apache/thrift v0.12.0/go.mod h1:cp2SuWMxlEZw2r+iP2GNCdIi4C1qmUzdZFSVb+bacwQ= +github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8= github.com/aws/aws-sdk-go v1.23.9 h1:UYWPGrBMlrW5VCYeWMbog1T/kqZzkvvheUDQaaUAhqI= github.com/aws/aws-sdk-go v1.23.9/go.mod h1:KmX6BPdI08NWTb3/sm4ZGu5ShLoqVDhKgpiN924inxo= github.com/beorn7/perks v0.0.0-20180321164747-3a771d992973/go.mod h1:Dwedo/Wpr24TaqPxmxbtue+5NUziq4I4S80YR8gNf3Q= github.com/certifi/gocertifi v0.0.0-20190506164543-d2eda7129713 h1:UNOqI3EKhvbqV8f1Vm3NIwkrhq388sGCeAH2Op7w0rc= github.com/certifi/gocertifi v0.0.0-20190506164543-d2eda7129713/go.mod h1:GJKEexRPVJrBSOjoqN5VNOIKJ5Q3RViH6eu3puDRwx4= github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= +github.com/coreos/etcd v3.3.10+incompatible/go.mod h1:uF7uidLiAD3TWHmW31ZFd/JWoc32PjwdhPthX9715RE= +github.com/coreos/go-etcd v2.0.0+incompatible/go.mod h1:Jez6KQU2B/sWsbdaef3ED8NzMklzPG4d5KIOhIy30Tk= +github.com/coreos/go-semver v0.2.0/go.mod h1:nnelYz7RCh+5ahJtPPxZlU+153eP4D4r3EedlOD2RNk= +github.com/cpuguy83/go-md2man v1.0.10/go.mod h1:SmD6nW6nTyfqj6ABTjUi3V3JVMnlJmwcJI5acqYI6dE= 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= @@ -42,6 +47,10 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 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/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.6.0/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -65,7 +74,9 @@ github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+ github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= +github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= +github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/gorm v1.9.1 h1:lDSDtsCt5AGGSKTs8AHlSDbbgif4G4+CKJ8ETBDVHTA= github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= @@ -74,13 +85,20 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2/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.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= +github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= @@ -88,6 +106,8 @@ github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2y github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= +github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5 h1:/TjjTS4kg7vC+05gD0LE4+97f/+PRFICnK/7wJPk7kE= github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU= @@ -97,6 +117,7 @@ github.com/onsi/gomega v1.4.3/go.mod h1:ex+gbHU/CVuBBDIJjb2X0qEXbFg53c61hWP/1Cpa github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 h1:lDH9UUVJtmYCjyT0CI4q8xvlXPxeZ0gYCVvWbmPlp88= github.com/op/go-logging v0.0.0-20160315200505-970db520ece7/go.mod h1:HzydrMdWErDVzsI23lYNej1Htcns9BCg93Dk0bBINWk= github.com/openzipkin/zipkin-go v0.1.6/go.mod h1:QgAqvLzwWbR/WpD4A3cGpPtJrZXNIiJc5AZX7/PBEpw= +github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/94hg7ilaic= 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 h1:iURUrRGxPUNPdy5/HRSm+Yj6okJ6UtLINN0Q9M4+h3I= @@ -115,7 +136,17 @@ github.com/retailcrm/api-client-go v1.1.1 h1:yqsyYjBDdmDwExVlTdGucY9/IpEokXpkfTf github.com/retailcrm/api-client-go v1.1.1/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7cYuq3q14Ot+6N8c= github.com/retailcrm/mg-transport-api-client-go v1.1.31 h1:21pE1JhT49rvbMLDYJa0iiqbb/roz+eSp27fPck4uUw= github.com/retailcrm/mg-transport-api-client-go v1.1.31/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= +github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= +github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= +github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= +github.com/spf13/cobra v0.0.5/go.mod h1:3K3wKZymM7VvHMDS9+Akkh4K60UwM26emMESw8tLCHU= +github.com/spf13/jwalterweatherman v1.0.0/go.mod h1:cQK4TGJAtQXfYWX+Ddv3mKDzgVb68N+wFjFa4jdeBTo= +github.com/spf13/pflag v1.0.3/go.mod h1:DYY7MBk1bdzusC3SYhjObp+wFpr4gzcvqqNjLnInEg4= +github.com/spf13/viper v1.3.2/go.mod h1:ZiWeW+zYFKm7srdB9IoDzzZXaJaI5eL9QjNiN/DMA2s= 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.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXfy6kDkUVs= @@ -124,13 +155,17 @@ github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJy github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= +github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= 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= @@ -143,6 +178,7 @@ golang.org/x/net v0.0.0-20190108225652-1e06a53dbb7e/go.mod h1:mL1N/T3taQHkDXs73r golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= @@ -158,8 +194,12 @@ golang.org/x/sys v0.0.0-20180905080454-ebe1bf3edb33/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20180909124046-d0be0721c37e/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-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= +golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= +golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a h1:aYOabOQFp6Vj6W1F80affTUvO9UxmJRx8K0gsfABByQ= golang.org/x/sys v0.0.0-20190813064441-fde4db37ae7a/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/text v0.0.0-20171214130843-f21a4dfb5e38/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= @@ -173,6 +213,7 @@ golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190226205152-f727befe758c/go.mod h1:9Yl7xja0Znq3iFh3HoIrodX9oNMXvdceNzlUR8zjMvY= golang.org/x/tools v0.0.0-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= +golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274 h1:3LEbAKuShoQDlrpbepJOeKph85ROShka+GypY1YNQYQ= golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= @@ -188,6 +229,7 @@ gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLks gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= From f26e535fd8e3290574186db17b0b703da049f582 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 18 Sep 2019 13:40:36 +0300 Subject: [PATCH 02/14] object migrations --- core/engine.go | 2 +- core/migrate.go | 260 ++++++++++++++++++++++++++++++++++++++++++++++++ go.mod | 7 +- go.sum | 17 ++++ 4 files changed, 280 insertions(+), 6 deletions(-) create mode 100644 core/migrate.go diff --git a/core/engine.go b/core/engine.go index 8b606cc..56fbb48 100644 --- a/core/engine.go +++ b/core/engine.go @@ -4,8 +4,8 @@ import ( "html/template" "github.com/gin-gonic/gin" - "github.com/op/go-logging" "github.com/gobuffalo/packr/v2" + "github.com/op/go-logging" ) // Engine struct diff --git a/core/migrate.go b/core/migrate.go new file mode 100644 index 0000000..3517237 --- /dev/null +++ b/core/migrate.go @@ -0,0 +1,260 @@ +package core + +import ( + "sort" + + "github.com/jinzhu/gorm" + "github.com/pkg/errors" + "gopkg.in/gormigrate.v1" +) + +// migrations default GORMigrate tool +var migrations *Migrate + +// Migrate tool, decorates gormigrate.Migration in order to provide better interface & versioning +type Migrate struct { + db *gorm.DB + first *gormigrate.Migration + versions []string + migrations map[string]*gormigrate.Migration + GORMigrate *gormigrate.Gormigrate + prepared bool +} + +// MigrationInfo with migration info +type MigrationInfo struct { + ID string `gorm:"column:id; type:varchar(255)"` +} + +// TableName for MigrationInfo +func (MigrationInfo) TableName() string { + return "migrations" +} + +// Migrations returns default migrate +func Migrations() *Migrate { + if migrations == nil { + migrations = &Migrate{ + db: nil, + prepared: false, + migrations: map[string]*gormigrate.Migration{}, + } + } + + return migrations +} + +// Add GORMigrate to migrate +func (m *Migrate) Add(migration *gormigrate.Migration) { + if migration == nil { + return + } + + m.migrations[migration.ID] = migration +} + +// SetORM to migrate +func (m *Migrate) SetDB(db *gorm.DB) *Migrate { + m.db = db + return m +} + +// Migrate all, including schema initialization +func (m *Migrate) Migrate() error { + if err := m.prepareMigrations(); err != nil { + return err + } + + if len(m.migrations) > 0 { + return m.GORMigrate.Migrate() + } + + return nil +} + +// Rollback all migrations +func (m *Migrate) Rollback() error { + if err := m.prepareMigrations(); err != nil { + return err + } + + if err := m.GORMigrate.RollbackTo(m.first.ID); err == nil { + if err := m.GORMigrate.RollbackMigration(m.first); err == nil { + return nil + } else { + return err + } + } else { + return err + } +} + +// MigrateTo specified version +func (m *Migrate) MigrateTo(version string) error { + if err := m.prepareMigrations(); err != nil { + return err + } + + current := m.Current() + switch { + case current > version: + return m.GORMigrate.RollbackTo(version) + case current < version: + return m.GORMigrate.MigrateTo(version) + default: + return nil + } +} + +// MigrateNextTo migrate to next version from specified version +func (m *Migrate) MigrateNextTo(version string) error { + if err := m.prepareMigrations(); err != nil { + return err + } + + if next, err := m.NextFrom(version); err == nil { + current := m.Current() + switch { + case current > next: + return m.GORMigrate.RollbackTo(next) + case current < next: + return m.GORMigrate.MigrateTo(next) + default: + return nil + } + } else { + return nil + } +} + +// MigratePreviousTo migrate to previous version from specified version +func (m *Migrate) MigratePreviousTo(version string) error { + if err := m.prepareMigrations(); err != nil { + return err + } + + if prev, err := m.PreviousFrom(version); err == nil { + current := m.Current() + switch { + case current > prev: + return m.GORMigrate.RollbackTo(prev) + case current < prev: + return m.GORMigrate.MigrateTo(prev) + default: + return nil + } + } else { + return nil + } +} + +// RollbackTo specified version +func (m *Migrate) RollbackTo(version string) error { + if err := m.prepareMigrations(); err != nil { + return err + } + + return m.GORMigrate.RollbackTo(version) +} + +// Current migration version +func (m *Migrate) Current() string { + var migrationInfo MigrationInfo + + if m.db == nil { + return "0" + } + + if !m.db.HasTable(MigrationInfo{}) { + m.db.CreateTable(MigrationInfo{}) + return "0" + } + + if err := m.db.Last(&migrationInfo).Error; err == nil { + return migrationInfo.ID + } else { + return "0" + } +} + +// NextFrom returns next version from passed version +func (m *Migrate) NextFrom(version string) (string, error) { + for key, ver := range m.versions { + if ver == version { + if key < (len(m.versions) - 1) { + return m.versions[key+1], nil + } else { + return "", errors.New("this is last migration") + } + } + } + + return "", errors.New("cannot find specified migration") +} + +// PreviousFrom returns previous version from passed version +func (m *Migrate) PreviousFrom(version string) (string, error) { + for key, ver := range m.versions { + if ver == version { + if key > 0 { + return m.versions[key-1], nil + } else { + return "", errors.New("this is first migration") + } + } + } + + return "", errors.New("cannot find specified migration") +} + +// Close db connection +func (m *Migrate) Close() error { + return m.db.Close() +} + +// prepareMigrations prepare migrate +func (m *Migrate) prepareMigrations() error { + var ( + keys []string + migrations []*gormigrate.Migration + ) + + if m.db == nil { + return errors.New("db must not be nil") + } + + if m.prepared { + return nil + } + + for key := range m.migrations { + keys = append(keys, key) + } + + sort.Strings(keys) + m.versions = keys + + if len(keys) > 0 { + if i, ok := m.migrations[keys[0]]; ok { + m.first = i + } + } + + for _, key := range keys { + if i, ok := m.migrations[key]; ok { + migrations = append(migrations, i) + } + } + + options := &gormigrate.Options{ + TableName: gormigrate.DefaultOptions.TableName, + IDColumnName: gormigrate.DefaultOptions.IDColumnName, + IDColumnSize: gormigrate.DefaultOptions.IDColumnSize, + UseTransaction: true, + ValidateUnknownMigrations: true, + } + + m.GORMigrate = gormigrate.New(m.db, options, migrations) + m.prepared = true + return nil +} diff --git a/go.mod b/go.mod index 3e278fd..c16d2bd 100644 --- a/go.mod +++ b/go.mod @@ -6,18 +6,14 @@ require ( github.com/aws/aws-sdk-go v1.23.9 github.com/certifi/gocertifi v0.0.0-20190506164543-d2eda7129713 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd // indirect - github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 // indirect github.com/getsentry/raven-go v0.0.0-20180903072508-084a9de9eb03 github.com/gin-contrib/multitemplate v0.0.0-20180827023943-5799bbbb6dce github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.3.0 - github.com/go-sql-driver/mysql v1.4.1 // indirect github.com/gobuffalo/packr/v2 v2.6.0 github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.0.0 // indirect - github.com/jinzhu/gorm v1.9.1 - github.com/jinzhu/inflection v1.0.0 // indirect - github.com/jinzhu/now v1.0.1 // indirect + github.com/jinzhu/gorm v1.9.10 github.com/lib/pq v1.2.0 // indirect github.com/mattn/go-isatty v0.0.9 // indirect github.com/mattn/go-sqlite3 v1.11.0 // indirect @@ -32,5 +28,6 @@ require ( golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 + gopkg.in/gormigrate.v1 v1.6.0 // indirect gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index b0e6ed1..abb9f4e 100644 --- a/go.sum +++ b/go.sum @@ -1,4 +1,5 @@ cloud.google.com/go v0.26.0/go.mod h1:aQUYkXzVsufM+DwF1aE+0xfcU+56JwCaLick0ClmMTw= +cloud.google.com/go v0.33.1/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.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= @@ -25,6 +26,8 @@ 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/denisenkom/go-mssqldb v0.0.0-20181014144952-4e0d7dc8888f/go.mod h1:xN/JuLBIz4bjkxNmByTiV1IbhfnYb6oo99phBn4Eqhc= +github.com/denisenkom/go-mssqldb v0.0.0-20190515213511-eb9f6a1743f3/go.mod h1:zAg7JM8CkOJ43xKXIj7eRO9kmWm/TW578qo+oDO6tuM= github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd h1:DoaaxHqzWPQCWKSTmsi8UDSiFqxbfue+Xt+qi/BFKb8= github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd/go.mod h1:uU0N10vx1abI4qeVe79CxepBP6PPREVTgMS5Gx6/mOk= github.com/eapache/go-resiliency v1.1.0/go.mod h1:kFI+JgMyC7bLPUVY133qvEBtVayf5mFgVsvEsIPBvNs= @@ -51,6 +54,7 @@ github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSC github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= github.com/gobuffalo/packr/v2 v2.6.0/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= +github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/gogo/protobuf v1.2.0/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= github.com/golang/glog v0.0.0-20160126235308-23def4e6c14b/go.mod h1:SBH7ygxi8pfUlaOkMMuAQtPIUF8ecWP5IEl/CR7VP2Q= @@ -79,8 +83,14 @@ github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpO github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= github.com/jinzhu/gorm v1.9.1 h1:lDSDtsCt5AGGSKTs8AHlSDbbgif4G4+CKJ8ETBDVHTA= github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= +github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= +github.com/jinzhu/gorm v1.9.10 h1:HvrsqdhCW78xpJF67g1hMxS6eCToo9PZH4LDB8WKPac= +github.com/jinzhu/gorm v1.9.10/go.mod h1:Kh6hTsSGffh4ui079FHrR5Gg+5D0hgihqDcsDN2BBJY= +github.com/jinzhu/inflection v0.0.0-20180308033659-04140366298a/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= github.com/jinzhu/inflection v1.0.0 h1:K317FqzuhWc8YvSVlFMCCUb36O/S9MCKRDI7QkRKD/E= github.com/jinzhu/inflection v1.0.0/go.mod h1:h+uFLlag+Qp1Va5pdKtLDYj+kHp5pxUVkryuEj+Srlc= +github.com/jinzhu/now v0.0.0-20181116074157-8ec929ed50c3/go.mod h1:oHTiXerJ20+SfYcrdlBO7rzZRJWGwSTQ0iUY2jI6Gfc= github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= @@ -96,6 +106,8 @@ github.com/kr/logfmt v0.0.0-20140226030751-b84e30acd515/go.mod h1:+0opPa2QZZtGFB 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/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= @@ -103,6 +115,7 @@ github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVc github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= +github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/mattn/go-sqlite3 v1.11.0 h1:LDdKkqtYlom37fkvqs8rMPFKAMe8+SgjbwZ6ex1/A/Q= github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= @@ -161,6 +174,7 @@ github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLY github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= +golang.org/x/crypto v0.0.0-20181112202954-3d3f9f413869/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/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-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= @@ -219,6 +233,7 @@ golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274/go.mod h1:b+2E5dAYhXwXZwtn golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= +google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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= @@ -233,6 +248,8 @@ gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI= gopkg.in/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= +gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI= +gopkg.in/gormigrate.v1 v1.6.0/go.mod h1:Lf00lQrHqfSYWiTtPcyQabsDdM6ejZaMgV0OU6JMSlw= gopkg.in/tomb.v1 v1.0.0-20141024135613-dd632973f1e7/go.mod h1:dt/ZhP58zS4L8KSrWDmTeBkI65Dw0HsyUHuEVlX15mw= gopkg.in/yaml.v2 v2.2.1/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v2 v2.2.2 h1:ZCJp+EgiOT7lHqUV2J862kp8Qj64Jo6az82+3Td9dZw= From 19e5c60ba2a0ab2fc1def76341eb6a3d312d66ee Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 18 Sep 2019 14:05:06 +0300 Subject: [PATCH 03/14] update README.md --- README.md | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++- 1 file changed, 84 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index ac2e164..d283560 100644 --- a/README.md +++ b/README.md @@ -1,3 +1,86 @@ ## MG Transport Library -This library provides different functions like error-reporting, logging, localization, etc. in order to make it easier to create transports +This library provides different functions like error-reporting, logging, localization, etc. in order to make it easier to create transports. +Usage: +```go +package main + +import ( + "os" + "fmt" + "html/template" + + "github.com/gin-gonic/gin" + "github.com/gobuffalo/packr/v2" + "github.com/retailcrm/mg-transport-core/core" +) + +func main() { + app := core.New() + app.Config = core.NewConfig("config.yml") + app.DefaultError = "unknown_error" + app.TranslationsPath = "./translations" + + app.ConfigureRouter(func(engine *gin.Engine) { + engine.Static("/static", "./static") + engine.HTMLRender = app.CreateRenderer( + func(renderer *core.Renderer) { + // insert templates here. Example: + r.Push("home", "templates/layout.html", "templates/home.html") + }, + template.FuncMap{}, + ) + }) + + if err := app.Prepare().Run(); err != nil { + fmt.Printf("Fatal error: %s", err.Error()) + os.Exit(1) + } +} +``` + +### Resource embedding +[packr](https://github.com/gobuffalo/packr/tree/master/v2) can be used to provide resource embedding. In order to use packr you must follow +[this instruction](https://github.com/gobuffalo/packr/tree/master/v2#library-installation), and provide boxes with templates, +translations and assets to library. Example: +```go +package main + +import ( + "os" + "fmt" + "html/template" + + "github.com/gin-gonic/gin" + "github.com/gobuffalo/packr/v2" + "github.com/retailcrm/mg-transport-core/core" +) + +func main() { + static := packr.New("assets", "./static") + templates := packr.New("templates", "./templates") + translations := packr.New("translations", "./translate") + + app := core.New() + app.Config = core.NewConfig("config.yml") + app.DefaultError = "unknown_error" + app.TranslationsBox = translations + + app.ConfigureRouter(func(engine *gin.Engine) { + engine.StaticFS("/static", static) + engine.HTMLRender = app.CreateRendererFS( + templates, + func(renderer *core.Renderer) { + // insert templates here. Example: + r.Push("home", "layout.html", "home.html") + }, + template.FuncMap{}, + ) + }) + + if err := app.Prepare().Run(); err != nil { + fmt.Printf("Fatal error: %s", err.Error()) + os.Exit(1) + } +} +``` \ No newline at end of file From bd5de124becc645a6670507601e794e4c4d18f67 Mon Sep 17 00:00:00 2001 From: Pavel Date: Wed, 18 Sep 2019 18:02:40 +0300 Subject: [PATCH 04/14] part of tests --- core/config.go | 6 - core/config_test.go | 119 +++++++++++++++++++ core/engine.go | 7 +- core/error_test.go | 29 +++++ core/localizer_test.go | 101 +++++++++++++++++ core/logger_test.go | 21 ++++ core/migrate_test.go | 144 +++++++++++++++++++++++ core/utils.go | 14 +-- core/utils_test.go | 252 +++++++++++++++++++++++++++++++++++++++++ go.mod | 7 +- go.sum | 13 +++ 11 files changed, 693 insertions(+), 20 deletions(-) create mode 100644 core/config_test.go create mode 100644 core/error_test.go create mode 100644 core/localizer_test.go create mode 100644 core/logger_test.go create mode 100644 core/migrate_test.go create mode 100644 core/utils_test.go diff --git a/core/config.go b/core/config.go index 85f9b72..055b37a 100644 --- a/core/config.go +++ b/core/config.go @@ -19,7 +19,6 @@ var ( slashRegex = regexp.MustCompile(`/+$`) ) - // ConfigInterface settings data structure type ConfigInterface interface { GetVersion() string @@ -170,11 +169,6 @@ func (c Config) GetUpdateInterval() int { return c.UpdateInterval } -// IsDebug debug state -func (c Config) IsDebug() bool { - return c.Debug -} - // GetName transport name func (t Info) GetName() string { return t.Name diff --git a/core/config_test.go b/core/config_test.go new file mode 100644 index 0000000..c1b939b --- /dev/null +++ b/core/config_test.go @@ -0,0 +1,119 @@ +package core + +import ( + "io/ioutil" + "os" + "path" + "testing" + + "github.com/op/go-logging" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +var testConfigFile = path.Join(os.TempDir(), "config_test.yml") + +type ConfigTest struct { + suite.Suite + config *Config + data []byte +} + +func (c *ConfigTest) SetupTest() { + c.data = []byte(` +version: 3.2.1 + +database: + connection: postgres://user:password@host:5432/dbname?sslmode=disable + +http_server: + host: example.com + listen: :3001 + +transport_info: + name: Transport + code: mg-transport + logo_path: /static/logo.svg + +sentry_dsn: dsn string +log_level: 5 +debug: true +update_interval: 24 + +config_aws: + access_key_id: key + secret_access_key: secret + region: region + bucket: bucket + folder_name: folder + content_type: image/jpeg`) + err := ioutil.WriteFile(testConfigFile, c.data, os.ModePerm) + require.Nil(c.T(), err) + + c.config = NewConfig(testConfigFile) +} + +func (c *ConfigTest) Test_GetConfigData() { + assert.Equal(c.T(), c.data, c.config.GetConfigData(testConfigFile)) +} + +func (c *ConfigTest) Test_GetVersion() { + assert.Equal(c.T(), "3.2.1", c.config.GetVersion()) +} + +func (c *ConfigTest) Test_GetDBConfig() { + assert.Equal(c.T(), "postgres://user:password@host:5432/dbname?sslmode=disable", c.config.GetDBConfig().Connection) +} + +func (c *ConfigTest) Test_GetHttpServer() { + assert.Equal(c.T(), "example.com", c.config.GetHTTPConfig().Host) + assert.Equal(c.T(), ":3001", c.config.GetHTTPConfig().Listen) +} + +func (c *ConfigTest) Test_GetTransportInfo() { + assert.Equal(c.T(), "Transport", c.config.GetTransportInfo().GetName()) + assert.Equal(c.T(), "mg-transport", c.config.GetTransportInfo().GetCode()) + assert.Equal(c.T(), "/static/logo.svg", c.config.GetTransportInfo().GetLogoPath()) +} + +func (c *ConfigTest) Test_GetSentryDSN() { + assert.Equal(c.T(), "dsn string", c.config.GetSentryDSN()) +} + +func (c *ConfigTest) Test_GetLogLevel() { + assert.Equal(c.T(), logging.Level(5), c.config.GetLogLevel()) +} + +func (c *ConfigTest) Test_GetDebug() { + assert.Equal(c.T(), true, c.config.GetDebug()) +} + +func (c *ConfigTest) Test_GetUpdateInterval() { + assert.Equal(c.T(), 24, c.config.GetUpdateInterval()) +} + +func (c *ConfigTest) Test_GetConfigAWS() { + assert.Equal(c.T(), "key", c.config.GetAWSConfig().AccessKeyID) + assert.Equal(c.T(), "secret", c.config.GetAWSConfig().SecretAccessKey) + assert.Equal(c.T(), "region", c.config.GetAWSConfig().Region) + assert.Equal(c.T(), "bucket", c.config.GetAWSConfig().Bucket) + assert.Equal(c.T(), "folder", c.config.GetAWSConfig().FolderName) + assert.Equal(c.T(), "image/jpeg", c.config.GetAWSConfig().ContentType) +} + +func (c *ConfigTest) TearDownTest() { + _ = os.Remove(testConfigFile) +} + +func TestConfig_Suite(t *testing.T) { + suite.Run(t, new(ConfigTest)) +} + +func TestConfig_NoFile(t *testing.T) { + defer func() { + assert.NotNil(t, recover()) + }() + + _ = NewConfig(path.Join(os.TempDir(), "file_which_should_not_exist_anyway")) +} diff --git a/core/engine.go b/core/engine.go index 56fbb48..fbb8a04 100644 --- a/core/engine.go +++ b/core/engine.go @@ -36,14 +36,14 @@ func New() *Engine { } func (e *Engine) initGin() { - if !e.Config.IsDebug() { + if !e.Config.GetDebug() { gin.SetMode(gin.ReleaseMode) } r := gin.New() r.Use(gin.Recovery()) - if e.Config.IsDebug() { + if e.Config.GetDebug() { r.Use(gin.Logger()) } @@ -76,9 +76,8 @@ func (e *Engine) Prepare() *Engine { e.LoadTranslations() e.createDB(e.Config.GetDBConfig()) e.createRavenClient(e.Config.GetSentryDSN()) - e.resetUtils(e.Config.GetAWSConfig(), e.Config.IsDebug(), 0) + e.resetUtils(e.Config.GetAWSConfig(), e.Config.GetDebug(), 0) e.Logger = NewLogger(e.Config.GetTransportInfo().GetCode(), e.Config.GetLogLevel(), e.LogFormatter) - e.Utils.Localizer = &e.Localizer e.Sentry.Localizer = &e.Localizer e.Utils.Logger = e.Logger e.Sentry.Logger = e.Logger diff --git a/core/error_test.go b/core/error_test.go new file mode 100644 index 0000000..8915dd8 --- /dev/null +++ b/core/error_test.go @@ -0,0 +1,29 @@ +package core + +import ( + "net/http" + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestError_GetErrorResponse(t *testing.T) { + code, resp := GetErrorResponse(http.StatusBadRequest, "error string") + + assert.Equal(t, http.StatusBadRequest, code) + assert.Equal(t, "error string", resp.(ErrorResponse).Error) +} + +func TestError_BadRequest(t *testing.T) { + code, resp := BadRequest("error string") + + assert.Equal(t, http.StatusBadRequest, code) + assert.Equal(t, "error string", resp.(ErrorResponse).Error) +} + +func TestError_InternalServerError(t *testing.T) { + code, resp := InternalServerError("error string") + + assert.Equal(t, http.StatusInternalServerError, code) + assert.Equal(t, "error string", resp.(ErrorResponse).Error) +} diff --git a/core/localizer_test.go b/core/localizer_test.go new file mode 100644 index 0000000..e2e5251 --- /dev/null +++ b/core/localizer_test.go @@ -0,0 +1,101 @@ +package core + +import ( + "io/ioutil" + "net/http" + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "golang.org/x/text/language" +) + +var ( + testTranslationsDir = path.Join(os.TempDir(), "translations_test_dir") + testLangFile = path.Join(testTranslationsDir, "translate.en.yml") +) + +type LocalizerTest struct { + suite.Suite + localizer *Localizer +} + +func (l *LocalizerTest) SetupTest() { + if _, err := os.Stat(testTranslationsDir); err != nil && os.IsNotExist(err) { + err := os.Mkdir(testTranslationsDir, os.ModePerm) + require.Nil(l.T(), err) + data := []byte("message: Test message\nmessage_template: Test message with {{.data}}") + err = ioutil.WriteFile(testLangFile, data, os.ModePerm) + require.Nil(l.T(), err) + } + + l.localizer = NewLocalizer(language.English, DefaultLocalizerBundle(), DefaultLocalizerMatcher(), testTranslationsDir) +} + +func (l *LocalizerTest) Test_SetLocale() { + defer func() { + require.Nil(l.T(), recover()) + }() + + l.localizer.SetLocale("en") +} + +func (l *LocalizerTest) Test_LocalizationMiddleware() { + assert.NotNil(l.T(), l.localizer.LocalizationMiddleware()) +} + +func (l *LocalizerTest) Test_LocalizationFuncMap() { + functions := l.localizer.LocalizationFuncMap() + _, ok := functions["trans"] + assert.True(l.T(), ok) +} + +func (l *LocalizerTest) Test_GetLocalizedMessage() { + defer func() { + require.Nil(l.T(), recover()) + }() + + message := l.localizer.GetLocalizedMessage("message") + assert.Equal(l.T(), "Test message", message) +} + +func (l *LocalizerTest) Test_GetLocalizedTemplateMessage() { + defer func() { + require.Nil(l.T(), recover()) + }() + + message := l.localizer.GetLocalizedTemplateMessage("message_template", map[string]interface{}{"data": "template"}) + assert.Equal(l.T(), "Test message with template", message) +} + +func (l *LocalizerTest) Test_BadRequestLocalized() { + status, resp := l.localizer.BadRequestLocalized("message") + + assert.Equal(l.T(), http.StatusBadRequest, status) + assert.Equal(l.T(), "Test message", resp.(ErrorResponse).Error) +} + +func (l *LocalizerTest) TearDownTest() { + err := os.RemoveAll(testTranslationsDir) + require.Nil(l.T(), err) +} + +func TestLocalizer_Suite(t *testing.T) { + suite.Run(t, new(LocalizerTest)) +} + +func TestLocalizer_NoDirectory(t *testing.T) { + defer func() { + assert.NotNil(t, recover()) + }() + + _ = NewLocalizer( + language.English, + DefaultLocalizerBundle(), + DefaultLocalizerMatcher(), + path.Join(os.TempDir(), "this directory should not exist"), + ) +} diff --git a/core/logger_test.go b/core/logger_test.go new file mode 100644 index 0000000..879fbd8 --- /dev/null +++ b/core/logger_test.go @@ -0,0 +1,21 @@ +package core + +import ( + "testing" + + "github.com/op/go-logging" + "github.com/stretchr/testify/assert" +) + +func TestLogger_NewLogger(t *testing.T) { + logger := NewLogger("code", logging.DEBUG, DefaultLogFormatter()) + + assert.NotNil(t, logger) +} + +func TestLogger_DefaultLogFormatter(t *testing.T) { + formatter := DefaultLogFormatter() + + assert.NotNil(t, formatter) + assert.IsType(t, logging.MustStringFormatter(`%{message}`), formatter) +} diff --git a/core/migrate_test.go b/core/migrate_test.go new file mode 100644 index 0000000..831d735 --- /dev/null +++ b/core/migrate_test.go @@ -0,0 +1,144 @@ +package core + +import ( + "database/sql" + "regexp" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/jinzhu/gorm" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" + "gopkg.in/gormigrate.v1" +) + +type TestModel struct { + Name string `gorm:"column:name; type:varchar(70)"` +} + +func (TestModel) TableName() string { + return "test_model" +} + +type MigrateTest struct { + suite.Suite + DB *gorm.DB + Migrate *Migrate + mock sqlmock.Sqlmock +} + +func (m *MigrateTest) SetupSuite() { + var ( + db *sql.DB + err error + ) + + require.NotEmpty(m.T(), (MigrationInfo{}).TableName()) + + db, m.mock, err = sqlmock.New() + require.NoError(m.T(), err) + + m.DB, err = gorm.Open("postgres", db) + require.NoError(m.T(), err) + + m.DB.LogMode(true) + m.RefreshMigrate() + m.Migrate.SetDB(m.DB) +} + +func (m *MigrateTest) RefreshMigrate() { + m.Migrate = &Migrate{ + db: m.DB, + prepared: false, + migrations: map[string]*gormigrate.Migration{}, + } +} + +func (m *MigrateTest) Migration_TestModel() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "1", + Migrate: func(db *gorm.DB) error { + return db.AutoMigrate(TestModel{}).Error + }, + Rollback: func(db *gorm.DB) error { + return db.DropTable(TestModel{}).Error + }, + } +} + +func (m *MigrateTest) Test_Add() { + m.RefreshMigrate() + m.Migrate.Add(nil) + m.Migrate.Add(m.Migration_TestModel()) + + assert.Equal(m.T(), 1, len(m.Migrate.migrations)) + i, ok := m.Migrate.migrations["1"] + require.True(m.T(), ok) + assert.Equal(m.T(), "1", i.ID) +} + +func (m *MigrateTest) Test_prepareMigrations_NilDB() { + m.RefreshMigrate() + m.Migrate.db = nil + err := m.Migrate.prepareMigrations() + + require.Error(m.T(), err) + assert.Equal(m.T(), "db must not be nil", err.Error()) +} + +func (m *MigrateTest) Test_prepareMigrations_AlreadyPrepared() { + m.RefreshMigrate() + m.Migrate.prepared = true + err := m.Migrate.prepareMigrations() + + require.NoError(m.T(), err) + assert.Nil(m.T(), m.Migrate.GORMigrate) +} + +func (m *MigrateTest) Test_prepareMigrations_OK() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModel()) + err := m.Migrate.prepareMigrations() + + require.NoError(m.T(), err) + assert.True(m.T(), m.Migrate.prepared) + assert.NotNil(m.T(), m.Migrate.GORMigrate) +} + +func (m *MigrateTest) Test_Migrate() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModel()) + + m.mock.ExpectBegin() + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE migrations (id VARCHAR(255) PRIMARY KEY)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT id FROM migrations`)). + WillReturnRows(sqlmock.NewRows([]string{"1"})) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("1"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "test_model" ("name" varchar(70) )`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectExec(regexp.QuoteMeta(`INSERT INTO migrations (id) VALUES ($1)`)). + WithArgs("1"). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectCommit() + + err := m.Migrate.Migrate() + + assert.NoError(m.T(), err) +} + +func TestMigrate_Migrate(t *testing.T) { + assert.NotNil(t, Migrations()) +} + +func TestMigrate_Suite(t *testing.T) { + suite.Run(t, new(MigrateTest)) +} diff --git a/core/utils.go b/core/utils.go index 6412296..35fefc2 100644 --- a/core/utils.go +++ b/core/utils.go @@ -25,18 +25,16 @@ import ( type Utils struct { IsDebug bool ConfigAWS ConfigAWS - Localizer *Localizer Logger *logging.Logger TokenCounter uint32 slashRegex *regexp.Regexp } // NewUtils will create new Utils instance -func NewUtils(awsConfig ConfigAWS, localizer *Localizer, logger *logging.Logger, debug bool) *Utils { +func NewUtils(awsConfig ConfigAWS, logger *logging.Logger, debug bool) *Utils { return &Utils{ IsDebug: debug, ConfigAWS: awsConfig, - Localizer: localizer, Logger: logger, TokenCounter: 0, slashRegex: slashRegex, @@ -141,6 +139,11 @@ func (u *Utils) UploadUserAvatar(url string) (picURLs3 string, err error) { return } +// RemoveTrailingSlash will remove slash at the end of any string +func (u *Utils) RemoveTrailingSlash(crmURL string) string { + return u.slashRegex.ReplaceAllString(crmURL, ``) +} + // GetMGItemData will upload file to MG by URL and return information about attachable item func GetMGItemData(client *v1.MgClient, url string, caption string) (v1.Item, int, error) { item := v1.Item{} @@ -160,11 +163,6 @@ func GetMGItemData(client *v1.MgClient, url string, caption string) (v1.Item, in return item, st, err } -// RemoveTrailingSlash will remove slash at the end of any string -func (u *Utils) RemoveTrailingSlash(crmURL string) string { - return u.slashRegex.ReplaceAllString(crmURL, ``) -} - // GetEntitySHA1 will serialize any value to JSON and return SHA1 hash of this JSON func GetEntitySHA1(v interface{}) (hash string, err error) { res, _ := json.Marshal(v) diff --git a/core/utils_test.go b/core/utils_test.go new file mode 100644 index 0000000..bcda9c7 --- /dev/null +++ b/core/utils_test.go @@ -0,0 +1,252 @@ +package core + +import ( + "encoding/json" + "net/http" + "testing" + "time" + + "github.com/h2non/gock" + "github.com/op/go-logging" + v5 "github.com/retailcrm/api-client-go/v5" + v1 "github.com/retailcrm/mg-transport-api-client-go/v1" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +var ( + testCRMURL = "https://fake-uri.retailcrm.ru" + testMGURL = "https://mg-url.example.com" +) + +type UtilsTest struct { + suite.Suite + utils *Utils +} + +func mgClient() *v1.MgClient { + return v1.New(testMGURL, "token") +} + +func (u *UtilsTest) SetupTest() { + logger := NewLogger("code", logging.DEBUG, DefaultLogFormatter()) + awsConfig := ConfigAWS{ + AccessKeyID: "access key id (will be removed)", + SecretAccessKey: "secret access key", + Region: "region", + Bucket: "bucket", + FolderName: "folder", + ContentType: "image/jpeg", + } + + u.utils = NewUtils(awsConfig, logger, false) + u.utils.TokenCounter = 12345 +} + +func (u *UtilsTest) Test_ResetUtils() { + assert.Equal(u.T(), "access key id (will be removed)", u.utils.ConfigAWS.AccessKeyID) + assert.Equal(u.T(), uint32(12345), u.utils.TokenCounter) + assert.False(u.T(), u.utils.IsDebug) + + awsConfig := u.utils.ConfigAWS + awsConfig.AccessKeyID = "access key id" + u.utils.resetUtils(awsConfig, true, 0) + + assert.Equal(u.T(), "access key id", u.utils.ConfigAWS.AccessKeyID) + assert.Equal(u.T(), uint32(0), u.utils.TokenCounter) + assert.True(u.T(), u.utils.IsDebug) +} + +func (u *UtilsTest) Test_GenerateToken() { + u.utils.TokenCounter = 12345 + token := u.utils.GenerateToken() + assert.NotEmpty(u.T(), token) + assert.Equal(u.T(), uint32(12346), u.utils.TokenCounter) +} + +func (u *UtilsTest) Test_GetAPIClient_FailRuntime() { + defer gock.Off() + gock.New(testCRMURL) + + _, status, err := u.utils.GetAPIClient(testCRMURL, "key") + assert.Equal(u.T(), http.StatusInternalServerError, status) + assert.NotNil(u.T(), err) +} + +func (u *UtilsTest) Test_GetAPIClient_FailAPI() { + defer gock.Off() + gock.New(testCRMURL). + Get("/credentials"). + Reply(http.StatusBadRequest). + BodyString(`{"success": false, "errorMsg": "error message"}`) + + _, status, err := u.utils.GetAPIClient(testCRMURL, "key") + assert.Equal(u.T(), http.StatusBadRequest, status) + if assert.NotNil(u.T(), err) { + assert.Equal(u.T(), "invalid credentials", err.Error()) + } +} + +func (u *UtilsTest) Test_GetAPIClient_FailAPICredentials() { + resp := v5.CredentialResponse{ + Success: true, + Credentials: []string{}, + SiteAccess: "all", + SitesAvailable: []string{}, + } + + data, _ := json.Marshal(resp) + + defer gock.Off() + gock.New(testCRMURL). + Get("/credentials"). + Reply(http.StatusOK). + BodyString(string(data)) + + _, status, err := u.utils.GetAPIClient(testCRMURL, "key") + assert.Equal(u.T(), http.StatusBadRequest, status) + if assert.NotNil(u.T(), err) { + assert.Equal(u.T(), "missing credentials", err.Error()) + } +} + +func (u *UtilsTest) Test_GetAPIClient_Success() { + resp := v5.CredentialResponse{ + Success: true, + Credentials: []string{ + "/api/integration-modules/{code}", + "/api/integration-modules/{code}/edit", + }, + SiteAccess: "all", + SitesAvailable: []string{"site"}, + } + + data, _ := json.Marshal(resp) + + defer gock.Off() + gock.New(testCRMURL). + Get("/credentials"). + Reply(http.StatusOK). + BodyString(string(data)) + + _, status, err := u.utils.GetAPIClient(testCRMURL, "key") + require.NoError(u.T(), err) + assert.Equal(u.T(), 0, status) +} + +func (u *UtilsTest) Test_UploadUserAvatar_FailGet() { + defer gock.Off() + gock.New("https://example.com") + + uri, err := u.utils.UploadUserAvatar("https://example.com/image.jpg") + assert.Empty(u.T(), uri) + assert.Error(u.T(), err) +} + +func (u *UtilsTest) Test_UploadUserAvatar_FailBadRequest() { + defer gock.Off() + gock.New("https://example.com"). + Get("/image.jpg"). + Reply(200). + BodyString(`no image here`) + + uri, err := u.utils.UploadUserAvatar("https://example.com/image.jpg") + assert.Empty(u.T(), uri) + assert.Error(u.T(), err) +} + +func (u *UtilsTest) Test_RemoveTrailingSlash() { + assert.Equal(u.T(), testCRMURL, u.utils.RemoveTrailingSlash(testCRMURL+"/")) + assert.Equal(u.T(), testCRMURL, u.utils.RemoveTrailingSlash(testCRMURL)) +} + +func TestUtils_GetMGItemData_FailRuntime_GetImage(t *testing.T) { + defer gock.Off() + gock.New(testMGURL) + gock.New("https://example.com/") + + _, status, err := GetMGItemData(mgClient(), "https://example.com/item.jpg", "") + assert.Error(t, err) + assert.Equal(t, 0, status) +} + +func TestUtils_GetMGItemData_FailAPI(t *testing.T) { + defer gock.Off() + + gock.New("https://example.com/"). + Get("/item.jpg"). + Reply(200). + BodyString(`fake data`) + + gock.New(testMGURL). + Post("/files/upload_by_url"). + Reply(400). + BodyString(`{"errors": ["error text"]}`) + + _, status, err := GetMGItemData(mgClient(), "https://example.com/item.jpg", "") + assert.Error(t, err) + assert.Equal(t, http.StatusBadRequest, status) + assert.Equal(t, "error text", err.Error()) +} + +func TestUtils_GetMGItemData_Success(t *testing.T) { + fileID := "file id" + size := 40 + uri := "file uri" + resp := v1.UploadFileResponse{ + ID: fileID, + Hash: "file hash", + Type: "image/jpeg", + Meta: v1.FileMeta{ + Width: &size, + Height: &size, + }, + MimeType: "image/jpeg", + Size: 250, + Url: &uri, + CreatedAt: time.Now(), + } + + data, _ := json.Marshal(resp) + + defer gock.Off() + + gock.New("https://example.com/"). + Get("/item.jpg"). + Reply(200). + BodyString(`fake data`) + + gock.New(testMGURL). + Post("/files/upload_by_url"). + Reply(200). + BodyString(string(data)) + + response, status, err := GetMGItemData(mgClient(), "https://example.com/item.jpg", "caption") + require.NoError(t, err) + assert.Equal(t, http.StatusOK, status) + assert.Equal(t, fileID, response.ID) + assert.Equal(t, "caption", response.Caption) +} + +func TestUtils_GetEntitySHA1(t *testing.T) { + entity := struct { + Field string + }{ + Field: "value", + } + + hash, err := GetEntitySHA1(entity) + require.NoError(t, err) + assert.Equal(t, "751b56fb98c9fd803140e8287b4236675554a668", hash) +} + +func TestUtils_ReplaceMarkdownSymbols(t *testing.T) { + test := "this *is* _test_ `string` [markdown" + expected := "this \\*is\\* \\_test\\_ \\`string\\` \\[markdown" + assert.Equal(t, expected, ReplaceMarkdownSymbols(test)) +} + +func TestUtils_Suite(t *testing.T) { + suite.Run(t, new(UtilsTest)) +} diff --git a/go.mod b/go.mod index c16d2bd..d92686d 100644 --- a/go.mod +++ b/go.mod @@ -3,6 +3,7 @@ module github.com/retailcrm/mg-transport-core go 1.12 require ( + github.com/DATA-DOG/go-sqlmock v1.3.3 github.com/aws/aws-sdk-go v1.23.9 github.com/certifi/gocertifi v0.0.0-20190506164543-d2eda7129713 // indirect github.com/denisenkom/go-mssqldb v0.0.0-20190830225923-3302f0226fbd // indirect @@ -10,9 +11,11 @@ require ( github.com/gin-contrib/multitemplate v0.0.0-20180827023943-5799bbbb6dce github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-gonic/gin v1.3.0 + github.com/gobuffalo/packd v0.3.0 github.com/gobuffalo/packr/v2 v2.6.0 github.com/golang/protobuf v1.3.2 // indirect github.com/google/go-querystring v1.0.0 // indirect + github.com/h2non/gock v1.0.10 github.com/jinzhu/gorm v1.9.10 github.com/lib/pq v1.2.0 // indirect github.com/mattn/go-isatty v0.0.9 // indirect @@ -22,12 +25,12 @@ require ( github.com/pkg/errors v0.8.1 github.com/retailcrm/api-client-go v1.1.1 github.com/retailcrm/mg-transport-api-client-go v1.1.31 - github.com/stretchr/testify v1.4.0 // indirect + github.com/stretchr/testify v1.4.0 github.com/ugorji/go v1.1.7 // indirect golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 - gopkg.in/gormigrate.v1 v1.6.0 // indirect + gopkg.in/gormigrate.v1 v1.6.0 gopkg.in/yaml.v2 v2.2.2 ) diff --git a/go.sum b/go.sum index abb9f4e..7c3e624 100644 --- a/go.sum +++ b/go.sum @@ -6,6 +6,8 @@ cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7h github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY= github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= +github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= github.com/Shopify/sarama v1.19.0/go.mod h1:FVkBWblsNy7DGZRfXLU0O9RCGt5g3g3yEuWXgklEdEo= github.com/Shopify/toxiproxy v2.1.4+incompatible/go.mod h1:OXgGpZ6Cli1/URJOF1DMxUHB2q5Ap20/P/eIdh4G0pI= github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc= @@ -50,9 +52,13 @@ github.com/go-logfmt/logfmt v0.3.0/go.mod h1:Qt1PoO58o5twSAckw1HlFXLmHsOX5/0LbT9 github.com/go-sql-driver/mysql v1.4.1 h1:g24URVg0OFbNUTx9qqY1IRZ9D9z3iPyi5zKhQZpNwpA= 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/gobuffalo/envy v1.7.0 h1:GlXgaiBkmrYMHco6t4j7SacKO4XUjvh5pwXh0f4uxXU= github.com/gobuffalo/envy v1.7.0/go.mod h1:n7DRkBerg/aorDM8kbduw5dN3oXGswK5liaSCx4T5NI= +github.com/gobuffalo/logger v1.0.0 h1:xw9Ko9EcC5iAFprrjJ6oZco9UpzS5MQ4jAwghsLHdy4= github.com/gobuffalo/logger v1.0.0/go.mod h1:2zbswyIUa45I+c+FLXuWl9zSWEiVuthsk8ze5s8JvPs= +github.com/gobuffalo/packd v0.3.0 h1:eMwymTkA1uXsqxS0Tpoop3Lc0u3kTfiMBE6nKtQU4g4= github.com/gobuffalo/packd v0.3.0/go.mod h1:zC7QkmNkYVGKPw4tHpBQ+ml7W/3tIebgeo1b36chA3Q= +github.com/gobuffalo/packr/v2 v2.6.0 h1:EMUzJIb5rof6r087PtGmgdzdLKpRBESJ/8jyL9MexfY= github.com/gobuffalo/packr/v2 v2.6.0/go.mod h1:sgEE1xNZ6G0FNN5xn9pevVu4nywaxHvgup67xisti08= github.com/gofrs/uuid v3.2.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM= github.com/gogo/protobuf v1.1.1/go.mod h1:r8qH/GZQm5c6nD/R0oafs1akxWv10x8SbQlK7atdtwQ= @@ -77,6 +83,8 @@ github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs167 github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= +github.com/h2non/gock v1.0.10 h1:EzHYzKKSLN4xk0w193uAy3tp8I3+L1jmaI2Mjg4lCgU= +github.com/h2non/gock v1.0.10/go.mod h1:CZMcB0Lg5IWnr9bF79pPMg9WeV6WumxQiUJ1UvdO1iE= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= @@ -95,9 +103,11 @@ github.com/jinzhu/now v1.0.1 h1:HjfetcXq097iXP0uoPCdnM4Efp5/9MsM0/M+XOTeR3M= github.com/jinzhu/now v1.0.1/go.mod h1:d3SSVoowX0Lcu0IBviAWJpolVfI5UJVZZ7cO71lE/z8= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5imkbgOkpRUYLnmbU7UEFbjtDA2hxJ1ichM= github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= +github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= +github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= @@ -150,9 +160,11 @@ github.com/retailcrm/api-client-go v1.1.1/go.mod h1:QRoPE2SM6ST7i2g0yEdqm7Iw98y7 github.com/retailcrm/mg-transport-api-client-go v1.1.31 h1:21pE1JhT49rvbMLDYJa0iiqbb/roz+eSp27fPck4uUw= github.com/retailcrm/mg-transport-api-client-go v1.1.31/go.mod h1:AWV6BueE28/6SCoyfKURTo4lF0oXYoOKmHTzehd5vAI= github.com/rogpeppe/go-internal v1.1.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= +github.com/rogpeppe/go-internal v1.3.0 h1:RR9dF3JtopPvtkroDZuVD7qquD0bnHlKSqaQhgwt8yk= github.com/rogpeppe/go-internal v1.3.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4= github.com/russross/blackfriday v1.5.2/go.mod h1:JO/DiYxRf+HjHt06OyowR9PTA263kcR/rfWxYHBV53g= github.com/sirupsen/logrus v1.2.0/go.mod h1:LxeOpSwHxABJmUn/MG1IvRgCAasNZTLOkJPxbbu5VWo= +github.com/sirupsen/logrus v1.4.2 h1:SPIRibHv4MatM3XXNO2BJeFLZwZ2LvZgfQ5+UNI2im4= github.com/sirupsen/logrus v1.4.2/go.mod h1:tLMulIdttU9McNUspp0xgXVQah82FyeX6MwdIuYE2rE= github.com/spf13/afero v1.1.2/go.mod h1:j4pytiNVoe2o6bmDsKpLACNPDBIoEAkihy7loJ1B0CQ= github.com/spf13/cast v1.3.0/go.mod h1:Qx5cxh0v+4UWYiBimWS+eyWzqEqokIECu5etghLkUJE= @@ -179,6 +191,7 @@ golang.org/x/crypto v0.0.0-20181203042331-505ab145d0a9/go.mod h1:6SG95UA2DQfeDnf golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c h1:Vj5n4GlwjmQteupaxJ9+0FNOmBrHfq7vN4btdGoDZgI= golang.org/x/crypto v0.0.0-20190325154230-a5d413f7728c/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w= +golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4 h1:ydJNl0ENAG67pFbB+9tfhiL2pYqLhfoaZFw/cjLhY4A= golang.org/x/crypto v0.0.0-20190621222207-cc06ce4a13d4/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/lint v0.0.0-20181026193005-c67002cb31c3/go.mod h1:UVdnD1Gm6xHRNCYTkRU2/jEulfH38KcIWyp/GAMgvoE= From dba75527319968c48bd43dd3ef328ee6a13e8a65 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:16:52 +0300 Subject: [PATCH 05/14] travis, codecov, more tests --- .travis.yml | 12 ++ core/config.go | 17 ++- core/config_test.go | 4 +- core/engine.go | 6 +- core/engine_test.go | 160 +++++++++++++++++++++++++++ core/migrate.go | 24 +++- core/migrate_test.go | 251 ++++++++++++++++++++++++++++++++++++++++-- core/models_test.go | 11 ++ core/orm_test.go | 73 ++++++++++++ core/sentry.go | 4 +- core/sentry_test.go | 114 +++++++++++++++++++ core/template_test.go | 56 ++++++++++ 12 files changed, 699 insertions(+), 33 deletions(-) create mode 100644 .travis.yml create mode 100644 core/engine_test.go create mode 100644 core/models_test.go create mode 100644 core/orm_test.go create mode 100644 core/sentry_test.go create mode 100644 core/template_test.go diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..a7324d1 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,12 @@ +language: go +go: + - '1.8' + - '1.9' + - '1.10' + - '1.11' +before_install: + - go get -t -v ./... +script: + - go test ./... -v -cpu 2 -race -cover -coverprofile=coverage.txt -covermode=atomic +after_success: + - bash <(curl -s https://codecov.io/bash) \ No newline at end of file diff --git a/core/config.go b/core/config.go index 055b37a..d218df6 100644 --- a/core/config.go +++ b/core/config.go @@ -24,7 +24,6 @@ type ConfigInterface interface { GetVersion() string GetSentryDSN() string GetLogLevel() logging.Level - GetDebug() bool GetHTTPConfig() HTTPServerConfig GetDBConfig() DatabaseConfig GetAWSConfig() ConfigAWS @@ -72,12 +71,12 @@ type ConfigAWS struct { // DatabaseConfig struct type DatabaseConfig struct { - Connection string `yaml:"connection"` - Logging bool `yaml:"logging"` - TablePrefix string `yaml:"table_prefix"` - MaxOpenConnections int `yaml:"max_open_connections"` - MaxIdleConnections int `yaml:"max_idle_connections"` - ConnectionLifetime int `yaml:"connection_lifetime"` + Connection interface{} `yaml:"connection"` + Logging bool `yaml:"logging"` + TablePrefix string `yaml:"table_prefix"` + MaxOpenConnections int `yaml:"max_open_connections"` + MaxIdleConnections int `yaml:"max_idle_connections"` + ConnectionLifetime int `yaml:"connection_lifetime"` } // HTTPServerConfig struct @@ -144,8 +143,8 @@ func (c Config) GetTransportInfo() InfoInterface { return c.TransportInfo } -// GetDebug debug flag -func (c Config) GetDebug() bool { +// IsDebug debug flag +func (c Config) IsDebug() bool { return c.Debug } diff --git a/core/config_test.go b/core/config_test.go index c1b939b..abe0e2d 100644 --- a/core/config_test.go +++ b/core/config_test.go @@ -85,8 +85,8 @@ func (c *ConfigTest) Test_GetLogLevel() { assert.Equal(c.T(), logging.Level(5), c.config.GetLogLevel()) } -func (c *ConfigTest) Test_GetDebug() { - assert.Equal(c.T(), true, c.config.GetDebug()) +func (c *ConfigTest) Test_IsDebug() { + assert.Equal(c.T(), true, c.config.IsDebug()) } func (c *ConfigTest) Test_GetUpdateInterval() { diff --git a/core/engine.go b/core/engine.go index fbb8a04..b09abd2 100644 --- a/core/engine.go +++ b/core/engine.go @@ -36,14 +36,14 @@ func New() *Engine { } func (e *Engine) initGin() { - if !e.Config.GetDebug() { + if !e.Config.IsDebug() { gin.SetMode(gin.ReleaseMode) } r := gin.New() r.Use(gin.Recovery()) - if e.Config.GetDebug() { + if e.Config.IsDebug() { r.Use(gin.Logger()) } @@ -76,7 +76,7 @@ func (e *Engine) Prepare() *Engine { e.LoadTranslations() e.createDB(e.Config.GetDBConfig()) e.createRavenClient(e.Config.GetSentryDSN()) - e.resetUtils(e.Config.GetAWSConfig(), e.Config.GetDebug(), 0) + e.resetUtils(e.Config.GetAWSConfig(), e.Config.IsDebug(), 0) e.Logger = NewLogger(e.Config.GetTransportInfo().GetCode(), e.Config.GetLogLevel(), e.LogFormatter) e.Sentry.Localizer = &e.Localizer e.Utils.Logger = e.Logger diff --git a/core/engine_test.go b/core/engine_test.go new file mode 100644 index 0000000..0d33b43 --- /dev/null +++ b/core/engine_test.go @@ -0,0 +1,160 @@ +package core + +import ( + "database/sql" + "html/template" + "io/ioutil" + "os" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/gin-gonic/gin" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type EngineTest struct { + suite.Suite + engine *Engine +} + +func (e *EngineTest) SetupTest() { + var ( + db *sql.DB + err error + ) + + e.engine = New() + require.NotNil(e.T(), e.engine) + + db, _, err = sqlmock.New() + require.NoError(e.T(), err) + + if _, err := os.Stat(testTranslationsDir); err != nil && os.IsNotExist(err) { + err := os.Mkdir(testTranslationsDir, os.ModePerm) + require.Nil(e.T(), err) + data := []byte("message: Test message\nmessage_template: Test message with {{.data}}") + err = ioutil.WriteFile(testLangFile, data, os.ModePerm) + require.Nil(e.T(), err) + } + + e.engine.Config = Config{ + Version: "1", + LogLevel: 5, + Database: DatabaseConfig{ + Connection: db, + Logging: true, + TablePrefix: "", + MaxOpenConnections: 10, + MaxIdleConnections: 10, + ConnectionLifetime: 60, + }, + SentryDSN: "sentry dsn", + HTTPServer: HTTPServerConfig{ + Host: "0.0.0.0", + Listen: ":3001", + }, + Debug: true, + UpdateInterval: 30, + ConfigAWS: ConfigAWS{}, + TransportInfo: Info{ + Name: "test", + Code: "test", + LogoPath: "/test.svg", + }, + } +} + +func (e *EngineTest) Test_Prepare_Twice() { + defer func() { + r := recover() + require.NotNil(e.T(), r) + assert.Equal(e.T(), "engine already initialized", r.(string)) + }() + + engine := New() + engine.prepared = true + engine.Prepare() +} + +func (e *EngineTest) Test_Prepare_NoConfig() { + defer func() { + r := recover() + require.NotNil(e.T(), r) + assert.Equal(e.T(), "engine.Config must be loaded before initializing", r.(string)) + }() + + engine := New() + engine.prepared = false + engine.Config = nil + engine.Prepare() +} + +func (e *EngineTest) Test_Prepare() { + defer func() { + require.Nil(e.T(), recover()) + }() + + e.engine.TranslationsPath = testTranslationsDir + e.engine.Prepare() + assert.True(e.T(), e.engine.prepared) +} + +func (e *EngineTest) Test_initGin_Release() { + engine := New() + engine.Config = Config{Debug: false} + engine.initGin() + assert.NotNil(e.T(), engine.ginEngine) +} + +func (e *EngineTest) Test_TemplateFuncMap() { + assert.NotNil(e.T(), e.engine.TemplateFuncMap(template.FuncMap{ + "test": func() string { + return "test" + }, + })) +} + +func (e *EngineTest) Test_CreateRenderer() { + e.engine.CreateRenderer(func(r *Renderer) { + assert.NotNil(e.T(), r) + }, template.FuncMap{}) +} + +func (e *EngineTest) Test_Router_Fail() { + defer func() { + r := recover() + require.NotNil(e.T(), r) + assert.Equal(e.T(), "prepare engine first", r.(string)) + }() + + engine := New() + engine.Router() +} + +func (e *EngineTest) Test_Router() { + e.engine.TranslationsPath = testTranslationsDir + e.engine.Prepare() + assert.NotNil(e.T(), e.engine.Router()) +} + +func (e *EngineTest) Test_ConfigureRouter() { + e.engine.TranslationsPath = testTranslationsDir + e.engine.Prepare() + e.engine.ConfigureRouter(func(engine *gin.Engine) { + assert.NotNil(e.T(), engine) + }) +} + +func (e *EngineTest) Test_Run_Fail() { + defer func() { + assert.NotNil(e.T(), recover()) + }() + + _ = New().Run() +} + +func TestEngine_Suite(t *testing.T) { + suite.Run(t, new(EngineTest)) +} diff --git a/core/migrate.go b/core/migrate.go index 3517237..5c7938e 100644 --- a/core/migrate.go +++ b/core/migrate.go @@ -1,6 +1,7 @@ package core import ( + "fmt" "sort" "github.com/jinzhu/gorm" @@ -78,6 +79,10 @@ func (m *Migrate) Rollback() error { return err } + if m.first == nil { + return errors.New("abnormal termination: first migration is nil") + } + if err := m.GORMigrate.RollbackTo(m.first.ID); err == nil { if err := m.GORMigrate.RollbackMigration(m.first); err == nil { return nil @@ -115,10 +120,10 @@ func (m *Migrate) MigrateNextTo(version string) error { if next, err := m.NextFrom(version); err == nil { current := m.Current() switch { - case current > next: - return m.GORMigrate.RollbackTo(next) case current < next: return m.GORMigrate.MigrateTo(next) + case current > next: + return errors.New(fmt.Sprintf("current migration version '%s' is higher than fetched version '%s'", current, next)) default: return nil } @@ -139,7 +144,9 @@ func (m *Migrate) MigratePreviousTo(version string) error { case current > prev: return m.GORMigrate.RollbackTo(prev) case current < prev: - return m.GORMigrate.MigrateTo(prev) + return errors.New(fmt.Sprintf("current migration version '%s' is lower than fetched version '%s'", current, prev)) + case prev == "0": + return m.GORMigrate.RollbackMigration(m.first) default: return nil } @@ -162,17 +169,24 @@ func (m *Migrate) Current() string { var migrationInfo MigrationInfo if m.db == nil { + fmt.Println("warning => db is nil - cannot return migration version") return "0" } if !m.db.HasTable(MigrationInfo{}) { - m.db.CreateTable(MigrationInfo{}) + if err := m.db.CreateTable(MigrationInfo{}).Error; err == nil { + fmt.Println("info => created migrations table") + } else { + panic(err.Error()) + } + return "0" } if err := m.db.Last(&migrationInfo).Error; err == nil { return migrationInfo.ID } else { + fmt.Printf("warning => cannot fetch migration version: %s\n", err.Error()) return "0" } } @@ -199,7 +213,7 @@ func (m *Migrate) PreviousFrom(version string) (string, error) { if key > 0 { return m.versions[key-1], nil } else { - return "", errors.New("this is first migration") + return "0", nil } } } diff --git a/core/migrate_test.go b/core/migrate_test.go index 831d735..8ce67c9 100644 --- a/core/migrate_test.go +++ b/core/migrate_test.go @@ -7,6 +7,7 @@ import ( "github.com/DATA-DOG/go-sqlmock" "github.com/jinzhu/gorm" + _ "github.com/jinzhu/gorm/dialects/postgres" "github.com/stretchr/testify/assert" "github.com/stretchr/testify/require" "github.com/stretchr/testify/suite" @@ -29,13 +30,16 @@ type MigrateTest struct { } func (m *MigrateTest) SetupSuite() { + require.NotEmpty(m.T(), (MigrationInfo{}).TableName()) + m.RefreshMigrate() +} + +func (m *MigrateTest) RefreshMigrate() { var ( db *sql.DB err error ) - require.NotEmpty(m.T(), (MigrationInfo{}).TableName()) - db, m.mock, err = sqlmock.New() require.NoError(m.T(), err) @@ -43,11 +47,6 @@ func (m *MigrateTest) SetupSuite() { require.NoError(m.T(), err) m.DB.LogMode(true) - m.RefreshMigrate() - m.Migrate.SetDB(m.DB) -} - -func (m *MigrateTest) RefreshMigrate() { m.Migrate = &Migrate{ db: m.DB, prepared: false, @@ -55,7 +54,7 @@ func (m *MigrateTest) RefreshMigrate() { } } -func (m *MigrateTest) Migration_TestModel() *gormigrate.Migration { +func (m *MigrateTest) Migration_TestModelFirst() *gormigrate.Migration { return &gormigrate.Migration{ ID: "1", Migrate: func(db *gorm.DB) error { @@ -67,15 +66,28 @@ func (m *MigrateTest) Migration_TestModel() *gormigrate.Migration { } } +func (m *MigrateTest) Migration_TestModelSecond() *gormigrate.Migration { + return &gormigrate.Migration{ + ID: "2", + Migrate: func(db *gorm.DB) error { + return db.Model(TestModel{}).ModifyColumn("name", "varchar(100)").Error + }, + Rollback: func(db *gorm.DB) error { + return db.Model(TestModel{}).ModifyColumn("name", "varchar(70)").Error + }, + } +} + func (m *MigrateTest) Test_Add() { m.RefreshMigrate() m.Migrate.Add(nil) - m.Migrate.Add(m.Migration_TestModel()) + m.Migrate.Add(m.Migration_TestModelFirst()) assert.Equal(m.T(), 1, len(m.Migrate.migrations)) i, ok := m.Migrate.migrations["1"] require.True(m.T(), ok) assert.Equal(m.T(), "1", i.ID) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) } func (m *MigrateTest) Test_prepareMigrations_NilDB() { @@ -85,6 +97,7 @@ func (m *MigrateTest) Test_prepareMigrations_NilDB() { require.Error(m.T(), err) assert.Equal(m.T(), "db must not be nil", err.Error()) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) } func (m *MigrateTest) Test_prepareMigrations_AlreadyPrepared() { @@ -94,21 +107,57 @@ func (m *MigrateTest) Test_prepareMigrations_AlreadyPrepared() { require.NoError(m.T(), err) assert.Nil(m.T(), m.Migrate.GORMigrate) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) } func (m *MigrateTest) Test_prepareMigrations_OK() { m.RefreshMigrate() - m.Migrate.Add(m.Migration_TestModel()) + m.Migrate.Add(m.Migration_TestModelFirst()) err := m.Migrate.prepareMigrations() require.NoError(m.T(), err) assert.True(m.T(), m.Migrate.prepared) assert.NotNil(m.T(), m.Migrate.GORMigrate) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) } -func (m *MigrateTest) Test_Migrate() { +func (m *MigrateTest) Test_Migrate_Fail_NilDB() { m.RefreshMigrate() - m.Migrate.Add(m.Migration_TestModel()) + m.Migrate.SetDB(nil) + m.Migrate.Add(m.Migration_TestModelFirst()) + + err := m.Migrate.Migrate() + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Migrate_Success_NoMigrations() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + + m.mock.ExpectBegin() + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE migrations (id VARCHAR(255) PRIMARY KEY)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT id FROM migrations`)). + WillReturnRows(sqlmock.NewRows([]string{"1"})) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("1"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + m.mock.ExpectCommit() + + err := m.Migrate.Migrate() + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Migrate_Success() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) m.mock.ExpectBegin() m.mock. @@ -133,6 +182,184 @@ func (m *MigrateTest) Test_Migrate() { err := m.Migrate.Migrate() assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Rollback_Fail_NilDB() { + m.RefreshMigrate() + m.Migrate.SetDB(nil) + m.Migrate.Add(m.Migration_TestModelFirst()) + + err := m.Migrate.Rollback() + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Rollback_Fail_NoMigrations() { + m.RefreshMigrate() + m.Migrate.first = m.Migration_TestModelFirst() + + err := m.Migrate.Rollback() + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Rollback_Fail_NoFirstMigration() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + m.Migrate.first = nil + + err := m.Migrate.Rollback() + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_MigrateTo_Fail_NilDB() { + m.RefreshMigrate() + m.Migrate.SetDB(nil) + + err := m.Migrate.MigrateTo("version") + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_MigrateTo_DoNothing() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectBegin() + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE migrations (id VARCHAR(255) PRIMARY KEY)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT id FROM migrations`)). + WillReturnRows(sqlmock.NewRows([]string{"1"})) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("1"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + m.mock.ExpectCommit() + + err := m.Migrate.MigrateTo(m.Migration_TestModelFirst().ID) + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_MigrateTo() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectBegin() + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE migrations (id VARCHAR(255) PRIMARY KEY)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT id FROM migrations`)). + WillReturnRows(sqlmock.NewRows([]string{"1"})) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("1"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "test_model" ("name" varchar(70) )`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectExec(regexp.QuoteMeta(`INSERT INTO migrations (id) VALUES ($1)`)). + WithArgs("1"). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectCommit() + + err := m.Migrate.MigrateTo(m.Migration_TestModelFirst().ID) + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_RollbackTo() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + m.Migrate.Add(m.Migration_TestModelSecond()) + + m.mock.ExpectBegin() + m.mock.ExpectCommit() + + err := m.Migrate.RollbackTo(m.Migration_TestModelSecond().ID) + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_MigrateNextTo() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + m.Migrate.Add(m.Migration_TestModelSecond()) + + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectBegin() + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE migrations (id VARCHAR(255) PRIMARY KEY)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT id FROM migrations`)). + WillReturnRows(sqlmock.NewRows([]string{"1"})) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("1"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(1)) + m.mock. + ExpectQuery(regexp.QuoteMeta(`SELECT count(*) FROM "migrations" WHERE (id = $1)`)). + WithArgs("2"). + WillReturnRows(sqlmock.NewRows([]string{"count"}).AddRow(0)) + m.mock. + ExpectExec(regexp.QuoteMeta(`ALTER TABLE "test_model" ALTER COLUMN "name" TYPE varchar(100)`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock. + ExpectExec(regexp.QuoteMeta(`INSERT INTO migrations (id) VALUES ($1)`)). + WithArgs("2"). + WillReturnResult(sqlmock.NewResult(1, 1)) + m.mock.ExpectCommit() + + err := m.Migrate.MigrateNextTo(m.Migration_TestModelFirst().ID) + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_MigratePreviousTo() { + m.RefreshMigrate() + m.Migrate.Add(m.Migration_TestModelFirst()) + m.Migrate.Add(m.Migration_TestModelSecond()) + + m.mock. + ExpectExec(regexp.QuoteMeta(`CREATE TABLE "migrations" ("id" varchar(255) , PRIMARY KEY ("id"))`)). + WillReturnResult(sqlmock.NewResult(1, 1)) + + err := m.Migrate.MigratePreviousTo(m.Migration_TestModelSecond().ID) + + assert.Error(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) +} + +func (m *MigrateTest) Test_Close() { + m.RefreshMigrate() + m.mock.ExpectClose() + err := m.Migrate.Close() + + assert.NoError(m.T(), err) + assert.NoError(m.T(), m.mock.ExpectationsWereMet()) } func TestMigrate_Migrate(t *testing.T) { diff --git a/core/models_test.go b/core/models_test.go new file mode 100644 index 0000000..6c26666 --- /dev/null +++ b/core/models_test.go @@ -0,0 +1,11 @@ +package core + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestModels_TableName(t *testing.T) { + assert.NotEmpty(t, (User{}).TableName()) +} diff --git a/core/orm_test.go b/core/orm_test.go new file mode 100644 index 0000000..404c947 --- /dev/null +++ b/core/orm_test.go @@ -0,0 +1,73 @@ +package core + +import ( + "database/sql" + "testing" + + "github.com/DATA-DOG/go-sqlmock" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" +) + +func TestORM_NewORM(t *testing.T) { + var ( + db *sql.DB + err error + ) + + defer func() { + require.Nil(t, recover()) + }() + + db, _, err = sqlmock.New() + require.NoError(t, err) + + config := DatabaseConfig{ + Connection: db, + Logging: true, + TablePrefix: "", + MaxOpenConnections: 10, + MaxIdleConnections: 10, + ConnectionLifetime: 100, + } + + _ = NewORM(config) +} + +func TestORM_createDB_Fail(t *testing.T) { + defer func() { + assert.NotNil(t, recover()) + }() + + NewORM(DatabaseConfig{Connection: nil}) +} + +func TestORM_CloseDB(t *testing.T) { + var ( + db *sql.DB + dbMock sqlmock.Sqlmock + err error + ) + + defer func() { + require.Nil(t, recover()) + }() + + db, dbMock, err = sqlmock.New() + require.NoError(t, err) + + config := DatabaseConfig{ + Connection: db, + Logging: true, + TablePrefix: "", + MaxOpenConnections: 10, + MaxIdleConnections: 10, + ConnectionLifetime: 100, + } + + dbMock.ExpectClose() + orm := NewORM(config) + orm.CloseDB() + + assert.NoError(t, dbMock.ExpectationsWereMet()) +} diff --git a/core/sentry.go b/core/sentry.go index 0d3d7a7..763ef73 100644 --- a/core/sentry.go +++ b/core/sentry.go @@ -287,7 +287,7 @@ func (t *SentryTaggedStruct) GetProperty(v interface{}, property string) (name s err = fmt.Errorf("cannot find property `%s`", property) } - field := val.FieldByName(property) + field := reflect.Indirect(val.FieldByName(property)) if !field.IsValid() { err = fmt.Errorf("invalid property, got %s", field.String()) return @@ -477,4 +477,4 @@ func getErrorCause(err error) error { return nil } return cer.Cause() -} \ No newline at end of file +} diff --git a/core/sentry_test.go b/core/sentry_test.go new file mode 100644 index 0000000..c263168 --- /dev/null +++ b/core/sentry_test.go @@ -0,0 +1,114 @@ +package core + +import ( + "errors" + "testing" + + "github.com/getsentry/raven-go" + pkgErrors "github.com/pkg/errors" + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +type SampleStruct struct { + ID int + Pointer *int + Field string +} + +type SentryTest struct { + suite.Suite + sentry *Sentry + structTags *SentryTaggedStruct + scalarTags *SentryTaggedScalar +} + +func (s *SentryTest) SetupTest() { + s.structTags = NewTaggedStruct(SampleStruct{}, "struct", map[string]string{"fake": "prop"}) + s.scalarTags = NewTaggedScalar("", "scalar", "Scalar") + require.Equal(s.T(), "struct", s.structTags.GetContextKey()) + require.Equal(s.T(), "scalar", s.scalarTags.GetContextKey()) + require.Equal(s.T(), "", s.structTags.GetName()) + require.Equal(s.T(), "Scalar", s.scalarTags.GetName()) + s.structTags.Tags = map[string]string{} +} + +func (s *SentryTest) TestStruct_AddTag() { + s.structTags.AddTag("test field", "Field") + require.NotEmpty(s.T(), s.structTags.GetTags()) + + tags, err := s.structTags.BuildTags(SampleStruct{Field: "value"}) + require.NoError(s.T(), err) + require.NotEmpty(s.T(), tags) + + i, ok := tags["test field"] + require.True(s.T(), ok) + assert.Equal(s.T(), "value", i) +} + +func (s *SentryTest) TestStruct_GetProperty() { + s.structTags.AddTag("test field", "Field") + name, value, err := s.structTags.GetProperty(SampleStruct{Field: "test"}, "Field") + require.NoError(s.T(), err) + assert.Equal(s.T(), "test field", name) + assert.Equal(s.T(), "test", value) +} + +func (s *SentryTest) TestStruct_GetProperty_InvalidStruct() { + _, _, err := s.structTags.GetProperty(nil, "Field") + require.Error(s.T(), err) + assert.Equal(s.T(), "invalid value provided", err.Error()) +} + +func (s *SentryTest) TestStruct_GetProperty_GotScalar() { + _, _, err := s.structTags.GetProperty("str", "Field") + require.Error(s.T(), err) + assert.Equal(s.T(), "passed value must be struct, str provided", err.Error()) +} + +func (s *SentryTest) TestStruct_GetProperty_InvalidType() { + _, _, err := s.structTags.GetProperty(Sentry{}, "Field") + require.Error(s.T(), err) + assert.Equal(s.T(), "passed value should be of type `core.SampleStruct`, got `core.Sentry` instead", err.Error()) +} + +func (s *SentryTest) TestStruct_GetProperty_CannotFindProperty() { + _, _, err := s.structTags.GetProperty(SampleStruct{ID: 1}, "ID") + require.Error(s.T(), err) + assert.Equal(s.T(), "cannot find property `ID`", err.Error()) +} + +func (s *SentryTest) TestStruct_GetProperty_InvalidProperty() { + s.structTags.AddTag("test invalid", "Pointer") + _, _, err := s.structTags.GetProperty(SampleStruct{Pointer: nil}, "Pointer") + require.Error(s.T(), err) + assert.Equal(s.T(), "invalid property, got ", err.Error()) +} + +func TestSentry_newRavenStackTrace_Fail(t *testing.T) { + defer func() { + assert.NotNil(t, recover()) + }() + + newRavenStackTrace(nil, errors.New("error"), 0) +} + +func TestSentry_newRavenStackTrace(t *testing.T) { + st := newRavenStackTrace(&raven.Client{}, errors.New("error"), 0) + + require.NotNil(t, st) + assert.NotEmpty(t, st.Frames) +} + +func TestSentry_newRavenStackTrace_ErrorsPkg(t *testing.T) { + err := pkgErrors.New("error") + st := newRavenStackTrace(&raven.Client{}, err, 0) + + require.NotNil(t, st) + assert.NotEmpty(t, st.Frames) +} + +func TestSentry_Suite(t *testing.T) { + suite.Run(t, new(SentryTest)) +} diff --git a/core/template_test.go b/core/template_test.go new file mode 100644 index 0000000..05e6e9f --- /dev/null +++ b/core/template_test.go @@ -0,0 +1,56 @@ +package core + +import ( + "fmt" + "html/template" + "io/ioutil" + "os" + "path" + "testing" + + "github.com/stretchr/testify/assert" + "github.com/stretchr/testify/require" + "github.com/stretchr/testify/suite" +) + +var ( + testTemplatesDir = path.Join(os.TempDir(), "templates_test_dir") + testTemplatesFile = path.Join(testTemplatesDir, "tpl%d.html") +) + +type TemplateTest struct { + suite.Suite + renderer Renderer +} + +func (t *TemplateTest) SetupTest() { + if _, err := os.Stat(testTemplatesDir); err != nil && os.IsNotExist(err) { + err := os.Mkdir(testTemplatesDir, os.ModePerm) + require.Nil(t.T(), err) + data1 := []byte(`data {{template "body" .}}`) + data2 := []byte(`{{define "body"}}test {{"test" | trans}}{{end}}`) + err1 := ioutil.WriteFile(fmt.Sprintf(testTemplatesFile, 1), data1, os.ModePerm) + err2 := ioutil.WriteFile(fmt.Sprintf(testTemplatesFile, 2), data2, os.ModePerm) + require.Nil(t.T(), err1) + require.Nil(t.T(), err2) + } + + t.renderer = NewRenderer(template.FuncMap{ + "trans": func(data string) string { + if data == "test" { + return "ok" + } + + return "fail" + }, + }) +} + +func (t *TemplateTest) Test_Push() { + tpl := t.renderer.Push("index", fmt.Sprintf(testTemplatesFile, 1), fmt.Sprintf(testTemplatesFile, 2)) + assert.Equal(t.T(), 3, len(tpl.Templates())) +} + +func TestTemplate_Suite(t *testing.T) { + suite.Run(t, new(TemplateTest)) +} From 20dd81c48962987d4b46c24225622895e0638b25 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:19:36 +0300 Subject: [PATCH 06/14] go mod tidy --- .travis.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.travis.yml b/.travis.yml index a7324d1..24591e3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,7 +5,7 @@ go: - '1.10' - '1.11' before_install: - - go get -t -v ./... + - go mod tidy script: - go test ./... -v -cpu 2 -race -cover -coverprofile=coverage.txt -covermode=atomic after_success: From 94b7f17c6c0b13795bdbd9ed7e66274540015847 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:22:15 +0300 Subject: [PATCH 07/14] test on newer golang versions --- .travis.yml | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 24591e3..407ab52 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,9 +1,11 @@ language: go +env: + - GO111MODULE=on go: - - '1.8' - - '1.9' - '1.10' - '1.11' + - '1.12' + - '1.13' before_install: - go mod tidy script: From 4ddf6a598501c60387ffd04dd0c869fe71d75d5e Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:25:07 +0300 Subject: [PATCH 08/14] set lowest version of go to 1.11 --- .travis.yml | 1 - go.mod | 8 +++++--- go.sum | 34 +++++++++++++++++++--------------- 3 files changed, 24 insertions(+), 19 deletions(-) diff --git a/.travis.yml b/.travis.yml index 407ab52..70763bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: go env: - GO111MODULE=on go: - - '1.10' - '1.11' - '1.12' - '1.13' diff --git a/go.mod b/go.mod index d92686d..279832e 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/retailcrm/mg-transport-core -go 1.12 +go 1.11 require ( github.com/DATA-DOG/go-sqlmock v1.3.3 @@ -17,19 +17,21 @@ require ( github.com/google/go-querystring v1.0.0 // indirect github.com/h2non/gock v1.0.10 github.com/jinzhu/gorm v1.9.10 + github.com/json-iterator/go v1.1.7 // indirect github.com/lib/pq v1.2.0 // indirect github.com/mattn/go-isatty v0.0.9 // indirect github.com/mattn/go-sqlite3 v1.11.0 // indirect + github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 // indirect github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5 github.com/op/go-logging v0.0.0-20160315200505-970db520ece7 github.com/pkg/errors v0.8.1 github.com/retailcrm/api-client-go v1.1.1 github.com/retailcrm/mg-transport-api-client-go v1.1.31 github.com/stretchr/testify v1.4.0 - github.com/ugorji/go v1.1.7 // indirect + github.com/ugorji/go/codec v1.1.7 // indirect golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 - golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274 // indirect + gopkg.in/go-playground/assert.v1 v1.2.1 // indirect gopkg.in/go-playground/validator.v8 v8.18.2 gopkg.in/gormigrate.v1 v1.6.0 gopkg.in/yaml.v2 v2.2.2 diff --git a/go.sum b/go.sum index 7c3e624..c4b4ba9 100644 --- a/go.sum +++ b/go.sum @@ -5,6 +5,7 @@ cloud.google.com/go v0.37.4 h1:glPeL3BQJsbF6aIIYfZizMwc5LTYz250bDMjttbBGAU= cloud.google.com/go v0.37.4/go.mod h1:NHPJ89PdicEuT9hdPXMROBD91xc5uRDxsMtSB16k7hw= github.com/BurntSushi/toml v0.3.0 h1:e1/Ivsx3Z0FVTV0NSOv/aVgbUWyQuzj7DDnFblkRvsY= github.com/BurntSushi/toml v0.3.0/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= +github.com/BurntSushi/toml v0.3.1 h1:WXkYYl6Yr3qBf1K79EBnL4mak0OimBfB0XUf9Vl28OQ= github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU= github.com/DATA-DOG/go-sqlmock v1.3.3 h1:CWUqKXe0s8A2z6qCgkP4Kru7wC11YoAnoupUKFDnH08= github.com/DATA-DOG/go-sqlmock v1.3.3/go.mod h1:f/Ixk793poVmq4qj/V1dPUg2JEAKC73Q5eFN3EC/SaM= @@ -37,7 +38,6 @@ github.com/eapache/go-xerial-snappy v0.0.0-20180814174437-776d5712da21/go.mod h1 github.com/eapache/queue v1.1.0/go.mod h1:6eCeP0CKFpHLu8blIFXhExK/dRa7WDZfr6jVFPTqq+I= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5 h1:Yzb9+7DPaBjB8zlTR87/ElzFsnQfuHnVUVqpZZIcV5Y= github.com/erikstmartin/go-testdb v0.0.0-20160219214506-8d10e4a1bae5/go.mod h1:a2zkGnVExMxdzMo3M0Hi/3sEU+cWnZpSni0O6/Yb/P0= -github.com/fatih/color v1.7.0/go.mod h1:Zm6kSWBoL9eyXnKyktHP6abPY2pDugNf5KwzbycvMj4= github.com/fsnotify/fsnotify v1.4.7/go.mod h1:jwhsz4b93w/PPRr/qN1Yymfu8t87LnFCMoQvtojpjFo= github.com/getsentry/raven-go v0.0.0-20180903072508-084a9de9eb03 h1:G/9fPivTr5EiyqE9OlW65iMRUxFXMGRHgZFGo50uG8Q= github.com/getsentry/raven-go v0.0.0-20180903072508-084a9de9eb03/go.mod h1:KungGk8q33+aIAZUIVWZDr2OfAEBsO49PX4NzFV5kcQ= @@ -71,15 +71,13 @@ github.com/golang/protobuf v1.3.2 h1:6nsPYzhq5kReh6QImI3k5qWzO4PEbvbIW2cwSfR/6xs 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/go-cmp v0.2.0 h1:+dTQ8DZQJz0Mb/HjFlkptS1FeQ4cWSnN941F8aEG4SQ= github.com/google/go-cmp v0.2.0/go.mod h1:oXzfMopK8JAjlY9xF4vHSVASa0yLyX7SntLO5aqRK0M= github.com/google/go-querystring v1.0.0 h1:Xkwi/a1rcvNg1PPYe5vI8GbeBY/jrVuDX5ASuANWTrk= github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck= +github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= 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/subcommands v1.0.1 h1:/eqq+otEXm5vhfBrbREPCSVQbvofip6kIz+mX5TUH7k= -github.com/google/subcommands v1.0.1/go.mod h1:ZjhPrFU+Olkh9WazFPsl27BQ4UPiG37m3yTrtFlrHVk= -github.com/google/wire v0.3.0 h1:imGQZGEVEHpje5056+K+cgdO72p0LQv2xIIFXNGUf60= -github.com/google/wire v0.3.0/go.mod h1:i1DMg/Lu8Sz5yYl25iOdmc5CT5qusaa+zmRWs16741s= github.com/googleapis/gax-go/v2 v2.0.4/go.mod h1:0Wqv26UfaUD9n4G6kQubkQ+KchISgw+vpHVxEJEs9eg= github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg= github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs= @@ -89,8 +87,6 @@ github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ github.com/hashicorp/hcl v1.0.0/go.mod h1:E5yfLk+7swimpb2L/Alb/PJmXilQ/rhwaUYs4T20WEQ= github.com/hpcloud/tail v1.0.0/go.mod h1:ab1qPbhIpdTxEkNHXyeSf5vhxWSCs/tWer42PpOxQnU= github.com/inconshreveable/mousetrap v1.0.0/go.mod h1:PxqpIevigyE2G7u3NXJIT2ANytuPF1OarO4DADm73n8= -github.com/jinzhu/gorm v1.9.1 h1:lDSDtsCt5AGGSKTs8AHlSDbbgif4G4+CKJ8ETBDVHTA= -github.com/jinzhu/gorm v1.9.1/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.2 h1:lCvgEaqe/HVE+tjAR2mt4HbbHAZsQOv3XAZiEZV37iw= github.com/jinzhu/gorm v1.9.2/go.mod h1:Vla75njaFJ8clLU1W44h34PjIkijhjHIYnZxMqCdxqo= github.com/jinzhu/gorm v1.9.10 h1:HvrsqdhCW78xpJF67g1hMxS6eCToo9PZH4LDB8WKPac= @@ -105,24 +101,27 @@ github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af h1:pmfjZENx5i github.com/jmespath/go-jmespath v0.0.0-20180206201540-c2b33e8439af/go.mod h1:Nht3zPeWKUH0NzdCt2Blrr5ys8VGpn0CEB0cQHVjt7k= github.com/joho/godotenv v1.3.0 h1:Zjp+RcGpHhGlrMbJzXTrZZPrWj+1vfm90La1wgB6Bhc= github.com/joho/godotenv v1.3.0/go.mod h1:7hK45KPybAkOC6peb+G5yklZfMxEjkZhHbwpqxOKXbg= +github.com/json-iterator/go v1.1.7 h1:KfgG9LzI+pYjr4xvmz/5H4FXjokeP+rlHLhv3iH62Fo= +github.com/json-iterator/go v1.1.7/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/julienschmidt/httprouter v1.2.0/go.mod h1:SYymIcj16QtmaHHD7aYtjjsJG7VTCxuUUipMqKk8s4w= github.com/karrick/godirwalk v1.10.12 h1:BqUm+LuJcXjGv1d2mj3gBiQyrQ57a0rYoAmhvJQ7RDU= github.com/karrick/godirwalk v1.10.12/go.mod h1:RoGL9dQei4vP9ilrpETWE8CLOZ1kiN0LhBygSwrAsHA= github.com/kisielk/gotool v1.0.0/go.mod h1:XhKaO+MFFWcvkIS/tQcRk01m1F5IRFswLeQ+oQHNcck= github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ= +github.com/konsorten/go-windows-terminal-sequences v1.0.2 h1:DB17ag19krx9CFsz4o3enTrPXyIXCl+2iCXH/aMAp9s= github.com/konsorten/go-windows-terminal-sequences v1.0.2/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 h1:L/CwN0zerZDmRFUapSPitk6f+Q3+0za1rQkzVuMiMFI= 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 h1:45sCR5RtlFHMR4UwH9sdQ5TC8v0qDQCHnXt+kaKSTVE= 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/lib/pq v1.1.1/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/lib/pq v1.2.0 h1:LXpIM/LZ5xGFhOpXAQUIMM1HdyqzVYM13zNdjCEEcA0= github.com/lib/pq v1.2.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo= github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ= -github.com/mattn/go-colorable v0.1.2/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= -github.com/mattn/go-isatty v0.0.8/go.mod h1:Iq45c/XA43vh69/j3iqttzPXn0bhXyGjM0Hdxcsrc5s= github.com/mattn/go-isatty v0.0.9 h1:d5US/mDsogSGW37IV293h//ZFaeajb69h+EHFsv2xGg= github.com/mattn/go-isatty v0.0.9/go.mod h1:YNRxwqDuOph6SZLI9vUUz6OYw3QyUt7WiY2yME+cCiQ= github.com/mattn/go-sqlite3 v1.10.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc= @@ -131,7 +130,13 @@ github.com/mattn/go-sqlite3 v1.11.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsO github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5Ld7szi9bcBfOoFv/3dc6xSMkL2PC0= github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/mapstructure v1.1.2/go.mod h1:FVVH3fgwuzCH5S8UJGiWEs2h04kUh9fWfEaFds41c1Y= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= +github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742 h1:Esafd1046DLDQ0W1YjYsBW+p8U2u7vzgW2SQVmlNazg= +github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0= github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32 h1:W6apQkHrMkS0Muv8G/TipAy/FJl/rCYT0+EuS8+Z0z4= +github.com/nbio/st v0.0.0-20140626010706-e9e8d9816f32/go.mod h1:9wM+0iRr9ahx58uYLpLIr5fm8diHn0JbqRycJi6w0Ms= github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5 h1:/TjjTS4kg7vC+05gD0LE4+97f/+PRFICnK/7wJPk7kE= github.com/nicksnyder/go-i18n/v2 v2.0.0-beta.5/go.mod h1:4Opqa6/HIv0lhG3WRAkqzO0afezkRhxXI0P8EJkqeRU= github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE= @@ -206,7 +211,6 @@ golang.org/x/net v0.0.0-20190125091013-d26f9f9a57f3/go.mod h1:mL1N/T3taQHkDXs73r 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-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 h1:fHDIZ2oxGnUZRN6WgWFCbYBjH9uqVPRCUVUDhs0wnbA= golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= @@ -215,6 +219,7 @@ golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJ 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 h1:8gQV6CLnAEikrhgkHFbMAEhagSSnXWGV915qUMm9mrU= golang.org/x/sync v0.0.0-20190423024810-112230192c58/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= @@ -223,7 +228,6 @@ golang.org/x/sys v0.0.0-20181116152217-5ac8a444bdc5/go.mod h1:STP8DvDyc/dI5b8T5h golang.org/x/sys v0.0.0-20181122145206-62eef0e2fa9b/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/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-20190222072716-a9d3bda3a223/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY= golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190422165155-953cdadca894/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= golang.org/x/sys v0.0.0-20190515120540-06a5c4944438/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= @@ -239,14 +243,11 @@ golang.org/x/tools v0.0.0-20180828015842-6cd1fcedba52/go.mod h1:n7NCudcB/nEzxVGm golang.org/x/tools v0.0.0-20190114222345-bf090417da8b/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-20190312170243-e65039ee4138/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= -golang.org/x/tools v0.0.0-20190422233926-fe54fb35175b/go.mod h1:LCzVGOaR6xXOjkQ3onu1FJEFr0SW1gC7cKk1uF8kGRs= golang.org/x/tools v0.0.0-20190628153133-6cdbf07be9d0/go.mod h1:/rFqwRUd4F7ZHNgwSSTFct+R/Kf4OFW1sUzUTQQTgfc= -golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274 h1:3LEbAKuShoQDlrpbepJOeKph85ROShka+GypY1YNQYQ= -golang.org/x/tools v0.0.0-20190830082254-f340ed3ae274/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo= -golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= google.golang.org/api v0.3.1/go.mod h1:6wY9I6uQWHQ8EM57III9mq/AjF+i8G65rmVagqKMtkk= google.golang.org/appengine v1.1.0/go.mod h1:EbEs0AVv82hx2wNQdGPgUI5lhzA/G0D9YwlJXL52JkM= google.golang.org/appengine v1.3.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= +google.golang.org/appengine v1.4.0 h1:/wp5JvzpHIxhs/dumFmF7BXTf3Z+dd4uXta4kVyO508= google.golang.org/appengine v1.4.0/go.mod h1:xpcJRLb0r/rnEns0DIKYYv+WjYCduHsrkT7/EB5XEv4= 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= @@ -256,9 +257,12 @@ google.golang.org/grpc v1.19.0/go.mod h1:mqu4LbDTu4XGKhr4mRzUsmM4RtVoemTSY81AxZi gopkg.in/alecthomas/kingpin.v2 v2.2.6/go.mod h1:FMv+mEhP44yOT+4EoQTLFTRgOQ1FBLkstjWtayDeSgw= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405 h1:yhCVgyC4o1eVCa2tZl7eS0r+SDo693bJlVdllGtEeKM= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= +gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33q108Sa+fhmuc+sWQYwY= 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/fsnotify.v1 v1.4.7/go.mod h1:Tz8NjZHkW78fSQdbUxIjBTcgA1z1m8ZHf0WmKUhAMys= +gopkg.in/go-playground/assert.v1 v1.2.1 h1:xoYuJVE7KT85PYWrN730RguIQO0ePzVRfFMXadIrXTM= +gopkg.in/go-playground/assert.v1 v1.2.1/go.mod h1:9RXL0bg/zibRAgZUYszZSwO/z8Y/a8bDuhia5mkpMnE= gopkg.in/go-playground/validator.v8 v8.18.2 h1:lFB4DoMU6B626w8ny76MV7VX6W2VHct2GVOI3xgiMrQ= gopkg.in/go-playground/validator.v8 v8.18.2/go.mod h1:RX2a/7Ha8BgOhfk7j780h4/u/RRjR0eouCJSH80/M2Y= gopkg.in/gormigrate.v1 v1.6.0 h1:XpYM6RHQPmzwY7Uyu+t+xxMXc86JYFJn4nEc9HzQjsI= From b81512cc85d473e6d9b29b5893be8ab61339cfc4 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:35:03 +0300 Subject: [PATCH 09/14] badges, vendoring --- .travis.yml | 1 + README.md | 3 ++- go.sum | 5 ----- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70763bf..d4d27e0 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,6 +1,7 @@ language: go env: - GO111MODULE=on + - GOFLAGS='-mod vendor' go: - '1.11' - '1.12' diff --git a/README.md b/README.md index d283560..9388698 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,6 @@ ## MG Transport Library - +[![Build Status](https://travis-ci.org/Neur0toxine/mg-transport-core.svg?branch=master)](https://travis-ci.org/Neur0toxine/mg-transport-core) +[![codecov](https://codecov.io/gh/Neur0toxine/mg-transport-core/branch/master/graph/badge.svg)](https://codecov.io/gh/Neur0toxine/mg-transport-core) This library provides different functions like error-reporting, logging, localization, etc. in order to make it easier to create transports. Usage: ```go diff --git a/go.sum b/go.sum index c4b4ba9..4f8c5a8 100644 --- a/go.sum +++ b/go.sum @@ -183,11 +183,6 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= -github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= -github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= -github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= -github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= -github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From 884cb5381555367e773c25aa86aed15dd1a9504e Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:37:16 +0300 Subject: [PATCH 10/14] remove vendoring - it's not necessary for project --- .travis.yml | 1 - go.mod | 2 +- go.sum | 3 +++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index d4d27e0..70763bf 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,7 +1,6 @@ language: go env: - GO111MODULE=on - - GOFLAGS='-mod vendor' go: - '1.11' - '1.12' diff --git a/go.mod b/go.mod index 279832e..ca9bb23 100644 --- a/go.mod +++ b/go.mod @@ -28,7 +28,7 @@ require ( github.com/retailcrm/api-client-go v1.1.1 github.com/retailcrm/mg-transport-api-client-go v1.1.31 github.com/stretchr/testify v1.4.0 - github.com/ugorji/go/codec v1.1.7 // indirect + github.com/ugorji/go v1.1.7 // indirect golang.org/x/net v0.0.0-20190813141303-74dc4d7220e7 // indirect golang.org/x/text v0.3.1-0.20180807135948-17ff2d5776d2 gopkg.in/go-playground/assert.v1 v1.2.1 // indirect diff --git a/go.sum b/go.sum index 4f8c5a8..c150edd 100644 --- a/go.sum +++ b/go.sum @@ -183,6 +183,9 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= +github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4= From 318d8375ce0e6fd0c5a2c3f8438d7d348b00f67b Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 14:41:05 +0300 Subject: [PATCH 11/14] use go 1.12 as latest version - forced by gorm --- .travis.yml | 1 - go.mod | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index 70763bf..12de6d3 100644 --- a/.travis.yml +++ b/.travis.yml @@ -2,7 +2,6 @@ language: go env: - GO111MODULE=on go: - - '1.11' - '1.12' - '1.13' before_install: diff --git a/go.mod b/go.mod index ca9bb23..ed243d0 100644 --- a/go.mod +++ b/go.mod @@ -1,6 +1,6 @@ module github.com/retailcrm/mg-transport-core -go 1.11 +go 1.12 require ( github.com/DATA-DOG/go-sqlmock v1.3.3 From 8f189ad14dff15423d760df33ae33e43265d25c9 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 15:26:08 +0300 Subject: [PATCH 12/14] fix for sentry error message, coverage --- core/sentry.go | 2 +- core/sentry_test.go | 87 +++++++++++++++++++++++++++++++++++++++++++-- go.sum | 2 ++ 3 files changed, 88 insertions(+), 3 deletions(-) diff --git a/core/sentry.go b/core/sentry.go index 763ef73..e346552 100644 --- a/core/sentry.go +++ b/core/sentry.go @@ -272,7 +272,7 @@ func (t *SentryTaggedStruct) GetProperty(v interface{}, property string) (name s } if val.Kind() != reflect.Struct { - err = fmt.Errorf("passed value must be struct, %s provided", val.String()) + err = fmt.Errorf("passed value must be struct, %s provided", val.Type().String()) return } diff --git a/core/sentry_test.go b/core/sentry_test.go index c263168..5f197e1 100644 --- a/core/sentry_test.go +++ b/core/sentry_test.go @@ -32,6 +32,7 @@ func (s *SentryTest) SetupTest() { require.Equal(s.T(), "", s.structTags.GetName()) require.Equal(s.T(), "Scalar", s.scalarTags.GetName()) s.structTags.Tags = map[string]string{} + s.sentry = NewSentry("dsn", "unknown_error", SentryTaggedTypes{}, nil, nil) } func (s *SentryTest) TestStruct_AddTag() { @@ -62,9 +63,9 @@ func (s *SentryTest) TestStruct_GetProperty_InvalidStruct() { } func (s *SentryTest) TestStruct_GetProperty_GotScalar() { - _, _, err := s.structTags.GetProperty("str", "Field") + _, _, err := s.structTags.GetProperty("", "Field") require.Error(s.T(), err) - assert.Equal(s.T(), "passed value must be struct, str provided", err.Error()) + assert.Equal(s.T(), "passed value must be struct, string provided", err.Error()) } func (s *SentryTest) TestStruct_GetProperty_InvalidType() { @@ -86,6 +87,88 @@ func (s *SentryTest) TestStruct_GetProperty_InvalidProperty() { assert.Equal(s.T(), "invalid property, got ", err.Error()) } +func (s *SentryTest) TestStruct_BuildTags_Fail() { + s.structTags.Tags = map[string]string{} + s.structTags.AddTag("test", "Field") + _, err := s.structTags.BuildTags(false) + assert.Error(s.T(), err) +} + +func (s *SentryTest) TestStruct_BuildTags() { + s.structTags.Tags = map[string]string{} + s.structTags.AddTag("test", "Field") + tags, err := s.structTags.BuildTags(SampleStruct{Field: "value"}) + + require.NoError(s.T(), err) + require.NotEmpty(s.T(), tags) + i, ok := tags["test"] + require.True(s.T(), ok) + assert.Equal(s.T(), "value", i) +} + +func (s *SentryTest) TestScalar_Get_Nil() { + _, err := s.scalarTags.Get(nil) + require.Error(s.T(), err) + assert.Equal(s.T(), "invalid value provided", err.Error()) +} + +func (s *SentryTest) TestScalar_Get_Struct() { + _, err := s.scalarTags.Get(struct{}{}) + require.Error(s.T(), err) + assert.Equal(s.T(), "passed value must not be struct", err.Error()) +} + +func (s *SentryTest) TestScalar_Get_InvalidType() { + _, err := s.scalarTags.Get(false) + require.Error(s.T(), err) + assert.Equal(s.T(), "passed value should be of type `string`, got `bool` instead", err.Error()) +} + +func (s *SentryTest) TestScalar_Get() { + val, err := s.scalarTags.Get("test") + require.NoError(s.T(), err) + assert.Equal(s.T(), "test", val) +} + +func (s *SentryTest) TestScalar_GetTags() { + assert.Empty(s.T(), s.scalarTags.GetTags()) +} + +func (s *SentryTest) TestScalar_BuildTags_Fail() { + _, err := s.scalarTags.BuildTags(false) + assert.Error(s.T(), err) +} + +func (s *SentryTest) TestScalar_BuildTags() { + tags, err := s.scalarTags.BuildTags("test") + + require.NoError(s.T(), err) + require.NotEmpty(s.T(), tags) + i, ok := tags[s.scalarTags.GetName()] + require.True(s.T(), ok) + assert.Equal(s.T(), "test", i) +} + +func (s *SentryTest) TestSentry_ErrorMiddleware() { + assert.NotNil(s.T(), s.sentry.ErrorMiddleware()) +} + +func (s *SentryTest) TestSentry_PanicLogger() { + assert.NotNil(s.T(), s.sentry.PanicLogger()) +} + +func (s *SentryTest) TestSentry_ErrorLogger() { + assert.NotNil(s.T(), s.sentry.ErrorLogger()) +} + +func (s *SentryTest) TestSentry_ErrorResponseHandler() { + assert.NotNil(s.T(), s.sentry.ErrorResponseHandler()) +} + +func (s *SentryTest) TestSentry_ErrorCaptureHandler() { + assert.NotNil(s.T(), s.sentry.ErrorCaptureHandler()) +} + func TestSentry_newRavenStackTrace_Fail(t *testing.T) { defer func() { assert.NotNil(t, recover()) diff --git a/go.sum b/go.sum index c150edd..c4b4ba9 100644 --- a/go.sum +++ b/go.sum @@ -183,8 +183,10 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.4.0 h1:2E4SXV/wtOkTonXsotYi4li6zVWxYlZuYNCXe9XRJyk= github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4= +github.com/ugorji/go v1.1.7 h1:/68gy2h+1mWMrwZFeD1kQialdSzAb432dtpeJ42ovdo= github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw= github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0= +github.com/ugorji/go/codec v1.1.7 h1:2SvQaVZ1ouYrrKKwoSk2pzd4A9evlKJb9oTL+OaLUSs= github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY= github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q= go.opencensus.io v0.20.1/go.mod h1:6WKK9ahsWS3RSO+PY9ZHZUfv2irvY6gN279GOPZjmmk= From 45ad97dbc4913bf11e580cf846157ef136b3c222 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 15:40:47 +0300 Subject: [PATCH 13/14] badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index 9388698..a5497cb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## MG Transport Library -[![Build Status](https://travis-ci.org/Neur0toxine/mg-transport-core.svg?branch=master)](https://travis-ci.org/Neur0toxine/mg-transport-core) -[![codecov](https://codecov.io/gh/Neur0toxine/mg-transport-core/branch/master/graph/badge.svg)](https://codecov.io/gh/Neur0toxine/mg-transport-core) +[![Build Status](https://travis-ci.org/retailcrm/mg-transport-core.svg?branch=master)](https://travis-ci.org/Neur0toxine/mg-transport-core) +[![codecov](https://codecov.io/gh/retailcrm/mg-transport-core/branch/master/graph/badge.svg)](https://codecov.io/gh/Neur0toxine/mg-transport-core) This library provides different functions like error-reporting, logging, localization, etc. in order to make it easier to create transports. Usage: ```go From 295843a85bb4a97c81be7667befe42a02fd267d8 Mon Sep 17 00:00:00 2001 From: Pavel Date: Thu, 19 Sep 2019 15:41:56 +0300 Subject: [PATCH 14/14] fix for badges --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index a5497cb..4de698a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ ## MG Transport Library -[![Build Status](https://travis-ci.org/retailcrm/mg-transport-core.svg?branch=master)](https://travis-ci.org/Neur0toxine/mg-transport-core) -[![codecov](https://codecov.io/gh/retailcrm/mg-transport-core/branch/master/graph/badge.svg)](https://codecov.io/gh/Neur0toxine/mg-transport-core) +[![Build Status](https://travis-ci.org/retailcrm/mg-transport-core.svg?branch=master)](https://travis-ci.org/retailcrm/mg-transport-core) +[![codecov](https://codecov.io/gh/retailcrm/mg-transport-core/branch/master/graph/badge.svg)](https://codecov.io/gh/retailcrm/mg-transport-core) This library provides different functions like error-reporting, logging, localization, etc. in order to make it easier to create transports. Usage: ```go