Skip to content

Commit 5886c46

Browse files
committed
Add tests for executeCommand
1 parent acf1df0 commit 5886c46

File tree

3 files changed

+114
-2
lines changed

3 files changed

+114
-2
lines changed
Lines changed: 107 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,107 @@
1+
import aws.sdk.kotlin.runtime.auth.credentials.executeCommand
2+
import aws.smithy.kotlin.runtime.auth.awscredentials.CredentialsProviderException
3+
import aws.smithy.kotlin.runtime.util.OsFamily
4+
import aws.smithy.kotlin.runtime.util.PlatformProvider
5+
import kotlinx.coroutines.TimeoutCancellationException
6+
import kotlinx.coroutines.test.runTest
7+
import kotlin.test.Test
8+
import kotlin.test.assertEquals
9+
import kotlin.test.assertFailsWith
10+
11+
class ExecuteCommandTest {
12+
val provider = PlatformProvider.System
13+
14+
@Test
15+
fun testExecuteCommand() = runTest {
16+
val command = "echo Hello, World!"
17+
18+
val result = executeCommand(
19+
command = command,
20+
platformProvider = provider,
21+
maxOutputLengthBytes = 1024L,
22+
timeoutMillis = 1000,
23+
)
24+
25+
assertEquals(0, result.first)
26+
assertEquals("Hello, World!\n", result.second)
27+
}
28+
29+
@Test
30+
fun testExecutionTimedOut() = runTest {
31+
assertFailsWith<TimeoutCancellationException> {
32+
executeCommand(
33+
command = "this won't be executed",
34+
platformProvider = provider,
35+
maxOutputLengthBytes = 1024L,
36+
timeoutMillis = 0,
37+
)
38+
}
39+
}
40+
41+
@Test
42+
fun testTooManyBytes() = runTest {
43+
val command = "echo ${"Hello! ".repeat(500)}"
44+
45+
val ex = assertFailsWith<CredentialsProviderException> {
46+
executeCommand(
47+
command = command,
48+
platformProvider = provider,
49+
maxOutputLengthBytes = 1024L,
50+
timeoutMillis = 1000,
51+
)
52+
}
53+
54+
assertEquals("Process output exceeded limit of 1024 bytes", ex.message)
55+
}
56+
57+
@Test
58+
fun testCommandHasQuotes() = runTest {
59+
val command = """echo \"Hello, in quotes!\""""
60+
61+
val result = executeCommand(
62+
command = command,
63+
platformProvider = provider,
64+
maxOutputLengthBytes = 1024L,
65+
timeoutMillis = 1000,
66+
)
67+
68+
assertEquals(0, result.first)
69+
assertEquals(""""Hello, in quotes!"""" + "\n", result.second)
70+
}
71+
72+
@Test
73+
fun testMultipleArgumentCommand() = runTest {
74+
val command = when (provider.osInfo().family) {
75+
OsFamily.Windows -> "powershell -Command \"& {Write-Host 'Arg1'; Write-Host 'Arg2'; Write-Host 'Arg3'}\""
76+
else -> "printf '%s\\n%s\\n%s\\n' 'Arg1' 'Arg2' 'Arg3'"
77+
}
78+
79+
val result = executeCommand(
80+
command = command,
81+
platformProvider = provider,
82+
maxOutputLengthBytes = 1024L,
83+
timeoutMillis = 1000
84+
)
85+
86+
assertEquals(0, result.first)
87+
assertEquals("Arg1\nArg2\nArg3\n", result.second)
88+
}
89+
90+
@Test
91+
fun testErrorReturnsStderr() = runTest {
92+
val errorCommand = when (provider.osInfo().family) {
93+
OsFamily.Windows -> "echo Error message 1>&2 & exit /b 13"
94+
else -> "echo 'Error message' >&2; exit 13"
95+
}
96+
97+
val result = executeCommand(
98+
command = errorCommand,
99+
platformProvider = provider,
100+
maxOutputLengthBytes = 1024L,
101+
timeoutMillis = 1000,
102+
)
103+
104+
assertEquals(13, result.first)
105+
assertEquals("Error message\n", result.second)
106+
}
107+
}

aws-runtime/aws-config/jvm/src/aws/sdk/kotlin/runtime/auth/credentials/executeCommandJVM.kt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,7 +56,7 @@ internal actual suspend fun executeCommand(
5656
val rc = reader.read(buffer)
5757
if (rc == -1) break
5858

59-
output.append(buffer)
59+
output.append(buffer, 0, rc)
6060
if (output.length > maxOutputLengthBytes) {
6161
throw CredentialsProviderException("Process output exceeded limit of $maxOutputLengthBytes bytes")
6262
}

aws-runtime/aws-config/native/src/aws/sdk/kotlin/runtime/auth/credentials/executeCommandNative.kt

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,12 @@ internal actual suspend fun executeCommand(
5252
}
5353

5454
val status = pclose(fp)
55-
status to output
55+
val exitCode = when (platformProvider.osInfo().family) {
56+
OsFamily.Windows -> status // Windows returns the exit code directly
57+
else -> (status shr 8) and 0xFF // Posix systems need to use the WEXITSTATUS macro, this is equivalent
58+
}
59+
60+
exitCode to output
5661
} catch (e: Exception) {
5762
pclose(fp)
5863
throw e

0 commit comments

Comments
 (0)