Skip to content

Commit 1849c53

Browse files
committed
test: refactor SSH integration tests with reusable config and helpers
- Refactor SSH-related integration tests to use a reusable SSHTestConfig struct and a new runSSHContainerTest helper function - Support testing both key-based and password-based authentication by passing configuration via SSHTestConfig - Move duplicated test setup code for containerized SSH server to the helper function - Update assertions to check outputs against configurable expected values for each test - Add test for password-based authentication in addition to existing sudo command test Signed-off-by: appleboy <appleboy.tw@gmail.com>
1 parent 798fc4f commit 1849c53

File tree

1 file changed

+80
-111
lines changed

1 file changed

+80
-111
lines changed

plugin_test.go

Lines changed: 80 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ package main
33
import (
44
"bytes"
55
"context"
6-
"fmt"
76
"io"
87
"os"
98
"reflect"
@@ -915,46 +914,43 @@ func TestAllEnvs(t *testing.T) {
915914
assert.Equal(t, unindent(expected), unindent(buffer.String()))
916915
}
917916

918-
func TestSudoCommand(t *testing.T) {
917+
type SSHTestConfig struct {
918+
Env map[string]string
919+
AuthMethod string // "key" or "password"
920+
KeyPath string
921+
Password string
922+
Script []string
923+
Expected string
924+
SudoAccess bool
925+
InsecureCipher bool
926+
RequireTty bool
927+
CommandTimeout time.Duration
928+
}
929+
930+
func runSSHContainerTest(t *testing.T, cfg SSHTestConfig) {
931+
t.Helper()
919932
ctx := context.Background()
920933

921-
pubKey, err := os.ReadFile("./tests/.ssh/id_rsa.pub")
922-
if err != nil {
923-
t.Fatalf("Could not read public key file: %v", err)
924-
}
925-
// Define the container request using the linuxserver/openssh-server image
926-
// Configure user 'testuser' with password 'testpass'
927934
req := testcontainers.ContainerRequest{
928935
Image: "linuxserver/openssh-server:latest",
929-
ExposedPorts: []string{"2222/tcp"}, // Default port for this image is 2222
930-
Env: map[string]string{
931-
"USER_NAME": "testuser",
932-
"PASSWORD_ACCESS": "false", // Disable password authentication
933-
"SUDO_ACCESS": "true", // Optional: grant sudo access
934-
"PUBLIC_KEY": string(pubKey),
935-
},
936-
// Wait for the SSH port (2222) to be listening
937-
WaitingFor: wait.ForListeningPort("2222/tcp").WithStartupTimeout(180 * time.Second),
936+
ExposedPorts: []string{"2222/tcp"},
937+
Env: cfg.Env,
938+
WaitingFor: wait.ForListeningPort("2222/tcp").WithStartupTimeout(180 * time.Second),
938939
}
939940

940-
// Create and start the container
941941
sshContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
942942
ContainerRequest: req,
943943
Started: true,
944944
})
945-
// Skip test if Docker is not available or container fails to start
946945
if err != nil {
947-
// Provide more context on failure
948946
t.Skipf("Could not start container with image %s: %v. Check Docker environment and image availability. Skipping test.", req.Image, err)
949947
}
950948
defer func() {
951949
if err := sshContainer.Terminate(ctx); err != nil {
952-
// Log termination errors but don't fail the test for this
953950
t.Logf("Could not terminate container: %v", err)
954951
}
955952
}()
956953

957-
// Get the mapped host and port for 2222/tcp
958954
host, err := sshContainer.Host(ctx)
959955
if err != nil {
960956
t.Fatalf("Could not get container host: %v", err)
@@ -963,31 +959,74 @@ func TestSudoCommand(t *testing.T) {
963959
if err != nil {
964960
t.Fatalf("Could not get container mapped port 2222/tcp: %v", err)
965961
}
966-
var (
967-
buffer bytes.Buffer
968-
expected = `
969-
root
970-
`
971-
)
962+
963+
var buffer bytes.Buffer
964+
965+
pluginCfg := Config{
966+
Host: []string{host},
967+
Username: "testuser",
968+
Port: port.Int(),
969+
Script: cfg.Script,
970+
CommandTimeout: cfg.CommandTimeout,
971+
UseInsecureCipher: cfg.InsecureCipher,
972+
RequireTty: cfg.RequireTty,
973+
}
974+
if pluginCfg.CommandTimeout == 0 {
975+
pluginCfg.CommandTimeout = 10 * time.Second
976+
}
977+
if cfg.AuthMethod == "key" {
978+
pluginCfg.KeyPath = cfg.KeyPath
979+
} else if cfg.AuthMethod == "password" {
980+
pluginCfg.Password = cfg.Password
981+
}
972982

973983
plugin := Plugin{
974-
Config: Config{
975-
Host: []string{host},
976-
Username: "testuser", // Use the configured username
977-
Port: port.Int(), // Use the mapped port
978-
KeyPath: "./tests/.ssh/id_rsa",
979-
Script: []string{
980-
`sudo su - -c "whoami"`,
981-
},
982-
CommandTimeout: 10 * time.Second,
983-
RequireTty: true,
984-
UseInsecureCipher: true, // Allow insecure ciphers for compatibility
985-
},
984+
Config: pluginCfg,
986985
Writer: &buffer,
987986
}
988987

989988
assert.Nil(t, plugin.Exec())
990-
assert.Equal(t, unindent(expected), unindent(buffer.String()))
989+
assert.Equal(t, unindent(cfg.Expected), unindent(buffer.String()))
990+
}
991+
992+
func TestSudoCommand(t *testing.T) {
993+
pubKey, err := os.ReadFile("./tests/.ssh/id_rsa.pub")
994+
if err != nil {
995+
t.Fatalf("Could not read public key file: %v", err)
996+
}
997+
runSSHContainerTest(t, SSHTestConfig{
998+
Env: map[string]string{
999+
"USER_NAME": "testuser",
1000+
"PASSWORD_ACCESS": "false",
1001+
"SUDO_ACCESS": "true",
1002+
"PUBLIC_KEY": string(pubKey),
1003+
},
1004+
AuthMethod: "key",
1005+
KeyPath: "./tests/.ssh/id_rsa",
1006+
Script: []string{`sudo su - -c "whoami"`},
1007+
Expected: "root",
1008+
SudoAccess: true,
1009+
InsecureCipher: true,
1010+
RequireTty: true,
1011+
CommandTimeout: 10 * time.Second,
1012+
})
1013+
}
1014+
1015+
func TestSSHWithTestcontainers(t *testing.T) {
1016+
runSSHContainerTest(t, SSHTestConfig{
1017+
Env: map[string]string{
1018+
"USER_NAME": "testuser",
1019+
"USER_PASSWORD": "testpass",
1020+
"PASSWORD_ACCESS": "true",
1021+
"SUDO_ACCESS": "false",
1022+
},
1023+
AuthMethod: "password",
1024+
Password: "testpass",
1025+
Script: []string{"whoami"},
1026+
Expected: "testuser",
1027+
InsecureCipher: true,
1028+
CommandTimeout: 60 * time.Second,
1029+
})
9911030
}
9921031

9931032
func TestCommandWithIPv6(t *testing.T) {
@@ -1015,73 +1054,3 @@ func TestCommandWithIPv6(t *testing.T) {
10151054
assert.Nil(t, plugin.Exec())
10161055
assert.Equal(t, unindent(expected), unindent(buffer.String()))
10171056
}
1018-
1019-
func TestSSHWithTestcontainers(t *testing.T) {
1020-
ctx := context.Background()
1021-
1022-
// Define the container request using the linuxserver/openssh-server image
1023-
// Configure user 'testuser' with password 'testpass'
1024-
req := testcontainers.ContainerRequest{
1025-
Image: "linuxserver/openssh-server:latest",
1026-
ExposedPorts: []string{"2222/tcp"}, // Default port for this image is 2222
1027-
Env: map[string]string{
1028-
"USER_NAME": "testuser",
1029-
"USER_PASSWORD": "testpass",
1030-
"PASSWORD_ACCESS": "true", // Enable password authentication
1031-
"SUDO_ACCESS": "false", // Optional: grant sudo access
1032-
},
1033-
// Wait for the SSH port (2222) to be listening
1034-
WaitingFor: wait.ForListeningPort("2222/tcp").WithStartupTimeout(180 * time.Second),
1035-
}
1036-
1037-
// Create and start the container
1038-
sshContainer, err := testcontainers.GenericContainer(ctx, testcontainers.GenericContainerRequest{
1039-
ContainerRequest: req,
1040-
Started: true,
1041-
})
1042-
// Skip test if Docker is not available or container fails to start
1043-
if err != nil {
1044-
// Provide more context on failure
1045-
t.Skipf("Could not start container with image %s: %v. Check Docker environment and image availability. Skipping test.", req.Image, err)
1046-
}
1047-
defer func() {
1048-
if err := sshContainer.Terminate(ctx); err != nil {
1049-
// Log termination errors but don't fail the test for this
1050-
t.Logf("Could not terminate container: %v", err)
1051-
}
1052-
}()
1053-
1054-
// Get the mapped host and port for 2222/tcp
1055-
host, err := sshContainer.Host(ctx)
1056-
if err != nil {
1057-
t.Fatalf("Could not get container host: %v", err)
1058-
}
1059-
port, err := sshContainer.MappedPort(ctx, "2222/tcp")
1060-
if err != nil {
1061-
t.Fatalf("Could not get container mapped port 2222/tcp: %v", err)
1062-
}
1063-
1064-
var buffer bytes.Buffer
1065-
expected := `testuser` // The user we configured
1066-
1067-
plugin := Plugin{
1068-
Config: Config{
1069-
Host: []string{host},
1070-
Username: "testuser", // Use the configured username
1071-
Port: port.Int(), // Use the mapped port
1072-
Password: "testpass", // Use the configured password
1073-
Script: []string{"whoami"},
1074-
CommandTimeout: 60 * time.Second,
1075-
UseInsecureCipher: true, // Allow insecure ciphers for compatibility
1076-
},
1077-
Writer: &buffer,
1078-
}
1079-
1080-
t.Logf("Attempting SSH connection to %s:%d as user %s", host, port.Int(), plugin.Config.Username)
1081-
err = plugin.Exec()
1082-
t.Logf("SSH command output: %s", buffer.String())
1083-
t.Logf("SSH command error: %v", err)
1084-
1085-
assert.Nil(t, err, fmt.Sprintf("plugin.Exec failed: %v", err))
1086-
assert.Equal(t, unindent(expected), unindent(buffer.String()))
1087-
}

0 commit comments

Comments
 (0)