Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ For example, the following command:

reads from the YAML configuration file, processes the "translate" function, and sends an API request to an API.
The response is then printed to stdout. For more Information about YAML Configuration, visit https://github.com/nvima/httpcli.`,
Run: tplCommand,
RunE: tplCommand,
}

func Execute() {
Expand Down
12 changes: 12 additions & 0 deletions cmd/testdata/config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -26,3 +26,15 @@ translate:
env:
- "TEST_API_KEY"
- "TEST_SERVER_URL"
emptydata:
url: "${TEST_SERVER_URL}/emptydata"
output: "response"
env:
- "TEST_SERVER_URL"
emptyoutput:
url: "${TEST_SERVER_URL}/emptydata"
env:
- "TEST_SERVER_URL"
emptyurl:
env:
- "TEST_SERVER_URL"
50 changes: 32 additions & 18 deletions cmd/tpl.go
Original file line number Diff line number Diff line change
Expand Up @@ -28,37 +28,51 @@ type AppConfig struct {
Functions map[string]FunctionConfig
}

//TODO Better error handling for testing
func tplCommand(cmd *cobra.Command, args []string) {
fc := initFunctionConfig(cmd, args)
output := fc.handleFunc(cmd)
var fc FunctionConfig

func tplCommand(cmd *cobra.Command, args []string) error {
err := initFunctionConfig(cmd, args)
if err != nil {
return err
}

output, err := fc.handleFunc(cmd)
if err != nil {
return err
}

fmt.Fprintf(cmd.OutOrStdout(), output)
return nil
}

func initFunctionConfig(cmd *cobra.Command, args []string) FunctionConfig {
fc := FunctionConfig{}
func initFunctionConfig(cmd *cobra.Command, args []string) error {
config := viper.AllSettings()

if len(config) == 0 {
util.HandleError(cmd, util.NO_FUNC_NAME_ERR.Err(), util.NO_CONFIG_FILE_ERR)
return util.HandleError(cmd, util.NO_FUNC_NAME_ERR.Err(), util.NO_CONFIG_FILE_ERR)
}

if len(args) == 0 {
util.HandleError(cmd, util.NO_FUNC_NAME_ERR.Err(), util.NO_FUNC_NAME_ERR)
return util.HandleError(cmd, util.NO_FUNC_NAME_ERR.Err(), util.NO_FUNC_NAME_ERR)
}

var appConfig AppConfig
err := mapstructure.Decode(config, &appConfig.Functions)
if err != nil {
util.HandleError(cmd, err, util.INVALID_CONFIG_ERR)
return util.HandleError(cmd, err, util.INVALID_CONFIG_ERR)
}

fc, ok := appConfig.Functions[args[0]]
funcConfig, ok := appConfig.Functions[args[0]]
if !ok {
util.HandleError(cmd, util.NO_FUNC_FOUND_ERR.Err(), util.NO_FUNC_FOUND_ERR)
return util.HandleError(cmd, util.NO_FUNC_FOUND_ERR.Err(), util.NO_FUNC_FOUND_ERR)
}

if funcConfig.Url == "" {
return util.HandleError(cmd, util.NO_URL_ERR.Err(), util.NO_URL_ERR)
}

return fc
fc = funcConfig
return nil
}

func (fc *FunctionConfig) makeHttpCall(jsonData []byte, cmd *cobra.Command) ([]byte, error) {
Expand Down Expand Up @@ -97,28 +111,28 @@ func (fc *FunctionConfig) makeHttpCall(jsonData []byte, cmd *cobra.Command) ([]b
return body, nil
}

func (fc *FunctionConfig) handleFunc(cmd *cobra.Command) string {
func (fc *FunctionConfig) handleFunc(cmd *cobra.Command) (string, error) {
jsonData, err := fc.getJSONData()
if err != nil {
util.HandleError(cmd, err, util.FAILED_TO_GET_DATA)
return "", util.HandleError(cmd, err, util.FAILED_TO_GET_DATA)
}

body, err := fc.makeHttpCall(jsonData, cmd)
if err != nil {
util.HandleError(cmd, err, util.FAILED_TO_MAKE_HTTP_CALL)
return "", util.HandleError(cmd, err, util.FAILED_TO_MAKE_HTTP_CALL)
}

responseData, err := util.ParseJSONResponse(body)
if err != nil {
util.HandleError(cmd, err, util.FAILED_TO_PARSE_JSON)
return "", util.HandleError(cmd, err, util.FAILED_TO_PARSE_JSON)
}

output, err := util.GetOutputField(responseData, fc.Output)
if err != nil {
util.HandleError(cmd, err, util.FAILED_TO_PARSE_OUTPUT_FIELD)
return "", util.HandleError(cmd, err, util.FAILED_TO_PARSE_OUTPUT_FIELD)
}

return output
return output, nil
}

func (fc *FunctionConfig) getJSONData() ([]byte, error) {
Expand Down
43 changes: 43 additions & 0 deletions cmd/tpl_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ import (
"os"
"testing"

"github.com/nvima/httpcli/util"
)

var testServer *httptest.Server
Expand Down Expand Up @@ -38,6 +39,8 @@ func startTestHTTPServer() *httptest.Server {
w.Write([]byte(`{"choices": [{"message": {"content": "` + data.Messages[0].Content + `"}}]}`))
case "/v2/translate":
w.Write([]byte(`{"translations": [{"text": "Pomme"}]}`))
case "/emptydata":
w.Write([]byte(`{"response":"Hello"}`))
default:
http.Error(w, "Not found", http.StatusNotFound)
}
Expand Down Expand Up @@ -75,3 +78,43 @@ func TestTranslate(t *testing.T) {
t.Fatalf("expected \"%s\" got \"%s\"", expected, string(out))
}
}

func TestEmptyData(t *testing.T) {
b := bytes.NewBufferString("")
rootCmd.SetOut(b)
rootCmd.SetArgs([]string{"emptydata", "--config", "./testdata/config.yaml"})
rootCmd.Execute()
out, err := ioutil.ReadAll(b)
if err != nil {
t.Fatal(err)
}
expected := "Hello"
if string(out) != expected {
t.Fatalf("expected \"%s\" got \"%s\"", expected, string(out))
}
}

func TestEmptyOutput(t *testing.T) {
b := bytes.NewBufferString("")
rootCmd.SetOut(b)
rootCmd.SetArgs([]string{"emptyoutput", "--config", "./testdata/config.yaml"})
rootCmd.Execute()
out, err := ioutil.ReadAll(b)
if err != nil {
t.Fatal(err)
}
expected := []byte(`{"response":"Hello"}`)
if string(out) != string(expected) {
t.Fatalf("expected \"%s\" got \"%s\"", expected, string(out))
}
}

func TestEmptyUrl(t *testing.T) {
b := bytes.NewBufferString("")
rootCmd.SetOut(b)
rootCmd.SetArgs([]string{"emptyurl", "--config", "./testdata/config.yaml"})
err := rootCmd.Execute()
if err.Error() != util.NO_URL_ERR.Msg() {
t.Fatalf("expected \"%s\" got \"%s\"", util.NO_URL_ERR.Msg(), err.Error())
}
}
17 changes: 3 additions & 14 deletions util/errors.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ import (
type TplError struct {
msg string
err error
exitCode int
}

func (te TplError) Err() error {
Expand All @@ -18,46 +17,36 @@ func (te TplError) Msg() string {
return te.msg
}

func (te TplError) ExitCode() int {
return te.exitCode
}

var NO_CONFIG_FILE_ERR = TplError{
msg: "No config file found",
exitCode: 1,
}

var NO_FUNC_NAME_ERR = TplError{
msg: "No function name provided",
exitCode: 2,
}
var NO_FUNC_FOUND_ERR = TplError{
msg: "Function not found in config",
exitCode: 3,
}

var INVALID_CONFIG_ERR = TplError{
msg: "Invalid config file",
exitCode: 4,
}

var INVALID_RESP_CODE = TplError{
msg: "Invalid response code",
exitCode: 5,
}
var FAILED_TO_GET_DATA = TplError{
msg: "Failed to get data",
exitCode: 6,
}
var FAILED_TO_MAKE_HTTP_CALL = TplError{
msg: "Failed to make http call",
exitCode: 7,
}
var FAILED_TO_PARSE_JSON = TplError{
msg: "Failed to parse JSON",
exitCode: 8,
}
var FAILED_TO_PARSE_OUTPUT_FIELD = TplError{
msg: "Failed to parse output field",
exitCode: 9,
}
var NO_URL_ERR = TplError{
msg: "No URL provided",
}
11 changes: 6 additions & 5 deletions util/handleError.go
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package util

import (
"fmt"
"os"
// "fmt"

"github.com/spf13/cobra"
)

func HandleError(cmd *cobra.Command, err error, tplError TplError) {
func HandleError(cmd *cobra.Command, err error, tplError TplError) error {
//TODO:: Add Error Logging with Stacktraces
// fmt.Println(err)
fmt.Fprintf(cmd.OutOrStdout(), tplError.msg)
os.Exit(tplError.exitCode)

// fmt.Fprintf(cmd.OutOrStdout(), tplError.msg)
return err
}