Skip to content

Commit

Permalink
Fixed #39
Browse files Browse the repository at this point in the history
  • Loading branch information
cpliakas committed May 23, 2021
1 parent 94ba60f commit dfd3c37
Show file tree
Hide file tree
Showing 3 changed files with 125 additions and 4 deletions.
42 changes: 42 additions & 0 deletions cmd/formula_testcmd.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
package cmd

import (
"github.com/QuickBase/quickbase-cli/qbcli"
"github.com/QuickBase/quickbase-cli/qbclient"
"github.com/cpliakas/cliutil"
"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var formulaTestCfg *viper.Viper

var formulaTestCmd = &cobra.Command{
Use: "test",
Short: "Test formulas",

Args: func(cmd *cobra.Command, args []string) (err error) {
err = globalCfg.Validate()
return
},

Run: func(cmd *cobra.Command, args []string) {
ctx, logger, qb := qbcli.NewClient(cmd, globalCfg)

input := &qbcli.TestFormulaInput{}
qbcli.GetOptions(ctx, logger, input, formulaTestCfg)

output, err := qbcli.TestFormula(qb, input)
qbcli.Render(ctx, logger, cmd, globalCfg, output, err)

if len(output.Failed) > 0 {
err = qbcli.TestsFailedError("%v tests failed", len(output.Failed))
qbcli.HandleError(ctx, logger, "tests failed", err)
}
},
}

func init() {
var flags *cliutil.Flagger
formulaTestCfg, flags = cliutil.AddCommand(formulaCmd, formulaTestCmd, qbclient.EnvPrefix)
flags.SetOptions(&qbcli.TestFormulaInput{})
}
10 changes: 10 additions & 0 deletions qbcli/error.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,21 @@ package qbcli

import (
"context"
"net/http"
"os"

"github.com/QuickBase/quickbase-cli/qberrors"
"github.com/cpliakas/cliutil"
)

var (
TestsFailed = qberrors.ErrSafe{Message: "tests failed", StatusCode: http.StatusBadRequest}
)

func TestsFailedError(format string, a ...interface{}) error {
return qberrors.Client(nil).Safef(TestsFailed, format, a...)
}

// HandleError handles an error by logging it and returning a non-zero status.
// We reserve Fatal errors for internal problems.
func HandleError(ctx context.Context, logger *cliutil.LeveledLogger, message string, err error) {
Expand Down
77 changes: 73 additions & 4 deletions qbcli/qbfile.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,10 +11,23 @@ import (
"gopkg.in/yaml.v3"
)

// QuickbaseFile models a quickbase.yml file.
type QuickbaseFile struct {
Test *QuickbaseFileTest `yaml:"test"`
Deploy *QuickbaseFileDeploy `yaml:"deploy"`
}

type QuickbaseFileTest struct {
Formulas []*QuickbaseFileTestFormula `yaml:"formulas"`
}

type QuickbaseFileTestFormula struct {
File string `validate:"required" yaml:"file"`
TableID string `validate:"required" yaml:"table_id"`
RecordID int `validate:"required" yaml:"record_id"`
Expected string `validate:"required" yaml:"expected"`
}

type QuickbaseFileDeploy struct {
Formulas []*QuickbaseFileDeployFormula `yaml:"formulas"`
}
Expand All @@ -28,23 +41,79 @@ type QuickbaseFileDeployFormula struct {
func ParseQuickbaseFile(file string) (f *QuickbaseFile, err error) {
f = &QuickbaseFile{}

// Read the quickbase.yml file.
b, err := ioutil.ReadFile(file)
if err != nil {
err = fmt.Errorf("error reading quickbase file: %w", err)
err = qberrors.Client(nil).Safef(qberrors.InvalidInput, "error reading quickbase file: %w", err)
return
}

// Parse the yaml file using strict settings.
dec := yaml.NewDecoder(bytes.NewBuffer(b))
dec.KnownFields(true)
err = dec.Decode(f)
derr := dec.Decode(f)
if derr != nil {
err = qberrors.Client(nil).Safef(qberrors.InvalidSyntax, "yaml not valid: %w", derr)
}

if verr := validator.New().Struct(f); err != nil {
// Validate the decoded file.
if verr := validator.New().Struct(f); verr != nil {
err = qberrors.HandleErrorValidation(verr)
}

return
}

type TestFormulaInput struct {
File string `cliutil:"option=file default=quickbase.yml"`
}

type TestFormulaOutput struct {
Passed []int `json:"passed"`
Failed map[int]string `json:"failed"`
}

func TestFormula(qb *qbclient.Client, in *TestFormulaInput) (out *TestFormulaOutput, err error) {
out = &TestFormulaOutput{
Passed: []int{},
Failed: map[int]string{},
}

var file *QuickbaseFile
file, err = ParseQuickbaseFile(in.File)
if err != nil {
return
}

for idx, f := range file.Test.Formulas {

b, ferr := ioutil.ReadFile(f.File)
if ferr != nil {
err = qberrors.Client(nil).Safef(qberrors.InvalidInput, "error reading formula file: %w", ferr)
return
}

rfi := &qbclient.RunFormulaInput{
From: f.TableID,
RecordID: f.RecordID,
Formula: string(b),
}

rfo, rerr := qb.RunFormula(rfi)
if rerr == nil {
if f.Expected == rfo.Result {
out.Passed = append(out.Passed, idx)
} else {
out.Failed[idx] = fmt.Sprintf("expected %q, got %q", f.Expected, rfo.Result)
}
} else {
out.Failed[idx] = rerr.Error()
}
}

return
}

type DeployFormulaInput struct {
File string `cliutil:"option=file default=quickbase.yml"`
}
Expand All @@ -70,7 +139,7 @@ func DeployFormula(qb *qbclient.Client, in *DeployFormulaInput) (out *DeployForm

b, ferr := ioutil.ReadFile(f.File)
if ferr != nil {
err = fmt.Errorf("error reading formula file: %w", ferr)
err = qberrors.Client(nil).Safef(qberrors.InvalidInput, "error reading formula file: %w", ferr)
return
}

Expand Down

0 comments on commit dfd3c37

Please sign in to comment.