Skip to content

Commit

Permalink
feat(apps): Describe application command (#265)
Browse files Browse the repository at this point in the history
* feat(apps): Describe application command
  • Loading branch information
janelletavares authored Mar 4, 2022
1 parent af971da commit 5817de5
Show file tree
Hide file tree
Showing 7 changed files with 321 additions and 13 deletions.
87 changes: 87 additions & 0 deletions cmd/meroxa/root/apps/describe.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
/*
Copyright © 2021 Meroxa Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package apps

import (
"context"
"errors"

"github.com/meroxa/cli/cmd/meroxa/builder"
"github.com/meroxa/cli/log"
"github.com/meroxa/cli/utils"
"github.com/meroxa/meroxa-go/pkg/meroxa"
)

var (
_ builder.CommandWithDocs = (*Describe)(nil)
_ builder.CommandWithArgs = (*Describe)(nil)
_ builder.CommandWithClient = (*Describe)(nil)
_ builder.CommandWithLogger = (*Describe)(nil)
_ builder.CommandWithExecute = (*Describe)(nil)
)

type describeApplicationClient interface {
GetApplication(ctx context.Context, nameOrUUID string) (*meroxa.Application, error)
}

type Describe struct {
client describeApplicationClient
logger log.Logger

args struct {
NameOrUUID string
}
}

func (d *Describe) Usage() string {
return "describe [NAMEorUUID]"
}

func (d *Describe) Docs() builder.Docs {
return builder.Docs{
Short: "Describe Application",
}
}

func (d *Describe) Execute(ctx context.Context) error {
app, err := d.client.GetApplication(ctx, d.args.NameOrUUID)
if err != nil {
return err
}

d.logger.Info(ctx, utils.AppTable(app))
d.logger.JSON(ctx, app)

return nil
}

func (d *Describe) Client(client meroxa.Client) {
d.client = client
}

func (d *Describe) Logger(logger log.Logger) {
d.logger = logger
}

func (d *Describe) ParseArgs(args []string) error {
if len(args) < 1 {
return errors.New("requires app name")
}

d.args.NameOrUUID = args[0]
return nil
}
160 changes: 160 additions & 0 deletions cmd/meroxa/root/apps/describe_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
/*
Copyright © 2021 Meroxa Inc
Licensed under the Apache License, Version 2.0 (the "License");
you may not use this file except in compliance with the License.
You may obtain a copy of the License at
http://www.apache.org/licenses/LICENSE-2.0
Unless required by applicable law or agreed to in writing, software
distributed under the License is distributed on an "AS IS" BASIS,
WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
See the License for the specific language governing permissions and
limitations under the License.
*/

package apps

import (
"context"
"encoding/json"
"errors"
"reflect"
"strings"
"testing"

"github.com/golang/mock/gomock"
"github.com/volatiletech/null/v8"

"github.com/meroxa/cli/log"
"github.com/meroxa/cli/utils"
"github.com/meroxa/meroxa-go/pkg/meroxa"
"github.com/meroxa/meroxa-go/pkg/mock"
)

func TestDescribeApplicationArgs(t *testing.T) {
tests := []struct {
args []string
err error
name string
}{
{args: nil, err: errors.New("requires app name"), name: ""},
{args: []string{"ApplicationName"}, err: nil, name: "ApplicationName"},
}

for _, tt := range tests {
ar := &Describe{}
err := ar.ParseArgs(tt.args)

if err != nil && tt.err.Error() != err.Error() {
t.Fatalf("expected \"%s\" got \"%s\"", tt.err, err)
}

if tt.name != ar.args.NameOrUUID {
t.Fatalf("expected \"%s\" got \"%s\"", tt.name, ar.args.NameOrUUID)
}
}
}

func TestDescribeApplicationExecution(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
client := mock.NewMockClient(ctrl)
logger := log.NewTestLogger()

appName := "my-env"

a := utils.GenerateApplication()
a.Name = appName

client.
EXPECT().
GetApplication(
ctx,
a.Name,
).
Return(&a, nil)

dc := &Describe{
client: client,
logger: logger,
}
dc.args.NameOrUUID = a.Name

err := dc.Execute(ctx)
if err != nil {
t.Fatalf("not expected error, got %q", err.Error())
}

gotLeveledOutput := logger.LeveledOutput()
wantLeveledOutput := utils.AppTable(&a)

if !strings.Contains(gotLeveledOutput, wantLeveledOutput) {
t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput)
}

gotJSONOutput := logger.JSONOutput()
var gotApp meroxa.Application
err = json.Unmarshal([]byte(gotJSONOutput), &gotApp)
if err != nil {
t.Fatalf("not expected error, got %q", err.Error())
}

if !reflect.DeepEqual(gotApp, a) {
t.Fatalf("expected \"%v\", got \"%v\"", a, gotApp)
}
}

func TestDescribeApplicationExecutionWithFunctions(t *testing.T) {
ctx := context.Background()
ctrl := gomock.NewController(t)
client := mock.NewMockClient(ctrl)
logger := log.NewTestLogger()

appName := "my-app-with-funcs"

a := utils.GenerateApplication()
a.Name = appName
a.Functions = []meroxa.FunctionIdentifier{
{Name: null.StringFrom("fun1")},
{Name: null.StringFrom("fun2")},
}

client.
EXPECT().
GetApplication(
ctx,
a.Name,
).
Return(&a, nil)

dc := &Describe{
client: client,
logger: logger,
}
dc.args.NameOrUUID = a.Name

err := dc.Execute(ctx)
if err != nil {
t.Fatalf("not expected error, got %q", err.Error())
}

gotLeveledOutput := logger.LeveledOutput()
wantLeveledOutput := utils.AppTable(&a)

if !strings.Contains(gotLeveledOutput, wantLeveledOutput) {
t.Fatalf("expected output:\n%s\ngot:\n%s", wantLeveledOutput, gotLeveledOutput)
}

gotJSONOutput := logger.JSONOutput()
var gotApp meroxa.Application
err = json.Unmarshal([]byte(gotJSONOutput), &gotApp)
if err != nil {
t.Fatalf("not expected error, got %q", err.Error())
}

if !reflect.DeepEqual(gotApp, a) {
t.Fatalf("expected \"%v\", got \"%v\"", a, gotApp)
}
}
6 changes: 2 additions & 4 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ require (
github.com/manifoldco/promptui v0.8.0
github.com/mattn/go-colorable v0.1.8 // indirect
github.com/mattn/go-runewidth v0.0.10 // indirect
github.com/meroxa/meroxa-go v0.0.0-20220302153558-e3b3dc31559c
github.com/meroxa/meroxa-go v0.0.0-20220304141736-3e708e76b666
github.com/nirasan/go-oauth-pkce-code-verifier v0.0.0-20170819232839-0fbfe93532da
github.com/pkg/browser v0.0.0-20210115035449-ce105d075bb4
github.com/rivo/uniseg v0.2.0 // indirect
Expand All @@ -28,6 +28,7 @@ require (
github.com/docker/docker v20.10.12+incompatible
github.com/mattn/go-shellwords v1.0.12
github.com/meroxa/turbine v0.0.0-20220301211444-5662995ad65f
github.com/volatiletech/null/v8 v8.1.2
)

require github.com/cristalhq/jwt/v3 v3.1.0 // indirect
Expand Down Expand Up @@ -72,7 +73,6 @@ require (
github.com/spf13/jwalterweatherman v1.1.0 // indirect
github.com/subosito/gotenv v1.2.0 // indirect
github.com/volatiletech/inflect v0.0.1 // indirect
github.com/volatiletech/null/v8 v8.1.2 // indirect
github.com/volatiletech/randomize v0.0.1 // indirect
github.com/volatiletech/strmangle v0.0.2 // indirect
go.opencensus.io v0.23.0 // indirect
Expand All @@ -88,5 +88,3 @@ require (
gopkg.in/ini.v1 v1.62.0 // indirect
gopkg.in/yaml.v2 v2.4.0 // indirect
)

replace github.com/meroxa/meroxa-go => ../meroxa-go
3 changes: 3 additions & 0 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -574,6 +574,9 @@ github.com/matttproud/golang_protobuf_extensions v1.0.1/go.mod h1:D8He9yQNgCq6Z5
github.com/matttproud/golang_protobuf_extensions v1.0.2-0.20181231171920-c182affec369/go.mod h1:BSXmuO+STAnVfrANrmjBb36TMTDstsz7MSK+HVaYKv4=
github.com/maxbrunsfeld/counterfeiter/v6 v6.2.2/go.mod h1:eD9eIE7cdwcMi9rYluz88Jz2VyhSmden33/aXg4oVIY=
github.com/meroxa/funtime v0.0.0-20220113012133-85e6e898fc73/go.mod h1:K2y2GvcA4Cg3dJtckcwYWnwnJzF63FDdtAQI0fToU0Q=
github.com/meroxa/meroxa-go v0.0.0-20220208195203-71ddc3133fab/go.mod h1:HDFszURCM1cOpKE699o5Hs0T2tEIXqY+vFcsur3RiwY=
github.com/meroxa/meroxa-go v0.0.0-20220304141736-3e708e76b666 h1:FWwzyreRc5RXbOTVjcNNfiBwNYaqTOqfppmyNGefVDA=
github.com/meroxa/meroxa-go v0.0.0-20220304141736-3e708e76b666/go.mod h1:BsqYa9jqfyGOAgfkggfK567b2Ahkb+RCH3lXDQGgrh8=
github.com/meroxa/turbine v0.0.0-20220301211444-5662995ad65f h1:fWCA+cO4aPIzePOuz4drdOQAgUTM6UG7lRYgtbWLHv0=
github.com/meroxa/turbine v0.0.0-20220301211444-5662995ad65f/go.mod h1:4A2E9icHDi3x4Flp9CunWyRBvNkZy6h8MS8zLvWUlmw=
github.com/miekg/dns v1.0.14/go.mod h1:W1PPwlIAgtquWBMBEV9nkV9Cazfe8ScdGz/Lj7v3Nrg=
Expand Down
52 changes: 52 additions & 0 deletions utils/display.go
Original file line number Diff line number Diff line change
Expand Up @@ -850,6 +850,58 @@ func AppsTable(apps []*meroxa.Application, hideHeaders bool) string {
return table.String()
}

func AppTable(app *meroxa.Application) string {
mainTable := simpletable.New()
mainTable.Body.Cells = [][]*simpletable.Cell{
{
{Align: simpletable.AlignRight, Text: "UUID:"},
{Text: app.UUID},
},
{
{Align: simpletable.AlignRight, Text: "Name:"},
{Text: app.Name},
},
{
{Align: simpletable.AlignRight, Text: "Language:"},
{Text: app.Language},
},
{
{Align: simpletable.AlignRight, Text: "Created At:"},
{Text: app.CreatedAt.String()},
},
{
{Align: simpletable.AlignRight, Text: "Updated At:"},
{Text: app.UpdatedAt.String()},
},
{
{Align: simpletable.AlignRight, Text: "State:"},
{Text: strings.Title(string(app.Status.State))},
},
}

details := app.Status.Details
if details != "" {
mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{
{Align: simpletable.AlignRight, Text: "State details:"},
{Text: strings.Title(details)},
})
}

if len(app.Functions) != 0 {
names := make([]string, 0)
for _, f := range app.Functions {
names = append(names, f.Name.String)
}

mainTable.Body.Cells = append(mainTable.Body.Cells, []*simpletable.Cell{
{Align: simpletable.AlignRight, Text: "Functions:"},
{Text: strings.Join(names, ", ")},
})
}
mainTable.SetStyle(simpletable.StyleCompact)
return mainTable.String()
}

func PrintAppsTable(apps []*meroxa.Application, hideHeaders bool) {
fmt.Println(AppsTable(apps, hideHeaders))
}
Expand Down
Loading

0 comments on commit 5817de5

Please sign in to comment.