11package cdk
22
33import (
4+ "bytes"
45 "fmt"
6+ "io"
57 "os"
68 "os/exec"
9+ "strings"
710 "testing"
811
912 iomocks "github.com/aws/amazon-genomics-cli/internal/pkg/mocks/io"
@@ -14,10 +17,15 @@ import (
1417)
1518
1619const (
17- testExecuteCommandSuccessArg = "test-execute-command-success-arg"
18- testExecuteCommandFailureArg = "test-execute-command-failure-arg"
19- testExecuteExecutioName = "test-key"
20- testExecuteCommandProgressLine = "Agc-Context-Demo-yy110HKO4J-ctx1 | 3/10 | 3:22:16 PM | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | Agc-Context-Demo-yy110HKO4J-ctx1 User Initiated"
20+ testExecuteCommandSuccessArg = "test-execute-command-success-arg"
21+ testExecuteCommandMultilineArg = "test-execute-command-multiline-arg"
22+ testExecuteCommandPromptArg = "test-execute-command-prompt-arg"
23+ testExecuteCommandFailureArg = "test-execute-command-failure-arg"
24+ testExecuteExecutioName = "test-key"
25+ testExecuteCommandProgressLine = "Agc-Context-Demo-yy110HKO4J-ctx1 | 3/10 | 3:22:16 PM | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | Agc-Context-Demo-yy110HKO4J-ctx1 User Initiated"
26+ testExecuteCommandProgressLine2 = "Agc-Context-Demo-yy110HKO4J-ctx1 | 4/10 | 3:23:16 PM | REVIEW_IN_PROGRESS | AWS::CloudFormation::Stack | Agc-Context-Demo-yy110HKO4J-ctx1 User Initiated"
27+ testExecuteCodePrompt = "\n MFA token for arn:something-or-other: \n \n "
28+ testExecuteCode = "31337"
2129)
2230
2331func fakeExecCommand (command string , args ... string ) * exec.Cmd {
@@ -33,6 +41,8 @@ type ExecuteCdkCommandTestSuite struct {
3341
3442 osRemoveAllOrig func (string ) error
3543 execCommandOrig func (command string , args ... string ) * exec.Cmd
44+ mfaInputOrig io.Reader
45+ mfaOutputOrig io.Writer
3646
3747 ctrl * gomock.Controller
3848 mockOs * iomocks.MockOS
@@ -49,9 +59,14 @@ func (s *ExecuteCdkCommandTestSuite) SetupTest() {
4959 s .mockOs = iomocks .NewMockOS (s .ctrl )
5060 s .osRemoveAllOrig = osRemoveAll
5161 s .execCommandOrig = execCommand
62+ s .mfaInputOrig = mfaInput
63+ s .mfaOutputOrig = mfaOutput
5264
5365 osRemoveAll = s .mockOs .RemoveAll
5466 execCommand = fakeExecCommand
67+ // mfaInput and mfaOutput will be overwritten by the tests that need them.
68+ // If we use real pipes here it's too easy for us to deadlock when the code
69+ // under test misbehaves.
5570
5671 s .appDir = s .T ().TempDir ()
5772 s .tmpDir = "/test/tmp/dir"
@@ -64,6 +79,8 @@ func (s *ExecuteCdkCommandTestSuite) AfterTest(_, _ string) {
6479func (s * ExecuteCdkCommandTestSuite ) TearDownTest () {
6580 osRemoveAll = s .osRemoveAllOrig
6681 execCommand = s .execCommandOrig
82+ mfaInput = s .mfaInputOrig
83+ mfaOutput = s .mfaOutputOrig
6784}
6885
6986func (s * ExecuteCdkCommandTestSuite ) TestExecuteCdkCommand_Success () {
@@ -81,6 +98,51 @@ func (s *ExecuteCdkCommandTestSuite) TestExecuteCdkCommand_Success() {
8198 waitForChanToClose (progressStream )
8299}
83100
101+ func (s * ExecuteCdkCommandTestSuite ) TestExecuteCdkCommand_Multiline () {
102+ s .mockOs .EXPECT ().RemoveAll (gomock .Any ()).Return (nil ).Times (0 )
103+
104+ progressStream , err := executeCdkCommand (s .appDir , []string {testExecuteCommandMultilineArg }, testExecuteExecutioName )
105+ s .Require ().NoError (err )
106+ event1 := <- progressStream
107+ s .Assert ().Equal (3 , event1 .CurrentStep )
108+ s .Assert ().Equal (10 , event1 .TotalSteps )
109+ s .Assert ().Equal (testExecuteCommandProgressLine , event1 .Outputs [0 ])
110+ s .Assert ().Equal (testExecuteExecutioName , event1 .ExecutionName )
111+ event2 := <- progressStream
112+ s .Assert ().Equal (4 , event2 .CurrentStep )
113+ s .Assert ().Equal (10 , event2 .TotalSteps )
114+ // Lines should accumulate into Outputs
115+ s .Assert ().Equal (testExecuteCommandProgressLine , event2 .Outputs [0 ])
116+ s .Assert ().Equal (testExecuteCommandProgressLine2 , event2 .Outputs [1 ])
117+ s .Assert ().Equal (testExecuteExecutioName , event2 .ExecutionName )
118+ event3 := <- progressStream
119+ s .Assert ().NoError (event3 .Err )
120+ waitForChanToClose (progressStream )
121+ }
122+
123+ func (s * ExecuteCdkCommandTestSuite ) TestExecuteCdkCommand_Prompt () {
124+ s .mockOs .EXPECT ().RemoveAll (gomock .Any ()).Return (nil ).Times (0 )
125+
126+ // Prepare the input the test expects to see typed
127+ toType := testExecuteCode + "\n "
128+ mfaInput = strings .NewReader (toType )
129+ // And somewhere to put the prompt
130+ var promptBuffer bytes.Buffer
131+ mfaOutput = & promptBuffer
132+
133+ progressStream , err := executeCdkCommand (s .appDir , []string {testExecuteCommandPromptArg }, testExecuteExecutioName )
134+ s .Require ().NoError (err )
135+ event1 := <- progressStream
136+ s .Assert ().Equal ("Waiting for MFA..." , event1 .StepDescription )
137+ // Prompt goes into the pipe before the event. So check it.
138+ s .Assert ().Equal (testExecuteCodePrompt , promptBuffer .String ())
139+ // Code is already waiting to be read when we start.
140+ // It shold continue.
141+ event2 := <- progressStream
142+ s .Assert ().NoError (event2 .Err )
143+ waitForChanToClose (progressStream )
144+ }
145+
84146func (s * ExecuteCdkCommandTestSuite ) TestExecuteCdkCommandAndCleanupDirectory_Success () {
85147 s .mockOs .EXPECT ().RemoveAll (s .tmpDir ).Return (nil ).Times (1 )
86148
@@ -153,15 +215,35 @@ func TestHelperProcess(t *testing.T) {
153215 testArg := args [4 ]
154216 switch testArg {
155217 case testExecuteCommandSuccessArg :
156- fmt .Fprint (os .Stdout , "some line" )
157- fmt .Fprint (os .Stderr , testExecuteCommandProgressLine )
218+ fmt .Fprintln (os .Stdout , "some line" )
219+ fmt .Fprintln (os .Stderr , testExecuteCommandProgressLine )
220+ os .Exit (0 )
221+ case testExecuteCommandMultilineArg :
222+ fmt .Fprintln (os .Stdout , "some line" )
223+ fmt .Fprintln (os .Stderr , testExecuteCommandProgressLine )
224+ fmt .Fprintln (os .Stdout , "another line" )
225+ fmt .Fprintln (os .Stderr , testExecuteCommandProgressLine2 )
226+ os .Exit (0 )
227+ case testExecuteCommandPromptArg :
228+ // Because the stdout and stderr streams are different, the order in
229+ // which they feed into the event-generation logic is nondeterministic,
230+ // so we make sure to only do the MFA prompt here (and not any progress
231+ // likes to stderr), because otherwise the test wouldn't be able to
232+ // predict what order it would see events in, and would then be hard to
233+ // write.
234+ fmt .Fprint (os .Stdout , testExecuteCodePrompt )
235+ var reply string
236+ fmt .Scanln (& reply )
237+ if reply != testExecuteCode {
238+ os .Exit (1 )
239+ }
158240 os .Exit (0 )
159241 case testExecuteCommandFailureArg :
160- fmt .Fprint (os .Stdout , "some line" )
161- fmt .Fprint (os .Stderr , testExecuteCommandFailureArg )
242+ fmt .Fprintln (os .Stdout , "some line" )
243+ fmt .Fprintln (os .Stderr , testExecuteCommandFailureArg )
162244 os .Exit (1 )
163245 default :
164- fmt .Fprint (os .Stderr , "Unknown failure" )
246+ fmt .Fprintln (os .Stderr , "Unknown failure" )
165247 os .Exit (1 )
166248 }
167249}
0 commit comments