mirror of
https://github.com/LukeHagar/sailpoint-cli.git
synced 2025-12-06 04:21:15 +00:00
PLTCONN-2935: More tests & mock out terminal for unit tests
This commit is contained in:
3
Makefile
3
Makefile
@@ -5,7 +5,8 @@ clean:
|
||||
.PHONY: mocks
|
||||
mocks:
|
||||
# Ref: https://github.com/golang/mock
|
||||
mockgen -source=client/client.go -destination=mocks/client.go -package=mocks
|
||||
mockgen -source=internal/client/client.go -destination=internal/mocks/client.go -package=mocks
|
||||
mockgen -source=internal/terminal/terminal.go -destination=internal/mocks/terminal.go -package=mocks
|
||||
|
||||
.PHONY: test
|
||||
test:
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewConfigureCmd() *cobra.Command {
|
||||
func NewConfigureCmd(term terminal.Terminal) *cobra.Command {
|
||||
var ClientID string
|
||||
var ClientSecret string
|
||||
var err error
|
||||
@@ -20,7 +20,7 @@ func NewConfigureCmd() *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
|
||||
if ClientID == "" {
|
||||
ClientID, err = terminal.PromptPassword("Personal Access Token Client ID:")
|
||||
ClientID, err = term.PromptPassword("Personal Access Token Client ID:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -29,7 +29,7 @@ func NewConfigureCmd() *cobra.Command {
|
||||
config.SetPatClientID(ClientID)
|
||||
|
||||
if ClientSecret == "" {
|
||||
ClientSecret, err = terminal.PromptPassword("Personal Access Token Client Secret:")
|
||||
ClientSecret, err = term.PromptPassword("Personal Access Token Client Secret:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/client"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/config"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
"github.com/spf13/pflag"
|
||||
"gopkg.in/yaml.v2"
|
||||
@@ -18,7 +19,7 @@ const (
|
||||
connectorsEndpoint = "/beta/platform-connectors"
|
||||
)
|
||||
|
||||
func NewConnCmd() *cobra.Command {
|
||||
func NewConnCmd(term terminal.Terminal) *cobra.Command {
|
||||
conn := &cobra.Command{
|
||||
Use: "connectors",
|
||||
Short: "manage connectors",
|
||||
@@ -45,7 +46,7 @@ func NewConnCmd() *cobra.Command {
|
||||
newConnCreateCmd(Client),
|
||||
newConnCreateVersionCmd(Client),
|
||||
newConnVersionsCmd(Client),
|
||||
newConnInvokeCmd(Client),
|
||||
newConnInvokeCmd(Client, term),
|
||||
newConnValidateCmd(Client),
|
||||
newConnTagCmd(Client),
|
||||
newConnValidateSourcesCmd(Client),
|
||||
|
||||
@@ -9,6 +9,7 @@ import (
|
||||
|
||||
connclient "github.com/sailpoint-oss/sailpoint-cli/cmd/connector/client"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/client"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -23,7 +24,7 @@ const (
|
||||
stdTestConnection = "std:test-connection"
|
||||
)
|
||||
|
||||
func newConnInvokeCmd(client client.Client) *cobra.Command {
|
||||
func newConnInvokeCmd(client client.Client, term terminal.Terminal) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "invoke",
|
||||
Short: "Invoke Command on a connector",
|
||||
@@ -42,7 +43,7 @@ func newConnInvokeCmd(client client.Client) *cobra.Command {
|
||||
|
||||
cmd.AddCommand(
|
||||
newConnInvokeTestConnectionCmd(client),
|
||||
newConnInvokeChangePasswordCmd(client),
|
||||
newConnInvokeChangePasswordCmd(client, term),
|
||||
newConnInvokeAccountCreateCmd(client),
|
||||
newConnInvokeAccountDiscoverSchemaCmd(client),
|
||||
newConnInvokeAccountListCmd(client),
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
)
|
||||
|
||||
// newConnInvokeChangePasswordCmd defines a command to perform change password operation
|
||||
func newConnInvokeChangePasswordCmd(spClient client.Client) *cobra.Command {
|
||||
func newConnInvokeChangePasswordCmd(spClient client.Client, term terminal.Terminal) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "change-password",
|
||||
Short: "Invoke a change-password command",
|
||||
@@ -24,7 +24,7 @@ func newConnInvokeChangePasswordCmd(spClient client.Client) *cobra.Command {
|
||||
return err
|
||||
}
|
||||
|
||||
password, err := terminal.PromptPassword("Enter Password:")
|
||||
password, err := term.PromptPassword("Enter Password:")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
92
cmd/connector/conn_invoke_change_password_test.go
Normal file
92
cmd/connector/conn_invoke_change_password_test.go
Normal file
@@ -0,0 +1,92 @@
|
||||
// Copyright (c) 2023, SailPoint Technologies, Inc. All rights reserved.
|
||||
package connector
|
||||
|
||||
import (
|
||||
"bytes"
|
||||
"io"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/golang/mock/gomock"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/mocks"
|
||||
)
|
||||
|
||||
func TestChangePasswordWithoutInput(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
client := mocks.NewMockClient(ctrl)
|
||||
term := mocks.NewMockTerm(ctrl)
|
||||
|
||||
cmd := newConnInvokeChangePasswordCmd(client, term)
|
||||
addRequiredFlagsFromParentCmd(cmd)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
cmd.SetOut(b)
|
||||
cmd.SetArgs([]string{"-c", "test-connector", "--config-json", "{}"})
|
||||
|
||||
err := cmd.Execute()
|
||||
if err == nil {
|
||||
t.Errorf("failed to detect error: reading account without identity")
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangePasswordWithIdentityAndPassword(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
i := `{"connectorRef":"test-connector","tag":"latest","type":"std:change-password","config":{},` +
|
||||
`"input":{"identity":"john.doe","key":{"simple":{"id":"john.doe"}},"password":"password"}}`
|
||||
|
||||
client := mocks.NewMockClient(ctrl)
|
||||
client.EXPECT().
|
||||
Post(gomock.Any(), gomock.Any(), "application/json", bytes.NewReader([]byte(i))).
|
||||
Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("{}")))}, nil)
|
||||
|
||||
term := mocks.NewMockTerm(ctrl)
|
||||
term.EXPECT().
|
||||
PromptPassword(gomock.Any()).
|
||||
Return("password", nil)
|
||||
|
||||
cmd := newConnInvokeChangePasswordCmd(client, term)
|
||||
addRequiredFlagsFromParentCmd(cmd)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
cmd.SetOut(b)
|
||||
cmd.SetArgs([]string{"john.doe", "-c", "test-connector", "--config-json", "{}"})
|
||||
|
||||
err := cmd.Execute()
|
||||
if err != nil {
|
||||
t.Errorf("command failed with err: %s", err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestChangePasswordWithIdentityAndPasswordAndUniqueId(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
i := `{"connectorRef":"test-connector","tag":"latest","type":"std:change-password","config":{},` +
|
||||
`"input":{"identity":"john.doe","key":{"compound":{"lookupId":"john.doe","uniqueId":"12345"}},"password":"password"}}`
|
||||
|
||||
client := mocks.NewMockClient(ctrl)
|
||||
client.EXPECT().
|
||||
Post(gomock.Any(), gomock.Any(), "application/json", bytes.NewReader([]byte(i))).
|
||||
Return(&http.Response{StatusCode: http.StatusOK, Body: io.NopCloser(bytes.NewReader([]byte("{}")))}, nil)
|
||||
|
||||
term := mocks.NewMockTerm(ctrl)
|
||||
term.EXPECT().
|
||||
PromptPassword(gomock.Any()).
|
||||
Return("password", nil)
|
||||
|
||||
cmd := newConnInvokeChangePasswordCmd(client, term)
|
||||
addRequiredFlagsFromParentCmd(cmd)
|
||||
|
||||
b := new(bytes.Buffer)
|
||||
cmd.SetOut(b)
|
||||
cmd.SetArgs([]string{"john.doe", "12345", "-c", "test-connector", "--config-json", "{}"})
|
||||
|
||||
err := cmd.Execute()
|
||||
if err != nil {
|
||||
t.Errorf("command failed with err: %s", err)
|
||||
}
|
||||
}
|
||||
@@ -24,7 +24,7 @@ func TestNewConnInvokeCmd_noArgs(t *testing.T) {
|
||||
ctrl := gomock.NewController(t)
|
||||
defer ctrl.Finish()
|
||||
|
||||
cmd := newConnInvokeCmd(mocks.NewMockClient(ctrl))
|
||||
cmd := newConnInvokeCmd(mocks.NewMockClient(ctrl), mocks.NewMockTerm(ctrl))
|
||||
if len(cmd.Commands()) != numConnInvokeSubcommands {
|
||||
t.Fatalf("expected: %d, actual: %d", len(cmd.Commands()), numConnInvokeSubcommands)
|
||||
}
|
||||
|
||||
@@ -13,6 +13,7 @@ import (
|
||||
"github.com/sailpoint-oss/sailpoint-cli/cmd/spconfig"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/cmd/transform"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/cmd/va"
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
@@ -34,13 +35,15 @@ func NewRootCmd() *cobra.Command {
|
||||
},
|
||||
}
|
||||
|
||||
t := &terminal.Term{}
|
||||
|
||||
root.AddCommand(
|
||||
set.NewSetCommand(),
|
||||
environment.NewEnvironmentCommand(),
|
||||
configure.NewConfigureCmd(),
|
||||
connector.NewConnCmd(),
|
||||
configure.NewConfigureCmd(t),
|
||||
connector.NewConnCmd(t),
|
||||
transform.NewTransformCmd(),
|
||||
va.NewVACmd(),
|
||||
va.NewVACmd(t),
|
||||
search.NewSearchCmd(),
|
||||
spconfig.NewSPConfigCmd(),
|
||||
report.NewReportCommand(),
|
||||
|
||||
@@ -11,7 +11,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newCollectCmd() *cobra.Command {
|
||||
func newCollectCmd(term terminal.Terminal) *cobra.Command {
|
||||
var output string
|
||||
var logs bool
|
||||
var config bool
|
||||
@@ -37,7 +37,7 @@ func newCollectCmd() *cobra.Command {
|
||||
}
|
||||
|
||||
for credential := 0; credential < len(args); credential++ {
|
||||
password, _ := terminal.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
password, _ := term.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
credentials = append(credentials, password)
|
||||
}
|
||||
|
||||
|
||||
@@ -13,7 +13,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewTroubleshootCmd() *cobra.Command {
|
||||
func NewTroubleshootCmd(term terminal.Terminal) *cobra.Command {
|
||||
var output string
|
||||
cmd := &cobra.Command{
|
||||
Use: "troubleshoot",
|
||||
@@ -29,7 +29,7 @@ func NewTroubleshootCmd() *cobra.Command {
|
||||
|
||||
var credentials []string
|
||||
for credential := 0; credential < len(args); credential++ {
|
||||
password, _ := terminal.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
password, _ := term.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
credentials = append(credentials, password)
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func newUpdateCmd() *cobra.Command {
|
||||
func newUpdateCmd(term terminal.Terminal) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "update",
|
||||
Short: "Perform Update Operations on a SailPoint Virtual Appliance",
|
||||
@@ -19,7 +19,7 @@ func newUpdateCmd() *cobra.Command {
|
||||
RunE: func(cmd *cobra.Command, args []string) error {
|
||||
var credentials []string
|
||||
for credential := 0; credential < len(args); credential++ {
|
||||
password, _ := terminal.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
password, _ := term.PromptPassword(fmt.Sprintf("Enter Password for %v:", args[credential]))
|
||||
credentials = append(credentials, password)
|
||||
}
|
||||
for i := 0; i < len(args); i++ {
|
||||
|
||||
@@ -4,10 +4,11 @@ package va
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
"github.com/sailpoint-oss/sailpoint-cli/internal/terminal"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
func NewVACmd() *cobra.Command {
|
||||
func NewVACmd(term terminal.Terminal) *cobra.Command {
|
||||
cmd := &cobra.Command{
|
||||
Use: "va",
|
||||
Short: "Interact with SailPoint Virtual Appliances",
|
||||
@@ -19,9 +20,9 @@ func NewVACmd() *cobra.Command {
|
||||
}
|
||||
|
||||
cmd.AddCommand(
|
||||
newCollectCmd(),
|
||||
newCollectCmd(term),
|
||||
// newTroubleshootCmd(),
|
||||
newUpdateCmd(),
|
||||
newUpdateCmd(term),
|
||||
newParseCmd(),
|
||||
)
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: client/client.go
|
||||
// Source: internal/client/client.go
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
@@ -95,17 +95,3 @@ func (mr *MockClientMockRecorder) Put(ctx, url, contentType, body interface{}) *
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "Put", reflect.TypeOf((*MockClient)(nil).Put), ctx, url, contentType, body)
|
||||
}
|
||||
|
||||
// VerifyToken mocks base method.
|
||||
func (m *MockClient) VerifyToken(ctx context.Context, tokenUrl, clientID, secret string) error {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "VerifyToken", ctx, tokenUrl, clientID, secret)
|
||||
ret0, _ := ret[0].(error)
|
||||
return ret0
|
||||
}
|
||||
|
||||
// VerifyToken indicates an expected call of VerifyToken.
|
||||
func (mr *MockClientMockRecorder) VerifyToken(ctx, tokenUrl, clientID, secret interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "VerifyToken", reflect.TypeOf((*MockClient)(nil).VerifyToken), ctx, tokenUrl, clientID, secret)
|
||||
}
|
||||
|
||||
49
internal/mocks/terminal.go
Normal file
49
internal/mocks/terminal.go
Normal file
@@ -0,0 +1,49 @@
|
||||
// Code generated by MockGen. DO NOT EDIT.
|
||||
// Source: internal/terminal/terminal.go
|
||||
|
||||
// Package mocks is a generated GoMock package.
|
||||
package mocks
|
||||
|
||||
import (
|
||||
reflect "reflect"
|
||||
|
||||
gomock "github.com/golang/mock/gomock"
|
||||
)
|
||||
|
||||
// MockTerm is a mock of Term interface.
|
||||
type MockTerm struct {
|
||||
ctrl *gomock.Controller
|
||||
recorder *MockTermMockRecorder
|
||||
}
|
||||
|
||||
// MockTermMockRecorder is the mock recorder for MockTerm.
|
||||
type MockTermMockRecorder struct {
|
||||
mock *MockTerm
|
||||
}
|
||||
|
||||
// NewMockTerm creates a new mock instance.
|
||||
func NewMockTerm(ctrl *gomock.Controller) *MockTerm {
|
||||
mock := &MockTerm{ctrl: ctrl}
|
||||
mock.recorder = &MockTermMockRecorder{mock}
|
||||
return mock
|
||||
}
|
||||
|
||||
// EXPECT returns an object that allows the caller to indicate expected use.
|
||||
func (m *MockTerm) EXPECT() *MockTermMockRecorder {
|
||||
return m.recorder
|
||||
}
|
||||
|
||||
// PromptPassword mocks base method.
|
||||
func (m *MockTerm) PromptPassword(promptMsg string) (string, error) {
|
||||
m.ctrl.T.Helper()
|
||||
ret := m.ctrl.Call(m, "PromptPassword", promptMsg)
|
||||
ret0, _ := ret[0].(string)
|
||||
ret1, _ := ret[1].(error)
|
||||
return ret0, ret1
|
||||
}
|
||||
|
||||
// PromptPassword indicates an expected call of PromptPassword.
|
||||
func (mr *MockTermMockRecorder) PromptPassword(promptMsg interface{}) *gomock.Call {
|
||||
mr.mock.ctrl.T.Helper()
|
||||
return mr.mock.ctrl.RecordCallWithMethodType(mr.mock, "PromptPassword", reflect.TypeOf((*MockTerm)(nil).PromptPassword), promptMsg)
|
||||
}
|
||||
@@ -11,8 +11,14 @@ import (
|
||||
"golang.org/x/term"
|
||||
)
|
||||
|
||||
type Term struct{}
|
||||
|
||||
type Terminal interface {
|
||||
PromptPassword(promptMsg string) (string, error)
|
||||
}
|
||||
|
||||
// PromptPassword prompts user to enter password and then returns it
|
||||
func PromptPassword(promptMsg string) (string, error) {
|
||||
func (c *Term) PromptPassword(promptMsg string) (string, error) {
|
||||
fmt.Print(promptMsg)
|
||||
bytePassword, err := term.ReadPassword(int(syscall.Stdin))
|
||||
if err != nil {
|
||||
|
||||
Reference in New Issue
Block a user