From b8816f910a7aed33b4aa37614b915d3d278c1767 Mon Sep 17 00:00:00 2001 From: Thomas von Dein Date: Mon, 20 Mar 2023 14:34:39 +0100 Subject: [PATCH] fix mod name, added tests --- README.md | 1 + upctl/Makefile | 3 +- upctl/cfg/config.go | 10 ++- upctl/cmd/delete.go | 4 +- upctl/cmd/describe.go | 4 +- upctl/cmd/download.go | 4 +- upctl/cmd/list.go | 4 +- upctl/cmd/root.go | 3 +- upctl/cmd/upload.go | 4 +- upctl/go.mod | 3 +- upctl/go.sum | 3 + upctl/lib/client.go | 24 ++++--- upctl/lib/client_test.go | 137 +++++++++++++++++++++++++++++++++++++++ upctl/main.go | 2 +- upctl/t/t1 | 1 + 15 files changed, 182 insertions(+), 25 deletions(-) create mode 100644 upctl/lib/client_test.go create mode 100644 upctl/t/t1 diff --git a/README.md b/README.md index e951d43..62e4bb8 100644 --- a/README.md +++ b/README.md @@ -193,6 +193,7 @@ The `endpoint` is the **Cenophane** server running somewhere and the - upd: https://docs.gofiber.io/guide/error-handling/ to always use json output - upctl: get rid of HandleResponse(), used only once anyway - add form so that public users can upload +- use Writer for output.go so we can unit test the stuff in there diff --git a/upctl/Makefile b/upctl/Makefile index 8c45681..dbadb30 100644 --- a/upctl/Makefile +++ b/upctl/Makefile @@ -33,7 +33,7 @@ all: buildlocal buildlocal: - go build -ldflags "-X 'github.com/tlinden/up/upctl/cfg.VERSION=$(VERSION)'" + go build -ldflags "-X 'github.com/tlinden/cenophane/upctl/cfg.VERSION=$(VERSION)'" release: ./mkrel.sh $(tool) $(version) @@ -48,7 +48,6 @@ clean: test: go test -v ./... - bash t/test.sh singletest: @echo "Call like this: ''make singletest TEST=TestX1 MOD=lib" diff --git a/upctl/cfg/config.go b/upctl/cfg/config.go index 3115293..85cf230 100644 --- a/upctl/cfg/config.go +++ b/upctl/cfg/config.go @@ -30,13 +30,19 @@ type Config struct { Endpoint string Debug bool Retries int - Apikey string + Silent bool + + // used for authentication + Apikey string // upload Expire string - // list + // used for filtering (list command) Apicontext string + + // required to intercept requests using httpmock in tests + Mock bool } func Getversion() string { diff --git a/upctl/cmd/delete.go b/upctl/cmd/delete.go index 53e067c..74d079d 100644 --- a/upctl/cmd/delete.go +++ b/upctl/cmd/delete.go @@ -19,8 +19,8 @@ package cmd import ( "errors" "github.com/spf13/cobra" - "github.com/tlinden/up/upctl/cfg" - "github.com/tlinden/up/upctl/lib" + "github.com/tlinden/cenophane/upctl/cfg" + "github.com/tlinden/cenophane/upctl/lib" ) func DeleteCommand(conf *cfg.Config) *cobra.Command { diff --git a/upctl/cmd/describe.go b/upctl/cmd/describe.go index 70858da..f38a1a7 100644 --- a/upctl/cmd/describe.go +++ b/upctl/cmd/describe.go @@ -19,8 +19,8 @@ package cmd import ( "errors" "github.com/spf13/cobra" - "github.com/tlinden/up/upctl/cfg" - "github.com/tlinden/up/upctl/lib" + "github.com/tlinden/cenophane/upctl/cfg" + "github.com/tlinden/cenophane/upctl/lib" ) func DescribeCommand(conf *cfg.Config) *cobra.Command { diff --git a/upctl/cmd/download.go b/upctl/cmd/download.go index f322011..ed12624 100644 --- a/upctl/cmd/download.go +++ b/upctl/cmd/download.go @@ -19,8 +19,8 @@ package cmd import ( "errors" "github.com/spf13/cobra" - "github.com/tlinden/up/upctl/cfg" - "github.com/tlinden/up/upctl/lib" + "github.com/tlinden/cenophane/upctl/cfg" + "github.com/tlinden/cenophane/upctl/lib" ) func DownloadCommand(conf *cfg.Config) *cobra.Command { diff --git a/upctl/cmd/list.go b/upctl/cmd/list.go index d141196..4d9ac65 100644 --- a/upctl/cmd/list.go +++ b/upctl/cmd/list.go @@ -18,8 +18,8 @@ package cmd import ( "github.com/spf13/cobra" - "github.com/tlinden/up/upctl/cfg" - "github.com/tlinden/up/upctl/lib" + "github.com/tlinden/cenophane/upctl/cfg" + "github.com/tlinden/cenophane/upctl/lib" ) func ListCommand(conf *cfg.Config) *cobra.Command { diff --git a/upctl/cmd/root.go b/upctl/cmd/root.go index 1fcf178..d1f953d 100644 --- a/upctl/cmd/root.go +++ b/upctl/cmd/root.go @@ -22,7 +22,7 @@ import ( "github.com/spf13/cobra" "github.com/spf13/pflag" "github.com/spf13/viper" - "github.com/tlinden/up/upctl/cfg" + "github.com/tlinden/cenophane/upctl/cfg" "os" "strings" ) @@ -81,6 +81,7 @@ func Execute() { // options rootCmd.PersistentFlags().BoolVarP(&ShowVersion, "version", "v", false, "Print program version") rootCmd.PersistentFlags().BoolVarP(&conf.Debug, "debug", "d", false, "Enable debugging") + rootCmd.PersistentFlags().BoolVarP(&conf.Silent, "silent", "s", false, "Disable progress bar and other noise") rootCmd.PersistentFlags().StringVarP(&cfgFile, "config", "c", "", "custom config file") rootCmd.PersistentFlags().IntVarP(&conf.Retries, "retries", "r", 3, "How often shall we retry to access our endpoint") rootCmd.PersistentFlags().StringVarP(&conf.Endpoint, "endpoint", "p", "http://localhost:8080/api/v1", "upload api endpoint url") diff --git a/upctl/cmd/upload.go b/upctl/cmd/upload.go index 79cb168..a271692 100644 --- a/upctl/cmd/upload.go +++ b/upctl/cmd/upload.go @@ -19,8 +19,8 @@ package cmd import ( "errors" "github.com/spf13/cobra" - "github.com/tlinden/up/upctl/cfg" - "github.com/tlinden/up/upctl/lib" + "github.com/tlinden/cenophane/upctl/cfg" + "github.com/tlinden/cenophane/upctl/lib" ) func UploadCommand(conf *cfg.Config) *cobra.Command { diff --git a/upctl/go.mod b/upctl/go.mod index 154e9f3..6b4ff8d 100644 --- a/upctl/go.mod +++ b/upctl/go.mod @@ -1,9 +1,10 @@ -module github.com/tlinden/up/upctl +module github.com/tlinden/cenophane/upctl go 1.18 require ( github.com/imroc/req/v3 v3.32.0 + github.com/jarcoal/httpmock v1.3.0 github.com/olekukonko/tablewriter v0.0.5 github.com/schollz/progressbar/v3 v3.13.1 github.com/spf13/cobra v1.6.1 diff --git a/upctl/go.sum b/upctl/go.sum index d07f735..d75a6e1 100644 --- a/upctl/go.sum +++ b/upctl/go.sum @@ -139,6 +139,8 @@ github.com/imroc/req/v3 v3.32.0 h1:jDGm2pVE8e/PExrJTvxEjOmgItVBJqvt3YjTUtZKyQM= github.com/imroc/req/v3 v3.32.0/go.mod h1:cZ+7C3L/AYOr4tLGG16hZF90F1WzAdAdzt1xFSlizXY= github.com/inconshreveable/mousetrap v1.0.1 h1:U3uMjPSQEBMNp1lFxmllqCPM6P5u/Xq7Pgzkat/bFNc= github.com/inconshreveable/mousetrap v1.0.1/go.mod h1:vpF70FUmC8bwa3OWnCshd2FqLfsEA9PFc4w1p2J65bw= +github.com/jarcoal/httpmock v1.3.0 h1:2RJ8GP0IIaWwcC9Fp2BmVi8Kog3v2Hn7VXM3fTd+nuc= +github.com/jarcoal/httpmock v1.3.0/go.mod h1:3yb8rc4BI7TCBhFY8ng0gjuLKJNquuDNiPaZjnENuYg= github.com/jstemmer/go-junit-report v0.0.0-20190106144839-af01ea7f8024/go.mod h1:6v2b51hI/fHJwM22ozAgKL4VKDeJcHhJFhtBdhmNjmU= github.com/jstemmer/go-junit-report v0.9.1/go.mod h1:Brl9GWCQeLvo8nXZwPNNblvFj/XSXhF0NWZEnDohbsk= github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213/go.mod h1:vNUNkEQ1e29fT/6vq2aBdFsgNPmy8qMdSay1npru+Sw= @@ -155,6 +157,7 @@ github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/ github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= github.com/mattn/go-runewidth v0.0.14 h1:+xnbZSEeDbOIg5/mE6JF0w6n9duR1l3/WmbinWVwUuU= github.com/mattn/go-runewidth v0.0.14/go.mod h1:Jdepj2loyihRzMpdS35Xk/zdY8IAYHsh153qUoGf23w= +github.com/maxatome/go-testdeep v1.12.0 h1:Ql7Go8Tg0C1D/uMMX59LAoYK7LffeJQ6X2T04nTH68g= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db h1:62I3jR2EmQ4l5rM/4FEfDWcRD+abF5XlKShorW5LRoQ= github.com/mitchellh/colorstring v0.0.0-20190213212951-d06e56a500db/go.mod h1:l0dey0ia/Uv7NcFFVbCLtqEBQbrT4OCwCSKTEv6enCw= github.com/mitchellh/mapstructure v1.5.0 h1:jeMsZIYE/09sWLaz43PL7Gy6RuMjD2eJVyuac5Z2hdY= diff --git a/upctl/lib/client.go b/upctl/lib/client.go index 004addc..b8befac 100644 --- a/upctl/lib/client.go +++ b/upctl/lib/client.go @@ -23,9 +23,10 @@ import ( "fmt" //"github.com/alecthomas/repr" "github.com/imroc/req/v3" + "github.com/jarcoal/httpmock" "github.com/schollz/progressbar/v3" "github.com/tlinden/cenophane/common" - "github.com/tlinden/up/upctl/cfg" + "github.com/tlinden/cenophane/upctl/cfg" "mime" "os" "path/filepath" @@ -79,6 +80,11 @@ func Setup(c *cfg.Config, path string) *Request { client.SetCommonBearerAuthToken(c.Apikey) } + if c.Mock { + // intercept, used by unit tests + httpmock.ActivateNonDefault(client.GetClient()) + } + return &Request{Url: c.Endpoint + path, R: R} } @@ -123,19 +129,21 @@ func UploadFiles(c *cfg.Config, args []string) error { return err } - // progres bar - bar := progressbar.Default(100) - var left float64 + if !c.Silent { + // progres bar + bar := progressbar.Default(100) + var left float64 + rq.R.SetUploadCallbackWithInterval(func(info req.UploadInfo) { + left = float64(info.UploadedSize) / float64(info.FileSize) * 100.0 + bar.Add(int(left)) + }, 10*time.Millisecond) + } // actual post w/ settings resp, err := rq.R. SetFormData(map[string]string{ "expire": c.Expire, }). - SetUploadCallbackWithInterval(func(info req.UploadInfo) { - left = float64(info.UploadedSize) / float64(info.FileSize) * 100.0 - bar.Add(int(left)) - }, 10*time.Millisecond). Post(rq.Url) if err != nil { diff --git a/upctl/lib/client_test.go b/upctl/lib/client_test.go new file mode 100644 index 0000000..578f38e --- /dev/null +++ b/upctl/lib/client_test.go @@ -0,0 +1,137 @@ +/* +Copyright © 2023 Thomas von Dein + +This program is free software: you can redistribute it and/or modify +it under the terms of the GNU General Public License as published by +the Free Software Foundation, either version 3 of the License, or +(at your option) any later version. + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License for more details. + +You should have received a copy of the GNU General Public License +along with this program. If not, see . +*/ + +package lib + +import ( + //"github.com/alecthomas/repr" + "fmt" + "github.com/jarcoal/httpmock" + "github.com/tlinden/cenophane/upctl/cfg" + "net/http" + "testing" +) + +const endpoint string = "http://localhost:8080/api/v1" + +type Unit struct { + name string + apikey string // set to something else than "token" to fail auth + wantfail bool // true: expect to fail + files []string // path relative to ./t/ + sendcode int // for httpmock + sendjson string // struct to respond with + route string // dito + method string // method to use +} + +// simulate our cenophane server +func Intercept(tt Unit) { + httpmock.RegisterResponder(tt.method, endpoint+tt.route, + func(request *http.Request) (*http.Response, error) { + respbody := fmt.Sprintf(tt.sendjson) + resp := httpmock.NewStringResponse(tt.sendcode, respbody) + resp.Header.Set("Content-Type", "application/json; charset=utf-8") + return resp, nil + }) +} + +func TestUploadFiles(t *testing.T) { + conf := &cfg.Config{ + Mock: true, + Apikey: "token", + Endpoint: endpoint, + Silent: true, + } + + tests := []Unit{ + { + name: "upload-file", + apikey: "token", + wantfail: false, + route: "/file/", + sendcode: 200, + sendjson: `{"success": true}`, + files: []string{"../t/t1"}, // pwd is lib/ ! + method: "POST", + }, + { + name: "upload-nonexistent-file", + apikey: "token", + wantfail: true, + route: "/file/", + sendcode: 200, + sendjson: `{"success": false}`, + files: []string{"../t/none"}, + method: "POST", + }, + { + name: "upload-unauth", + apikey: "token", + wantfail: true, + route: "/file/", + sendcode: 403, + sendjson: `{"success": false}`, + files: []string{"../t/t1"}, + method: "POST", + }, + } + + for _, tt := range tests { + testname := fmt.Sprintf("UploadFiles-%s-%t", tt.name, tt.wantfail) + Intercept(tt) + err := UploadFiles(conf, tt.files) + + if err != nil && !tt.wantfail { + t.Errorf("%s failed! wantfail: %t, error: %s", testname, tt.wantfail, err.Error()) + } + } +} + +func TestList(t *testing.T) { + conf := &cfg.Config{ + Mock: true, + Apikey: "token", + Endpoint: endpoint, + Silent: true, + } + + listing := `{"uploads":[{"id":"c8dh","expire":"asap","file":"t1","members":["t1"],"uploaded":1679318969.6434112,"context":"foo","url":""}],"success":true,"message":"","code":200}` + tests := []Unit{ + { + name: "list", + apikey: "token", + wantfail: false, + route: "/list/", + sendcode: 200, + sendjson: listing, + files: []string{}, + method: "GET", + }, + } + + for _, tt := range tests { + testname := fmt.Sprintf("List-%s-%t", tt.name, tt.wantfail) + Intercept(tt) + err := List(conf, []string{}) + + if err != nil && !tt.wantfail { + t.Errorf("%s failed! wantfail: %t, error: %s", testname, tt.wantfail, err.Error()) + } + } + +} diff --git a/upctl/main.go b/upctl/main.go index 1552c1b..c11a498 100644 --- a/upctl/main.go +++ b/upctl/main.go @@ -18,7 +18,7 @@ along with this program. If not, see . package main import ( - "github.com/tlinden/up/upctl/cmd" + "github.com/tlinden/cenophane/upctl/cmd" ) func main() { diff --git a/upctl/t/t1 b/upctl/t/t1 new file mode 100644 index 0000000..7c0bf85 --- /dev/null +++ b/upctl/t/t1 @@ -0,0 +1 @@ +Mon Mar 20 12:16:26 PM CET 2023