Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
139 changes: 139 additions & 0 deletions ssh_shell_command_executor_using_sshj/pom.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,139 @@
<?xml version="1.0" encoding="UTF-8"?>
<project
xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<groupId>com.testsigma.addons</groupId>
<artifactId>ssh_shell_command_executor_using_sshj</artifactId>
<version>1.0.1</version>
<packaging>jar</packaging>

<properties>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<testsigma.sdk.version>1.2.24_cloud</testsigma.sdk.version>
<junit.jupiter.version>5.8.0-M1</junit.jupiter.version>
<testsigma.addon.maven.plugin>1.0.0</testsigma.addon.maven.plugin>
<maven.source.plugin.version>3.2.1</maven.source.plugin.version>
<lombok.version>1.18.30</lombok.version>

</properties>

<dependencies>
<dependency>
<groupId>com.testsigma</groupId>
<artifactId>testsigma-java-sdk</artifactId>
<version>${testsigma.sdk.version}</version>
</dependency>
<dependency>
<groupId>org.projectlombok</groupId>
<artifactId>lombok</artifactId>
<version>${lombok.version}</version>
<optional>true</optional>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>${junit.jupiter.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.testng</groupId>
<artifactId>testng</artifactId>
<version>6.14.3</version>
</dependency>
<!-- https://mvnrepository.com/artifact/org.seleniumhq.selenium/selenium-java -->
<dependency>
<groupId>org.seleniumhq.selenium</groupId>
<artifactId>selenium-java</artifactId>
<version>4.33.0</version>
</dependency>
<!-- https://mvnrepository.com/artifact/io.appium/java-client -->
<dependency>
<groupId>io.appium</groupId>
<artifactId>java-client</artifactId>
<version>9.4.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.13.0</version>
</dependency>


<!-- SSHJ - alternative SSH library for command execution -->
<dependency>
<groupId>com.hierynomus</groupId>
<artifactId>sshj</artifactId>
<version>0.38.0</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>3.14.0</version>
</dependency>

<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.12.3</version> <!-- Make sure to use the latest version -->
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>httpclient</artifactId>
<version>4.5.13</version>
</dependency>
<dependency>
<groupId>org.apache.poi</groupId>
<artifactId>poi</artifactId>
<version>5.2.4</version>
</dependency>

</dependencies>
<build>
<finalName>ssh_shell_command_executor_using_sshj</finalName>
<plugins>
<plugin>
<configuration>
<minimizeJar>true</minimizeJar>
<filters>
<filter>
<artifact>*:*</artifact>
<excludes>
<exclude>META-INF/*.SF</exclude>
<exclude>META-INF/*.DSA</exclude>
<exclude>META-INF/*.RSA</exclude>
</excludes>
</filter>
</filters>
</configuration>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-shade-plugin</artifactId>
<version>3.2.4</version>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>shade</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>${maven.source.plugin.version}</version>
<executions>
<execution>
<id>attach-sources</id>
<goals>
<goal>jar</goal>
</goals>
</execution>
</executions>
</plugin>
</plugins>
</build>
</project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,149 @@
package com.testsigma.addons.android;

import com.testsigma.addons.util.ImageComparisonUtils;
import com.testsigma.addons.util.StringToImageConverter;
import com.testsigma.sdk.ApplicationType;
import com.testsigma.sdk.AndroidAction;
import com.testsigma.sdk.Result;
import com.testsigma.sdk.annotation.Action;
import com.testsigma.sdk.annotation.RunTimeData;
import com.testsigma.sdk.annotation.TestData;
import com.testsigma.sdk.annotation.TestStepResult;
import lombok.Data;
import lombok.EqualsAndHashCode;
import net.schmizz.sshj.SSHClient;
import net.schmizz.sshj.connection.channel.direct.Session;
import net.schmizz.sshj.connection.channel.direct.Session.Command;
import net.schmizz.sshj.transport.verification.PromiscuousVerifier;
import org.apache.commons.lang3.exception.ExceptionUtils;
import org.openqa.selenium.NoSuchElementException;

import java.io.File;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.concurrent.TimeUnit;

@Data
@EqualsAndHashCode(callSuper = false)
@Action(actionText = "SSHJ: Connect to SSH server and execute commands, SSH server details: Host: Host-Name,"
+ " Port: Port-Number, UserName: User-Name, Password: User-Password, Commands: Terminal-Commands ,"
+ " Command Separator: Command-Separator , Store Output Variable: Variable-Name",
description = "Executes commands on an SSH server using the SSHJ library (alternative implementation). "
+ "This action connects via SSH, runs the given commands in a login shell, and stores the output in a variable.",
applicationType = ApplicationType.ANDROID,
displayName = "SSHJ: Connect to SSH server and execute commands",
useCustomScreenshot = true)
public class SSHCommandExecutionSSHJ extends AndroidAction {

@TestStepResult
private com.testsigma.sdk.TestStepResult testStepResult;

@TestData(reference = "Host-Name")
private com.testsigma.sdk.TestData hostName;
@TestData(reference = "Port-Number")
private com.testsigma.sdk.TestData portNumber;
@TestData(reference = "User-Name")
private com.testsigma.sdk.TestData userName;
@TestData(reference = "User-Password")
private com.testsigma.sdk.TestData userPassword;
@TestData(reference = "Terminal-Commands")
private com.testsigma.sdk.TestData commands;
@TestData(reference = "Command-Separator")
private com.testsigma.sdk.TestData commandSeparator;
@TestData(reference = "Variable-Name")
private com.testsigma.sdk.TestData storeVariable;

@RunTimeData
private com.testsigma.sdk.RunTimeData runTimeData;

@Override
public Result execute() throws NoSuchElementException {
logger.info("Initiating execution (SSHJ) - Android");

String user = userName.getValue().toString();
String host = hostName.getValue().toString();
String password = userPassword.getValue().toString();
int port = Integer.parseInt(portNumber.getValue().toString());
String commandSeparatorStr = commandSeparator != null && !commandSeparator.getValue().toString().isEmpty()
? commandSeparator.getValue().toString()
: "&&";
String allCommands = commands.getValue().toString().replace(commandSeparatorStr, "&&");

String wrappedCommand = wrapInLoginShell(allCommands);

SSHClient ssh = null;
Session session = null;

try {
ssh = new SSHClient();
ssh.addHostKeyVerifier(new PromiscuousVerifier());
ssh.connect(host, port);
ssh.authPassword(user, password);
logger.info("SSH session connected (SSHJ).");

session = ssh.startSession();
Command cmd = session.exec(wrappedCommand);
StringBuilder output = new StringBuilder();
try (Reader reader = new InputStreamReader(cmd.getInputStream())) {
char[] buf = new char[1024];
int n;
while ((n = reader.read(buf)) != -1) {
output.append(buf, 0, n);
}
}
cmd.join(30, TimeUnit.SECONDS);
if (cmd.getExitStatus() != null && cmd.getExitStatus() != 0) {
try (Reader errReader = new InputStreamReader(cmd.getErrorStream())) {
char[] buf = new char[1024];
int n;
while ((n = errReader.read(buf)) != -1) {
output.append(buf, 0, n);
}
}
}

runTimeData.setKey(storeVariable.getValue().toString());
runTimeData.setValue(output.toString());

File screenshotFile = null;
try {
screenshotFile = StringToImageConverter.convertToFile(output);
String s3Url = testStepResult != null ? testStepResult.getScreenshotUrl() : null;
if (s3Url != null && !s3Url.isEmpty()) {
ImageComparisonUtils imageComparisonUtils = new ImageComparisonUtils(driver, logger);
boolean uploadResult = imageComparisonUtils.uploadFile(s3Url, screenshotFile.getAbsolutePath());
if (!uploadResult) {
logger.debug("Error uploading custom screenshot to S3; step result may not show the output image.");
} else {
logger.debug("Custom screenshot (command output) uploaded successfully.");
}
}
} finally {
if (screenshotFile != null && screenshotFile.exists()) {
screenshotFile.deleteOnExit();
}
}

setSuccessMessage("Output is: " + output.toString());
return Result.SUCCESS;
} catch (Exception e) {
String errorStack = ExceptionUtils.getStackTrace(e);
logger.info("Error occurred while executing the command (SSHJ): " + errorStack);
setErrorMessage("Error occurred while executing the command: " + e.getMessage());
return Result.FAILED;
} finally {
try {
if (session != null) session.close();
if (ssh != null) ssh.disconnect();
} catch (IOException e) {
logger.info("Error closing SSHJ resources: " + e.getMessage());
}
}
}

private static String wrapInLoginShell(String command) {
String escaped = command.replace("'", "'\\''");
return "bash -l -c '" + escaped + "'";
}
}
Loading
Loading