Skip to content

Commit 7978bff

Browse files
authored
Merge pull request #19 from Vonage/feat/mongo-new
MongoDB support
2 parents 219164e + b5efae9 commit 7978bff

File tree

13 files changed

+918
-0
lines changed

13 files changed

+918
-0
lines changed

pkg/api/deployment.go

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -401,3 +401,100 @@ func (c *DeploymentClient) RemoveSecret(ctx context.Context, name string) error
401401
}
402402
return nil
403403
}
404+
405+
type pluginsRequest struct {
406+
Plugin string `json:"plugin"`
407+
Version string `json:"version"`
408+
Action string `json:"action"`
409+
Options map[string]interface{} `json:"options"`
410+
}
411+
412+
type MongoInfoResponse struct {
413+
Username string `json:"username"`
414+
Password string `json:"password"`
415+
Database string `json:"database"`
416+
ConnectionString string `json:"connectionString"`
417+
}
418+
419+
const pluginsPath = "/plugins"
420+
421+
func (c *DeploymentClient) CreateMongoDatabase(ctx context.Context, version string) (MongoInfoResponse, error) {
422+
var result MongoInfoResponse
423+
424+
resp, err := c.httpClient.R().
425+
SetContext(ctx).
426+
SetResult(&result).
427+
SetBody(pluginsRequest{Plugin: "mongo", Version: version, Action: "createDB"}).
428+
Post(c.baseURL + pluginsPath)
429+
if err != nil {
430+
return MongoInfoResponse{}, fmt.Errorf("%w: trace_id = %s", err, traceIDFromHTTPResponse(resp))
431+
}
432+
if resp.StatusCode() == http.StatusNotFound {
433+
return MongoInfoResponse{}, ErrNotFound
434+
}
435+
if resp.IsError() {
436+
return MongoInfoResponse{}, NewErrorFromHTTPResponse(resp)
437+
}
438+
439+
return result, nil
440+
}
441+
442+
func (c *DeploymentClient) DeleteMongoDatabase(ctx context.Context, version, database string) error {
443+
resp, err := c.httpClient.R().
444+
SetContext(ctx).
445+
SetBody(pluginsRequest{Plugin: "mongo", Version: version, Action: "deleteDB", Options: map[string]interface{}{"database": database}}).
446+
Post(c.baseURL + pluginsPath)
447+
if err != nil {
448+
return fmt.Errorf("%w: trace_id = %s", err, traceIDFromHTTPResponse(resp))
449+
}
450+
if resp.StatusCode() == http.StatusNotFound {
451+
return ErrNotFound
452+
}
453+
if resp.IsError() {
454+
return NewErrorFromHTTPResponse(resp)
455+
}
456+
457+
return nil
458+
}
459+
460+
func (c *DeploymentClient) GetMongoDatabase(ctx context.Context, version string, database string) (MongoInfoResponse, error) {
461+
var result MongoInfoResponse
462+
463+
resp, err := c.httpClient.R().
464+
SetContext(ctx).
465+
SetResult(&result).
466+
SetBody(pluginsRequest{Plugin: "mongo", Version: version, Action: "getDB", Options: map[string]interface{}{"database": database}}).
467+
Post(c.baseURL + pluginsPath)
468+
if err != nil {
469+
return MongoInfoResponse{}, fmt.Errorf("%w: trace_id = %s", err, traceIDFromHTTPResponse(resp))
470+
}
471+
if resp.StatusCode() == http.StatusNotFound {
472+
return MongoInfoResponse{}, ErrNotFound
473+
}
474+
if resp.IsError() {
475+
return MongoInfoResponse{}, NewErrorFromHTTPResponse(resp)
476+
}
477+
478+
return result, nil
479+
}
480+
481+
func (c *DeploymentClient) ListMongoDatabases(ctx context.Context, version string) ([]string, error) {
482+
var result []string
483+
484+
resp, err := c.httpClient.R().
485+
SetContext(ctx).
486+
SetResult(&result).
487+
SetBody(pluginsRequest{Plugin: "mongo", Version: version, Action: "listDBs"}).
488+
Post(c.baseURL + pluginsPath)
489+
if err != nil {
490+
return nil, fmt.Errorf("%w: trace_id = %s", err, traceIDFromHTTPResponse(resp))
491+
}
492+
if resp.StatusCode() == http.StatusNotFound {
493+
return nil, ErrNotFound
494+
}
495+
if resp.IsError() {
496+
return nil, NewErrorFromHTTPResponse(resp)
497+
}
498+
499+
return result, nil
500+
}

pkg/cmdutil/factory.go

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,10 @@ type DeploymentInterface interface {
5252
CreateSecret(ctx context.Context, s config.Secret) error
5353
UpdateSecret(ctx context.Context, s config.Secret) error
5454
RemoveSecret(ctx context.Context, name string) error
55+
CreateMongoDatabase(ctx context.Context, version string) (api.MongoInfoResponse, error)
56+
DeleteMongoDatabase(ctx context.Context, version, database string) error
57+
GetMongoDatabase(ctx context.Context, version, database string) (api.MongoInfoResponse, error)
58+
ListMongoDatabases(ctx context.Context, version string) ([]string, error)
5559
}
5660

5761
type DatastoreInterface interface {

testutil/mocks/factory.go

Lines changed: 59 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

vcr/mongo/create/create.go

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
package create
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"vonage-cloud-runtime-cli/pkg/cmdutil"
7+
8+
"github.com/MakeNowJust/heredoc"
9+
"github.com/spf13/cobra"
10+
)
11+
12+
type Options struct {
13+
cmdutil.Factory
14+
15+
Version string
16+
}
17+
18+
func NewCmdMongoCreate(f cmdutil.Factory) *cobra.Command {
19+
20+
opts := Options{
21+
Factory: f,
22+
}
23+
24+
cmd := &cobra.Command{
25+
Use: "create",
26+
Short: "Create a database and user credentials",
27+
Example: heredoc.Doc(`$ vcr mongo create`),
28+
Args: cobra.MaximumNArgs(0),
29+
RunE: func(cmd *cobra.Command, args []string) error {
30+
ctx, cancel := context.WithDeadline(context.Background(), opts.Deadline())
31+
defer cancel()
32+
33+
return runCreate(ctx, &opts)
34+
},
35+
}
36+
37+
cmd.Flags().StringVarP(&opts.Version, "version", "v", "v0.1", "API version (default is v0.1)")
38+
39+
return cmd
40+
}
41+
42+
func runCreate(ctx context.Context, opts *Options) error {
43+
io := opts.IOStreams()
44+
c := opts.IOStreams().ColorScheme()
45+
46+
spinner := cmdutil.DisplaySpinnerMessageWithHandle(" Creating database")
47+
result, err := opts.DeploymentClient().CreateMongoDatabase(ctx, opts.Version)
48+
spinner.Stop()
49+
if err != nil {
50+
return fmt.Errorf("failed to create database: %w", err)
51+
}
52+
fmt.Fprintf(io.Out, heredoc.Doc(`
53+
%s Database created:
54+
username: %s
55+
password: %s
56+
database: %s
57+
connectionString: %s
58+
`),
59+
c.SuccessIcon(),
60+
result.Username,
61+
result.Password,
62+
result.Database,
63+
result.ConnectionString)
64+
return nil
65+
}

vcr/mongo/create/create_test.go

Lines changed: 117 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,117 @@
1+
package create
2+
3+
import (
4+
"bytes"
5+
"errors"
6+
"io"
7+
"testing"
8+
"vonage-cloud-runtime-cli/pkg/api"
9+
"vonage-cloud-runtime-cli/testutil"
10+
"vonage-cloud-runtime-cli/testutil/mocks"
11+
12+
"github.com/MakeNowJust/heredoc"
13+
"github.com/cli/cli/v2/pkg/iostreams"
14+
"github.com/golang/mock/gomock"
15+
"github.com/google/shlex"
16+
"github.com/stretchr/testify/require"
17+
)
18+
19+
func TestMongoCreate(t *testing.T) {
20+
type mock struct {
21+
CreateTimes int
22+
CreateReturnResponse api.MongoInfoResponse
23+
CreateReturnErr error
24+
CreateVersion string
25+
}
26+
type want struct {
27+
errMsg string
28+
stdout string
29+
}
30+
31+
tests := []struct {
32+
name string
33+
cli string
34+
mock mock
35+
want want
36+
}{
37+
{
38+
name: "happy-path",
39+
cli: "",
40+
mock: mock{
41+
CreateVersion: "v0.1",
42+
CreateTimes: 1,
43+
CreateReturnResponse: api.MongoInfoResponse{
44+
Username: "test",
45+
Password: "test",
46+
Database: "TestDB",
47+
ConnectionString: "mongodb://test:test@localhost:27017/TestDB",
48+
},
49+
CreateReturnErr: nil,
50+
},
51+
want: want{
52+
stdout: heredoc.Doc(`
53+
✓ Database created:
54+
username: test
55+
password: test
56+
database: TestDB
57+
connectionString: mongodb://test:test@localhost:27017/TestDB
58+
`),
59+
},
60+
},
61+
{
62+
name: "create-api-error",
63+
cli: "",
64+
mock: mock{
65+
CreateVersion: "v0.1",
66+
CreateTimes: 1,
67+
CreateReturnResponse: api.MongoInfoResponse{},
68+
CreateReturnErr: errors.New("api error"),
69+
},
70+
want: want{
71+
errMsg: "failed to create database: api error",
72+
},
73+
},
74+
}
75+
76+
for _, tt := range tests {
77+
t.Run(tt.name, func(t *testing.T) {
78+
79+
ctrl := gomock.NewController(t)
80+
81+
deploymentMock := mocks.NewMockDeploymentInterface(ctrl)
82+
deploymentMock.EXPECT().
83+
CreateMongoDatabase(gomock.Any(), tt.mock.CreateVersion).
84+
Times(tt.mock.CreateTimes).
85+
Return(tt.mock.CreateReturnResponse, tt.mock.CreateReturnErr)
86+
87+
ios, _, stdout, stderr := iostreams.Test()
88+
89+
argv, err := shlex.Split(tt.cli)
90+
if err != nil {
91+
t.Fatal(err)
92+
}
93+
94+
f := testutil.DefaultFactoryMock(t, ios, nil, nil, nil, deploymentMock, nil, nil)
95+
96+
cmd := NewCmdMongoCreate(f)
97+
cmd.SetArgs(argv)
98+
cmd.SetIn(&bytes.Buffer{})
99+
cmd.SetOut(io.Discard)
100+
cmd.SetErr(io.Discard)
101+
102+
if _, err := cmd.ExecuteC(); err != nil && tt.want.errMsg != "" {
103+
require.Error(t, err, "should throw error")
104+
require.Equal(t, tt.want.errMsg, err.Error())
105+
return
106+
}
107+
cmdOut := &testutil.CmdOut{
108+
OutBuf: stdout,
109+
ErrBuf: stderr,
110+
}
111+
112+
require.NoError(t, err, "should not throw error")
113+
require.Equal(t, tt.want.stdout, cmdOut.String())
114+
115+
})
116+
}
117+
}

0 commit comments

Comments
 (0)