mirror of
https://codeberg.org/scip/ephemerup.git
synced 2025-12-18 13:01:13 +01:00
some changes:
- added unit tests
- put all subcmds into one file
- use io.Writer for output, better for testing
This commit is contained in:
59
api/db_test.go
Normal file
59
api/db_test.go
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"github.com/tlinden/cenophane/cfg"
|
||||||
|
"os"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func finalize(db *Db) {
|
||||||
|
if db.bolt != nil {
|
||||||
|
db.Close()
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(db.cfg.DbFile); err == nil {
|
||||||
|
os.Remove(db.cfg.DbFile)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestNew(t *testing.T) {
|
||||||
|
var tests = []struct {
|
||||||
|
name string
|
||||||
|
file string
|
||||||
|
wantfail bool
|
||||||
|
}{
|
||||||
|
{"opennew", "test.db", false},
|
||||||
|
{"openfail", "/hopefully/not/existing/directory/test.db", true},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, tt := range tests {
|
||||||
|
c := &cfg.Config{DbFile: tt.file}
|
||||||
|
t.Run(tt.name, func(t *testing.T) {
|
||||||
|
db, err := NewDb(c)
|
||||||
|
defer finalize(db)
|
||||||
|
if err != nil && !tt.wantfail {
|
||||||
|
t.Errorf("expected: &Db{}, got err: " + err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if err == nil && tt.wantfail {
|
||||||
|
t.Errorf("expected: fail, got &Db{}")
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
|
||||||
"github.com/tlinden/cenophane/upctl/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DeleteCommand(conf *cfg.Config) *cobra.Command {
|
|
||||||
var deleteCmd = &cobra.Command{
|
|
||||||
Use: "delete [options] <id>",
|
|
||||||
Short: "Delete an upload",
|
|
||||||
Long: `Delete an upload identified by its id`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return errors.New("No id specified to delete!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// errors at this stage do not cause the usage to be shown
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
|
|
||||||
return lib.Delete(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
deleteCmd.Aliases = append(deleteCmd.Aliases, "rm")
|
|
||||||
deleteCmd.Aliases = append(deleteCmd.Aliases, "d")
|
|
||||||
|
|
||||||
return deleteCmd
|
|
||||||
}
|
|
||||||
@@ -1,48 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
|
||||||
"github.com/tlinden/cenophane/upctl/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DescribeCommand(conf *cfg.Config) *cobra.Command {
|
|
||||||
var listCmd = &cobra.Command{
|
|
||||||
Use: "describe [options] upload-id",
|
|
||||||
Long: "Show detailed informations about an upload object.",
|
|
||||||
Short: `Describe an upload.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return errors.New("No id specified to delete!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// errors at this stage do not cause the usage to be shown
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
|
|
||||||
return lib.Describe(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "des")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "info")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "i")
|
|
||||||
|
|
||||||
return listCmd
|
|
||||||
}
|
|
||||||
@@ -1,49 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
|
||||||
"github.com/tlinden/cenophane/upctl/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func DownloadCommand(conf *cfg.Config) *cobra.Command {
|
|
||||||
var listCmd = &cobra.Command{
|
|
||||||
Use: "download [options] upload-id",
|
|
||||||
Long: "Download the file associated with an upload object.",
|
|
||||||
Short: `Download a file.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return errors.New("No id specified to delete!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// errors at this stage do not cause the usage to be shown
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
|
|
||||||
return lib.Download(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "down")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "get")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "g")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "fetch")
|
|
||||||
|
|
||||||
return listCmd
|
|
||||||
}
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
|
||||||
"github.com/tlinden/cenophane/upctl/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func ListCommand(conf *cfg.Config) *cobra.Command {
|
|
||||||
var listCmd = &cobra.Command{
|
|
||||||
Use: "list [options] [file ..]",
|
|
||||||
Short: "List uploads",
|
|
||||||
Long: `List uploads.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
// errors at this stage do not cause the usage to be shown
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
|
|
||||||
return lib.List(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// options
|
|
||||||
listCmd.PersistentFlags().StringVarP(&conf.Apicontext, "apicontext", "", "", "Filter by given API context")
|
|
||||||
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "ls")
|
|
||||||
listCmd.Aliases = append(listCmd.Aliases, "l")
|
|
||||||
|
|
||||||
return listCmd
|
|
||||||
}
|
|
||||||
145
upctl/cmd/subcommands.go
Normal file
145
upctl/cmd/subcommands.go
Normal file
@@ -0,0 +1,145 @@
|
|||||||
|
/*
|
||||||
|
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 <http://www.gnu.org/licenses/>.
|
||||||
|
*/
|
||||||
|
package cmd
|
||||||
|
|
||||||
|
import (
|
||||||
|
"errors"
|
||||||
|
"github.com/spf13/cobra"
|
||||||
|
"github.com/tlinden/cenophane/upctl/cfg"
|
||||||
|
"github.com/tlinden/cenophane/upctl/lib"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
|
func UploadCommand(conf *cfg.Config) *cobra.Command {
|
||||||
|
var uploadCmd = &cobra.Command{
|
||||||
|
Use: "upload [options] [file ..]",
|
||||||
|
Short: "Upload files",
|
||||||
|
Long: `Upload files to an upload api.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No files specified to upload!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// errors at this stage do not cause the usage to be shown
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
|
||||||
|
return lib.UploadFiles(os.Stdout, conf, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// options
|
||||||
|
uploadCmd.PersistentFlags().StringVarP(&conf.Expire, "expire", "e", "", "Expire setting: asap or duration (accepted shortcuts: dmh)")
|
||||||
|
|
||||||
|
uploadCmd.Aliases = append(uploadCmd.Aliases, "up")
|
||||||
|
uploadCmd.Aliases = append(uploadCmd.Aliases, "u")
|
||||||
|
|
||||||
|
return uploadCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func ListCommand(conf *cfg.Config) *cobra.Command {
|
||||||
|
var listCmd = &cobra.Command{
|
||||||
|
Use: "list [options] [file ..]",
|
||||||
|
Short: "List uploads",
|
||||||
|
Long: `List uploads.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
// errors at this stage do not cause the usage to be shown
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
|
||||||
|
return lib.List(os.Stdout, conf, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
// options
|
||||||
|
listCmd.PersistentFlags().StringVarP(&conf.Apicontext, "apicontext", "", "", "Filter by given API context")
|
||||||
|
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "ls")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "l")
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func DeleteCommand(conf *cfg.Config) *cobra.Command {
|
||||||
|
var deleteCmd = &cobra.Command{
|
||||||
|
Use: "delete [options] <id>",
|
||||||
|
Short: "Delete an upload",
|
||||||
|
Long: `Delete an upload identified by its id`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No id specified to delete!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// errors at this stage do not cause the usage to be shown
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
|
||||||
|
return lib.Delete(os.Stdout, conf, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
deleteCmd.Aliases = append(deleteCmd.Aliases, "rm")
|
||||||
|
deleteCmd.Aliases = append(deleteCmd.Aliases, "d")
|
||||||
|
|
||||||
|
return deleteCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func DescribeCommand(conf *cfg.Config) *cobra.Command {
|
||||||
|
var listCmd = &cobra.Command{
|
||||||
|
Use: "describe [options] upload-id",
|
||||||
|
Long: "Show detailed informations about an upload object.",
|
||||||
|
Short: `Describe an upload.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No id specified to delete!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// errors at this stage do not cause the usage to be shown
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
|
||||||
|
return lib.Describe(os.Stdout, conf, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "des")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "info")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "i")
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
}
|
||||||
|
|
||||||
|
func DownloadCommand(conf *cfg.Config) *cobra.Command {
|
||||||
|
var listCmd = &cobra.Command{
|
||||||
|
Use: "download [options] upload-id",
|
||||||
|
Long: "Download the file associated with an upload object.",
|
||||||
|
Short: `Download a file.`,
|
||||||
|
RunE: func(cmd *cobra.Command, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No id specified to delete!")
|
||||||
|
}
|
||||||
|
|
||||||
|
// errors at this stage do not cause the usage to be shown
|
||||||
|
cmd.SilenceUsage = true
|
||||||
|
|
||||||
|
return lib.Download(os.Stdout, conf, args)
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "down")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "get")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "g")
|
||||||
|
listCmd.Aliases = append(listCmd.Aliases, "fetch")
|
||||||
|
|
||||||
|
return listCmd
|
||||||
|
}
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/*
|
|
||||||
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 <http://www.gnu.org/licenses/>.
|
|
||||||
*/
|
|
||||||
package cmd
|
|
||||||
|
|
||||||
import (
|
|
||||||
"errors"
|
|
||||||
"github.com/spf13/cobra"
|
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
|
||||||
"github.com/tlinden/cenophane/upctl/lib"
|
|
||||||
)
|
|
||||||
|
|
||||||
func UploadCommand(conf *cfg.Config) *cobra.Command {
|
|
||||||
var uploadCmd = &cobra.Command{
|
|
||||||
Use: "upload [options] [file ..]",
|
|
||||||
Short: "Upload files",
|
|
||||||
Long: `Upload files to an upload api.`,
|
|
||||||
RunE: func(cmd *cobra.Command, args []string) error {
|
|
||||||
if len(args) == 0 {
|
|
||||||
return errors.New("No files specified to upload!")
|
|
||||||
}
|
|
||||||
|
|
||||||
// errors at this stage do not cause the usage to be shown
|
|
||||||
cmd.SilenceUsage = true
|
|
||||||
|
|
||||||
return lib.UploadFiles(conf, args)
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
// options
|
|
||||||
uploadCmd.PersistentFlags().StringVarP(&conf.Expire, "expire", "e", "", "Expire setting: asap or duration (accepted shortcuts: dmh)")
|
|
||||||
|
|
||||||
uploadCmd.Aliases = append(uploadCmd.Aliases, "up")
|
|
||||||
uploadCmd.Aliases = append(uploadCmd.Aliases, "u")
|
|
||||||
|
|
||||||
return uploadCmd
|
|
||||||
}
|
|
||||||
@@ -14,6 +14,7 @@ require (
|
|||||||
)
|
)
|
||||||
|
|
||||||
require (
|
require (
|
||||||
|
github.com/alecthomas/repr v0.2.0 // indirect
|
||||||
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
github.com/fsnotify/fsnotify v1.6.0 // indirect
|
||||||
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
github.com/go-task/slim-sprig v0.0.0-20210107165309-348f09dbbbc0 // indirect
|
||||||
github.com/golang/mock v1.6.0 // indirect
|
github.com/golang/mock v1.6.0 // indirect
|
||||||
|
|||||||
@@ -38,6 +38,8 @@ cloud.google.com/go/storage v1.14.0/go.mod h1:GrKmX003DSIwi9o29oFT7YDnHYwZoctc3f
|
|||||||
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU=
|
||||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||||
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
github.com/BurntSushi/xgb v0.0.0-20160522181843-27f122750802/go.mod h1:IVnqGOEym/WlBOVXweHU+Q+/VP0lqqI8lqeDx9IjBqo=
|
||||||
|
github.com/alecthomas/repr v0.2.0 h1:HAzS41CIzNW5syS8Mf9UwXhNH1J9aix/BvDRf1Ml2Yk=
|
||||||
|
github.com/alecthomas/repr v0.2.0/go.mod h1:Fr0507jx4eOXV7AlPV6AVZLYrLIuIeSOWtW57eE/O/4=
|
||||||
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU=
|
||||||
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI=
|
||||||
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI=
|
||||||
|
|||||||
@@ -27,6 +27,7 @@ import (
|
|||||||
"github.com/schollz/progressbar/v3"
|
"github.com/schollz/progressbar/v3"
|
||||||
"github.com/tlinden/cenophane/common"
|
"github.com/tlinden/cenophane/common"
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
"github.com/tlinden/cenophane/upctl/cfg"
|
||||||
|
"io"
|
||||||
"mime"
|
"mime"
|
||||||
"os"
|
"os"
|
||||||
"path/filepath"
|
"path/filepath"
|
||||||
@@ -51,6 +52,9 @@ type ListParams struct {
|
|||||||
|
|
||||||
const Maxwidth = 10
|
const Maxwidth = 10
|
||||||
|
|
||||||
|
/*
|
||||||
|
Create a new request object for outgoing queries
|
||||||
|
*/
|
||||||
func Setup(c *cfg.Config, path string) *Request {
|
func Setup(c *cfg.Config, path string) *Request {
|
||||||
client := req.C()
|
client := req.C()
|
||||||
if c.Debug {
|
if c.Debug {
|
||||||
@@ -86,9 +90,12 @@ func Setup(c *cfg.Config, path string) *Request {
|
|||||||
}
|
}
|
||||||
|
|
||||||
return &Request{Url: c.Endpoint + path, R: R}
|
return &Request{Url: c.Endpoint + path, R: R}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
Iterate over args, considering the elements are filenames, and add
|
||||||
|
them to the request.
|
||||||
|
*/
|
||||||
func GatherFiles(rq *Request, args []string) error {
|
func GatherFiles(rq *Request, args []string) error {
|
||||||
for _, file := range args {
|
for _, file := range args {
|
||||||
info, err := os.Stat(file)
|
info, err := os.Stat(file)
|
||||||
@@ -120,7 +127,42 @@ func GatherFiles(rq *Request, args []string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func UploadFiles(c *cfg.Config, args []string) error {
|
/*
|
||||||
|
Check HTTP Response Code and validate JSON status output, if
|
||||||
|
any. Turns'em into a regular error
|
||||||
|
*/
|
||||||
|
func HandleResponse(c *cfg.Config, resp *req.Response) error {
|
||||||
|
// we expect a json response, extract the error, if any
|
||||||
|
r := Response{}
|
||||||
|
|
||||||
|
if err := json.Unmarshal([]byte(resp.String()), &r); err != nil {
|
||||||
|
// text output!
|
||||||
|
r.Message = resp.String()
|
||||||
|
}
|
||||||
|
|
||||||
|
if c.Debug {
|
||||||
|
trace := resp.Request.TraceInfo()
|
||||||
|
fmt.Println(trace.Blame())
|
||||||
|
fmt.Println("----------")
|
||||||
|
fmt.Println(trace)
|
||||||
|
}
|
||||||
|
|
||||||
|
if !r.Success {
|
||||||
|
if len(r.Message) == 0 {
|
||||||
|
if resp.Err != nil {
|
||||||
|
return resp.Err
|
||||||
|
} else {
|
||||||
|
return errors.New("Unknown error")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
return errors.New(r.Message)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func UploadFiles(w io.Writer, c *cfg.Config, args []string) error {
|
||||||
// setup url, req.Request, timeout handling etc
|
// setup url, req.Request, timeout handling etc
|
||||||
rq := Setup(c, "/file/")
|
rq := Setup(c, "/file/")
|
||||||
|
|
||||||
@@ -150,46 +192,14 @@ func UploadFiles(c *cfg.Config, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return RespondExtended(resp)
|
if err := HandleResponse(c, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return RespondExtended(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func HandleResponse(c *cfg.Config, resp *req.Response) error {
|
func List(w io.Writer, c *cfg.Config, args []string) error {
|
||||||
// we expect a json response, extract the error, if any
|
|
||||||
r := Response{}
|
|
||||||
|
|
||||||
if err := json.Unmarshal([]byte(resp.String()), &r); err != nil {
|
|
||||||
// text output!
|
|
||||||
r.Message = resp.String()
|
|
||||||
}
|
|
||||||
|
|
||||||
if c.Debug {
|
|
||||||
trace := resp.Request.TraceInfo()
|
|
||||||
fmt.Println(trace.Blame())
|
|
||||||
fmt.Println("----------")
|
|
||||||
fmt.Println(trace)
|
|
||||||
}
|
|
||||||
|
|
||||||
if !r.Success {
|
|
||||||
if len(r.Message) == 0 {
|
|
||||||
if resp.Err != nil {
|
|
||||||
return resp.Err
|
|
||||||
} else {
|
|
||||||
return errors.New("Unknown error")
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
return errors.New(r.Message)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// all right
|
|
||||||
if r.Message != "" {
|
|
||||||
fmt.Println(r.Message)
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func List(c *cfg.Config, args []string) error {
|
|
||||||
rq := Setup(c, "/list/")
|
rq := Setup(c, "/list/")
|
||||||
|
|
||||||
params := &ListParams{Apicontext: c.Apicontext}
|
params := &ListParams{Apicontext: c.Apicontext}
|
||||||
@@ -201,10 +211,14 @@ func List(c *cfg.Config, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return RespondTable(resp)
|
if err := HandleResponse(c, resp); err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return RespondTable(w, resp)
|
||||||
}
|
}
|
||||||
|
|
||||||
func Delete(c *cfg.Config, args []string) error {
|
func Delete(w io.Writer, c *cfg.Config, args []string) error {
|
||||||
for _, id := range args {
|
for _, id := range args {
|
||||||
rq := Setup(c, "/file/"+id+"/")
|
rq := Setup(c, "/file/"+id+"/")
|
||||||
|
|
||||||
@@ -218,13 +232,17 @@ func Delete(c *cfg.Config, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("Upload %s successfully deleted.\n", id)
|
fmt.Fprintf(w, "Upload %s successfully deleted.\n", id)
|
||||||
}
|
}
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func Describe(c *cfg.Config, args []string) error {
|
func Describe(w io.Writer, c *cfg.Config, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No id provided!")
|
||||||
|
}
|
||||||
|
|
||||||
id := args[0] // we describe only 1 object
|
id := args[0] // we describe only 1 object
|
||||||
|
|
||||||
rq := Setup(c, "/upload/"+id+"/")
|
rq := Setup(c, "/upload/"+id+"/")
|
||||||
@@ -234,25 +252,37 @@ func Describe(c *cfg.Config, args []string) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
return RespondExtended(resp)
|
if err := HandleResponse(c, resp); err != nil {
|
||||||
}
|
return err
|
||||||
|
|
||||||
func Download(c *cfg.Config, args []string) error {
|
|
||||||
id := args[0]
|
|
||||||
|
|
||||||
// progres bar
|
|
||||||
bar := progressbar.Default(100)
|
|
||||||
|
|
||||||
callback := func(info req.DownloadInfo) {
|
|
||||||
if info.Response.Response != nil {
|
|
||||||
bar.Add(1)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return RespondExtended(w, resp)
|
||||||
|
}
|
||||||
|
|
||||||
|
func Download(w io.Writer, c *cfg.Config, args []string) error {
|
||||||
|
if len(args) == 0 {
|
||||||
|
return errors.New("No id provided!")
|
||||||
|
}
|
||||||
|
|
||||||
|
id := args[0]
|
||||||
|
|
||||||
rq := Setup(c, "/file/"+id+"/")
|
rq := Setup(c, "/file/"+id+"/")
|
||||||
|
|
||||||
|
if !c.Silent {
|
||||||
|
// progres bar
|
||||||
|
bar := progressbar.Default(100)
|
||||||
|
|
||||||
|
callback := func(info req.DownloadInfo) {
|
||||||
|
if info.Response.Response != nil {
|
||||||
|
bar.Add(1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rq.R.SetDownloadCallback(callback)
|
||||||
|
}
|
||||||
|
|
||||||
resp, err := rq.R.
|
resp, err := rq.R.
|
||||||
SetOutputFile(id).
|
SetOutputFile(id).
|
||||||
SetDownloadCallback(callback).
|
|
||||||
Get(rq.Url)
|
Get(rq.Url)
|
||||||
|
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@@ -278,7 +308,7 @@ func Download(c *cfg.Config, args []string) error {
|
|||||||
return fmt.Errorf("\nUnable to rename file: " + err.Error())
|
return fmt.Errorf("\nUnable to rename file: " + err.Error())
|
||||||
}
|
}
|
||||||
|
|
||||||
fmt.Printf("%s successfully downloaded to file %s.", id, cleanfilename)
|
fmt.Fprintf(w, "%s successfully downloaded to file %s.", id, cleanfilename)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -19,10 +19,17 @@ package lib
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
//"github.com/alecthomas/repr"
|
//"github.com/alecthomas/repr"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"github.com/jarcoal/httpmock"
|
"github.com/jarcoal/httpmock"
|
||||||
"github.com/tlinden/cenophane/upctl/cfg"
|
"github.com/tlinden/cenophane/upctl/cfg"
|
||||||
|
"io/ioutil"
|
||||||
"net/http"
|
"net/http"
|
||||||
|
"os"
|
||||||
|
"path/filepath"
|
||||||
|
"regexp"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -33,23 +40,64 @@ type Unit struct {
|
|||||||
apikey string // set to something else than "token" to fail auth
|
apikey string // set to something else than "token" to fail auth
|
||||||
wantfail bool // true: expect to fail
|
wantfail bool // true: expect to fail
|
||||||
files []string // path relative to ./t/
|
files []string // path relative to ./t/
|
||||||
sendcode int // for httpmock
|
expect string // regex used to parse the output
|
||||||
sendjson string // struct to respond with
|
|
||||||
route string // dito
|
sendcode int // for httpmock
|
||||||
method string // method to use
|
sendjson string // struct to respond with
|
||||||
|
sendfile string // bare file content to be sent
|
||||||
|
route string // dito
|
||||||
|
method string // method to use
|
||||||
}
|
}
|
||||||
|
|
||||||
// simulate our cenophane server
|
// simulate our cenophane server
|
||||||
func Intercept(tt Unit) {
|
func Intercept(tt Unit) {
|
||||||
httpmock.RegisterResponder(tt.method, endpoint+tt.route,
|
httpmock.RegisterResponder(tt.method, endpoint+tt.route,
|
||||||
func(request *http.Request) (*http.Response, error) {
|
func(request *http.Request) (*http.Response, error) {
|
||||||
respbody := fmt.Sprintf(tt.sendjson)
|
var resp *http.Response
|
||||||
resp := httpmock.NewStringResponse(tt.sendcode, respbody)
|
|
||||||
resp.Header.Set("Content-Type", "application/json; charset=utf-8")
|
if tt.sendfile != "" {
|
||||||
|
// simulate a file download
|
||||||
|
content, err := ioutil.ReadFile(tt.sendfile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // should not happen
|
||||||
|
}
|
||||||
|
|
||||||
|
stat, err := os.Stat(tt.sendfile)
|
||||||
|
if err != nil {
|
||||||
|
panic(err) // should not happen as well
|
||||||
|
}
|
||||||
|
|
||||||
|
resp = httpmock.NewStringResponse(tt.sendcode, string(content))
|
||||||
|
resp.Header.Set("Content-Type", "text/markdown; charset=utf-8")
|
||||||
|
resp.Header.Set("Content-Length", strconv.Itoa(int(stat.Size())))
|
||||||
|
resp.Header.Set("Content-Disposition", "attachment; filename='t1'")
|
||||||
|
} else {
|
||||||
|
// simulate JSON response
|
||||||
|
resp = httpmock.NewStringResponse(tt.sendcode, tt.sendjson)
|
||||||
|
resp.Header.Set("Content-Type", "application/json; charset=utf-8")
|
||||||
|
}
|
||||||
|
|
||||||
return resp, nil
|
return resp, nil
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// execute the actual test
|
||||||
|
func Check(t *testing.T, tt Unit, w *bytes.Buffer, err error) {
|
||||||
|
testname := fmt.Sprintf("%s-%t", tt.name, tt.wantfail)
|
||||||
|
|
||||||
|
if err != nil && !tt.wantfail {
|
||||||
|
t.Errorf("%s failed! wantfail: %t, error: %s", testname, tt.wantfail, err.Error())
|
||||||
|
}
|
||||||
|
|
||||||
|
if tt.expect != "" {
|
||||||
|
got := strings.TrimSpace(w.String())
|
||||||
|
r := regexp.MustCompile(tt.expect)
|
||||||
|
if !r.MatchString(got) {
|
||||||
|
t.Errorf("%s failed! error: output does not match!\nexpect: %s\ngot:\n%s", testname, tt.expect, got)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestUploadFiles(t *testing.T) {
|
func TestUploadFiles(t *testing.T) {
|
||||||
conf := &cfg.Config{
|
conf := &cfg.Config{
|
||||||
Mock: true,
|
Mock: true,
|
||||||
@@ -70,7 +118,17 @@ func TestUploadFiles(t *testing.T) {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "upload-nonexistent-file",
|
name: "upload-dir",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: false,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: `{"success": true}`,
|
||||||
|
files: []string{"../t"}, // pwd is lib/ !
|
||||||
|
method: "POST",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "upload-catch-nonexistent-file",
|
||||||
apikey: "token",
|
apikey: "token",
|
||||||
wantfail: true,
|
wantfail: true,
|
||||||
route: "/file/",
|
route: "/file/",
|
||||||
@@ -80,7 +138,7 @@ func TestUploadFiles(t *testing.T) {
|
|||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: "upload-unauth",
|
name: "upload-catch-no-access",
|
||||||
apikey: "token",
|
apikey: "token",
|
||||||
wantfail: true,
|
wantfail: true,
|
||||||
route: "/file/",
|
route: "/file/",
|
||||||
@@ -89,16 +147,31 @@ func TestUploadFiles(t *testing.T) {
|
|||||||
files: []string{"../t/t1"},
|
files: []string{"../t/t1"},
|
||||||
method: "POST",
|
method: "POST",
|
||||||
},
|
},
|
||||||
|
{
|
||||||
|
name: "upload-check-output",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: false,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: `{"uploads":[
|
||||||
|
{
|
||||||
|
"id":"cc2c965a","expire":"asap","file":"t1","members":["t1"],
|
||||||
|
"uploaded":1679396814.890502,"context":"foo","url":""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"success":true,
|
||||||
|
"message":"Download url: http://localhost:8080/download/cc2c965a/t1",
|
||||||
|
"code":200}`,
|
||||||
|
files: []string{"../t/t1"}, // pwd is lib/ !
|
||||||
|
method: "POST",
|
||||||
|
expect: "Expire: On first access",
|
||||||
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, unit := range tests {
|
||||||
testname := fmt.Sprintf("UploadFiles-%s-%t", tt.name, tt.wantfail)
|
var w bytes.Buffer
|
||||||
Intercept(tt)
|
Intercept(unit)
|
||||||
err := UploadFiles(conf, tt.files)
|
Check(t, unit, &w, UploadFiles(&w, conf, unit.files))
|
||||||
|
|
||||||
if err != nil && !tt.wantfail {
|
|
||||||
t.Errorf("%s failed! wantfail: %t, error: %s", testname, tt.wantfail, err.Error())
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -110,7 +183,18 @@ func TestList(t *testing.T) {
|
|||||||
Silent: true,
|
Silent: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
listing := `{"uploads":[{"id":"c8dh","expire":"asap","file":"t1","members":["t1"],"uploaded":1679318969.6434112,"context":"foo","url":""}],"success":true,"message":"","code":200}`
|
listing := `{"uploads":[
|
||||||
|
{
|
||||||
|
"id":"cc2c965a","expire":"asap","file":"t1","members":["t1"],
|
||||||
|
"uploaded":1679396814.890502,"context":"foo","url":""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"success":true,
|
||||||
|
"message":"",
|
||||||
|
"code":200}`
|
||||||
|
|
||||||
|
listingnoaccess := `{"success":false,"message":"invalid context","code":503}`
|
||||||
|
|
||||||
tests := []Unit{
|
tests := []Unit{
|
||||||
{
|
{
|
||||||
name: "list",
|
name: "list",
|
||||||
@@ -121,17 +205,205 @@ func TestList(t *testing.T) {
|
|||||||
sendjson: listing,
|
sendjson: listing,
|
||||||
files: []string{},
|
files: []string{},
|
||||||
method: "GET",
|
method: "GET",
|
||||||
|
expect: `cc2c965a\s*asap\s*foo\s*2023-03-21 12:06:54`, // expect tabular output
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list-catch-empty-json",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/list/",
|
||||||
|
sendcode: 404,
|
||||||
|
sendjson: "",
|
||||||
|
files: []string{},
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "list-catch-no-access",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/list/",
|
||||||
|
sendcode: 503,
|
||||||
|
sendjson: listingnoaccess,
|
||||||
|
files: []string{},
|
||||||
|
method: "GET",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for _, tt := range tests {
|
for _, unit := range tests {
|
||||||
testname := fmt.Sprintf("List-%s-%t", tt.name, tt.wantfail)
|
var w bytes.Buffer
|
||||||
Intercept(tt)
|
Intercept(unit)
|
||||||
err := List(conf, []string{})
|
Check(t, unit, &w, List(&w, conf, []string{}))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if err != nil && !tt.wantfail {
|
func TestDescribe(t *testing.T) {
|
||||||
t.Errorf("%s failed! wantfail: %t, error: %s", testname, tt.wantfail, err.Error())
|
conf := &cfg.Config{
|
||||||
}
|
Mock: true,
|
||||||
|
Apikey: "token",
|
||||||
|
Endpoint: endpoint,
|
||||||
|
Silent: true,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
listing := `{"uploads":[
|
||||||
|
{
|
||||||
|
"id":"cc2c965a","expire":"asap","file":"t1","members":["t1"],
|
||||||
|
"uploaded":1679396814.890502,"context":"foo","url":""
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"success":true,
|
||||||
|
"message":"",
|
||||||
|
"code":200}`
|
||||||
|
|
||||||
|
listingnoaccess := `{"success":false,"message":"invalid context","code":503}`
|
||||||
|
|
||||||
|
tests := []Unit{
|
||||||
|
{
|
||||||
|
name: "describe",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: false,
|
||||||
|
route: "/upload/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: listing,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
expect: `Uploaded: 2023-03-21 12:06:54.890501888`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "describe-catch-empty-json",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/upload/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: "",
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "describe-catch-no-access",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/upload/",
|
||||||
|
sendcode: 503,
|
||||||
|
sendjson: listingnoaccess,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, unit := range tests {
|
||||||
|
var w bytes.Buffer
|
||||||
|
unit.route += unit.files[0] + "/"
|
||||||
|
Intercept(unit)
|
||||||
|
Check(t, unit, &w, Describe(&w, conf, unit.files))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDelete(t *testing.T) {
|
||||||
|
conf := &cfg.Config{
|
||||||
|
Mock: true,
|
||||||
|
Apikey: "token",
|
||||||
|
Endpoint: endpoint,
|
||||||
|
Silent: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
listingnoaccess := `{"success":false,"message":"invalid context","code":503}`
|
||||||
|
|
||||||
|
tests := []Unit{
|
||||||
|
{
|
||||||
|
name: "delete",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: false,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: `{"success":true,"message":"","code":200}`,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "DELETE",
|
||||||
|
expect: `Upload cc2c965a successfully deleted`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete-catch-empty-json",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendjson: "",
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "DELETE",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "delete-catch-no-access",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 503,
|
||||||
|
sendjson: listingnoaccess,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "DELETE",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, unit := range tests {
|
||||||
|
var w bytes.Buffer
|
||||||
|
unit.route += unit.files[0] + "/"
|
||||||
|
Intercept(unit)
|
||||||
|
Check(t, unit, &w, Delete(&w, conf, unit.files))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestDownload(t *testing.T) {
|
||||||
|
conf := &cfg.Config{
|
||||||
|
Mock: true,
|
||||||
|
Apikey: "token",
|
||||||
|
Endpoint: endpoint,
|
||||||
|
Silent: true,
|
||||||
|
}
|
||||||
|
|
||||||
|
listingnoaccess := `{"success":false,"message":"invalid context","code":503}`
|
||||||
|
|
||||||
|
tests := []Unit{
|
||||||
|
{
|
||||||
|
name: "download",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: false,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
sendfile: "../t/t1",
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
expect: `cc2c965a successfully downloaded to file t1`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "download-catch-empty-response",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 200,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: "download-catch-no-access",
|
||||||
|
apikey: "token",
|
||||||
|
wantfail: true,
|
||||||
|
route: "/file/",
|
||||||
|
sendcode: 503,
|
||||||
|
sendjson: listingnoaccess,
|
||||||
|
files: []string{"cc2c965a"},
|
||||||
|
method: "GET",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
|
for _, unit := range tests {
|
||||||
|
var w bytes.Buffer
|
||||||
|
unit.route += unit.files[0] + "/"
|
||||||
|
Intercept(unit)
|
||||||
|
Check(t, unit, &w, Download(&w, conf, unit.files))
|
||||||
|
|
||||||
|
if unit.sendfile != "" {
|
||||||
|
file := filepath.Base(unit.sendfile)
|
||||||
|
if _, err := os.Stat(file); err == nil {
|
||||||
|
os.Remove(file)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -24,7 +24,8 @@ import (
|
|||||||
"github.com/imroc/req/v3"
|
"github.com/imroc/req/v3"
|
||||||
"github.com/olekukonko/tablewriter"
|
"github.com/olekukonko/tablewriter"
|
||||||
"github.com/tlinden/cenophane/common"
|
"github.com/tlinden/cenophane/common"
|
||||||
"os"
|
"io"
|
||||||
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -41,8 +42,9 @@ func prepareExpire(expire string, start common.Timestamp) string {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// generic table writer
|
// generic table writer
|
||||||
func WriteTable(headers []string, data [][]string) {
|
func WriteTable(w io.Writer, headers []string, data [][]string) {
|
||||||
table := tablewriter.NewWriter(os.Stdout)
|
tableString := &strings.Builder{}
|
||||||
|
table := tablewriter.NewWriter(tableString)
|
||||||
|
|
||||||
table.SetHeader(headers)
|
table.SetHeader(headers)
|
||||||
table.AppendBulk(data)
|
table.AppendBulk(data)
|
||||||
@@ -60,22 +62,24 @@ func WriteTable(headers []string, data [][]string) {
|
|||||||
table.SetNoWhiteSpace(true)
|
table.SetNoWhiteSpace(true)
|
||||||
|
|
||||||
table.Render()
|
table.Render()
|
||||||
|
|
||||||
|
fmt.Fprintln(w, tableString.String())
|
||||||
}
|
}
|
||||||
|
|
||||||
// output like psql \x
|
// output like psql \x
|
||||||
func WriteExtended(uploads *common.Uploads) {
|
func WriteExtended(w io.Writer, uploads *common.Uploads) {
|
||||||
format := fmt.Sprintf("%%%ds: %%s\n", Maxwidth)
|
format := fmt.Sprintf("%%%ds: %%s\n", Maxwidth)
|
||||||
|
|
||||||
// we shall only have 1 element, however, if we ever support more, here we go
|
// we shall only have 1 element, however, if we ever support more, here we go
|
||||||
for _, entry := range uploads.Entries {
|
for _, entry := range uploads.Entries {
|
||||||
expire := prepareExpire(entry.Expire, entry.Uploaded)
|
expire := prepareExpire(entry.Expire, entry.Uploaded)
|
||||||
fmt.Printf(format, "Id", entry.Id)
|
fmt.Fprintf(w, format, "Id", entry.Id)
|
||||||
fmt.Printf(format, "Expire", expire)
|
fmt.Fprintf(w, format, "Expire", expire)
|
||||||
fmt.Printf(format, "Context", entry.Context)
|
fmt.Fprintf(w, format, "Context", entry.Context)
|
||||||
fmt.Printf(format, "Uploaded", entry.Uploaded)
|
fmt.Fprintf(w, format, "Uploaded", entry.Uploaded)
|
||||||
fmt.Printf(format, "Filename", entry.File)
|
fmt.Fprintf(w, format, "Filename", entry.File)
|
||||||
fmt.Printf(format, "Url", entry.Url)
|
fmt.Fprintf(w, format, "Url", entry.Url)
|
||||||
fmt.Println()
|
fmt.Fprintln(w)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -95,14 +99,14 @@ func GetUploadsFromResponse(resp *req.Response) (*common.Uploads, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// turn the Uploads{} struct into a table and print it
|
// turn the Uploads{} struct into a table and print it
|
||||||
func RespondTable(resp *req.Response) error {
|
func RespondTable(w io.Writer, resp *req.Response) error {
|
||||||
uploads, err := GetUploadsFromResponse(resp)
|
uploads, err := GetUploadsFromResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if uploads.Message != "" {
|
if uploads.Message != "" {
|
||||||
fmt.Println(uploads.Message)
|
fmt.Fprintln(w, uploads.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
// tablewriter
|
// tablewriter
|
||||||
@@ -113,23 +117,23 @@ func RespondTable(resp *req.Response) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteTable([]string{"ID", "EXPIRE", "CONTEXT", "UPLOADED"}, data)
|
WriteTable(w, []string{"ID", "EXPIRE", "CONTEXT", "UPLOADED"}, data)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// turn the Uploads{} struct into xtnd output and print it
|
// turn the Uploads{} struct into xtnd output and print it
|
||||||
func RespondExtended(resp *req.Response) error {
|
func RespondExtended(w io.Writer, resp *req.Response) error {
|
||||||
uploads, err := GetUploadsFromResponse(resp)
|
uploads, err := GetUploadsFromResponse(resp)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
if uploads.Message != "" {
|
if uploads.Message != "" {
|
||||||
fmt.Println(uploads.Message)
|
fmt.Fprintln(w, uploads.Message)
|
||||||
}
|
}
|
||||||
|
|
||||||
WriteExtended(uploads)
|
WriteExtended(w, uploads)
|
||||||
|
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user