Skip to content

Commit

Permalink
refactor: Add new methods according to new approach of keploy serve (#…
Browse files Browse the repository at this point in the history
…159)

* refactor: different approach of serve cmd of keploy

* refactor: according to keploy server command

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>

---------

Signed-off-by: gouravkrosx <gouravgreatkr@gmail.com>
  • Loading branch information
gouravkrosx committed Dec 8, 2023
1 parent f9225f2 commit baafc13
Show file tree
Hide file tree
Showing 4 changed files with 160 additions and 85 deletions.
12 changes: 12 additions & 0 deletions v2/pom.xml
Original file line number Diff line number Diff line change
Expand Up @@ -34,4 +34,16 @@
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
</properties>

<build>
<resources>
<resource>
<directory>src/main/resources</directory>
<!-- Include all resources in src/main/resources (default behavior) -->
<includes>
<include>**/*</include>
</includes>
</resource>
</resources>
</build>

</project>
233 changes: 148 additions & 85 deletions v2/src/main/java/io.keploy.cli/KeployCLI.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,27 @@
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.management.ManagementFactory;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

//FOR CLI CODE COVERAGE REFERENCE: https://dzone.com/articles/code-coverage-report-generator-for-java-projects-a

// Jacococli & JacocoAgent version: 0.8.8
public class KeployCLI {

private static final String GRAPHQL_ENDPOINT = "/query";
Expand All @@ -25,9 +35,11 @@ public class KeployCLI {

private static int serverPort = 6789;

private static Process kprocess;
private static long userCommandPid = 0;

private static Thread kLogThread;
private static String jacocoCliPath = "";

private static String jacocoAgentPath = "";

public class GraphQLResponse {
Data data;
Expand All @@ -49,91 +61,151 @@ public class RunTestSetResponse {
}
}


public enum TestRunStatus {
RUNNING,
PASSED,
FAILED
}

// public static void main(String[] args) throws IOException, InterruptedException {
// }


// Run Keploy server
public static void RunKeployServer(long pid, int delay, String testPath, int port) throws InterruptedException, IOException {
// Registering a shutdown hook
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
System.out.println("\nShutdown hook executed!");
kprocess.destroy();
try {
Thread.sleep(1000);
kLogThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
public static void StartUserApplication(String runCmd) throws IOException {

runCmd = attachJacocoAgent(runCmd);

// Split the runCmd string into command parts
String[] command = runCmd.split(" ");

// Start the command using ProcessBuilder
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
Process process = processBuilder.start();

// Get the PID of the process
userCommandPid = getProcessId(process);

// Start a thread to log the output of the process
Thread logThread = new Thread(() -> logProcessOutput(process));
logThread.start();
}

private static String attachJacocoAgent(String cmd) {
String resourcePath = "jacocoagent.jar"; // Relative path in the JAR file

try (InputStream is = KeployCLI.class.getClassLoader().getResourceAsStream(resourcePath)) {
if (is == null) {
throw new IllegalStateException("jacocoagent.jar not found in resources");
}
}));


// String password = "keploy@123"; // Ensure this isn't hardcoded in production code!
// String commandString = "echo '" + password + "' | sudo -S /usr/local/bin/keploy serve --pid=" + pid + " -p=" + testPath + " -d=" + delay + " --port=" + port;
// String[] command = {
// commandString
// };

// Construct the keploy command
String[] command = {
"sudo",
"-S",
"/usr/local/bin/keploy",
"serve",
"--pid=" + pid,
"-p=" + testPath,
"-d=" + delay,
"--port=" + port,
"--language=java"
};


if (port != 0) {
serverPort = port;

Path tempFile = Files.createTempFile("jacocoagent", ".jar");

// Using Files.copy for robust file copying
Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING);
is.close();
String agentString = "-javaagent:" + tempFile.toAbsolutePath()
+ "=address=localhost,port=36320,destfile=coverage.exec,output=tcpserver";

jacocoAgentPath = tempFile.toAbsolutePath().toString();
return cmd.replaceFirst("java", "java " + agentString);
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException("Error setting up JaCoCo agent", e);
}
}

public static void FindCoverage(String testSet) throws IOException, InterruptedException {
String dest = "target/" + testSet;
String runCmd = "java -jar " + getJacococliPath() + " dump --address localhost --port 36320 --destfile "
+ dest + ".exec";

// Start the keploy command

// Split the runCmd string into command parts
String[] command = runCmd.split(" ");

// Start the command using ProcessBuilder
ProcessBuilder processBuilder = new ProcessBuilder(command);
processBuilder.redirectErrorStream(true);
kprocess = processBuilder.start();

// // When running without root user
// String password = "keploy@123";
// try (OutputStream os = kprocess.getOutputStream()) {
// os.write((password + "\n").getBytes());
// os.flush();
// }

// Read the output in real-time

Thread logThread = new Thread(() -> {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(kprocess.getInputStream()))) {
String line;
while (kprocess.isAlive() && (line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
// Since the stream might get closed due to process termination,
// we can handle this specific error more gracefully
if (!"Stream closed".equals(e.getMessage())) {
e.printStackTrace();
}
Process process = processBuilder.start();

// Start a thread to log the output of the process
Thread logThread = new Thread(() -> logProcessOutput(process));
logThread.start();
}

private static String getJacococliPath() {
String resourcePath = "jacococli.jar"; // Relative path in the JAR file

try (InputStream is = KeployCLI.class.getClassLoader().getResourceAsStream(resourcePath)) {
if (is == null) {
throw new IllegalStateException("jacococli.jar not found in resources");
}
});

Path tempFile = Files.createTempFile("jacococli", ".jar");

logThread.start();
// Using Files.copy for robust file copying
Files.copy(is, tempFile, StandardCopyOption.REPLACE_EXISTING);
is.close();
jacocoCliPath = tempFile.toAbsolutePath().toString();
return jacocoCliPath;
} catch (IOException e) {
e.printStackTrace();
throw new IllegalStateException("Error setting up JacocoCli", e);
}
}

public static void StopUserApplication() {
deleteJacocoFiles();
killProcessesAndTheirChildren((int) userCommandPid);
}

private static void deleteJacocoFiles() {
deleteFile(jacocoAgentPath);
deleteFile(jacocoCliPath);
}

private static boolean deleteFile(String filePath) {
File file = new File(filePath);

// Check if the file exists
if (!file.exists()) {
System.out.println("File not found: " + filePath);
return false;
}

// Attempt to delete the file
if (file.delete()) {
logger.debug("File deleted successfully:",filePath);
// System.out.println("File deleted successfully: " + filePath);
return true;
} else {
System.out.println("Failed to delete the file: " + filePath);
return false;
}
}

kLogThread = logThread;
// Wait for the command to finish and get its exit code
// int exitCode = process.waitFor();
private static long getProcessId(Process process) {
// Java 9 and later
if (process.getClass().getName().equals("java.lang.ProcessImpl")) {
return process.pid();
}

// Java 8 and earlier
try {
java.lang.reflect.Field f = process.getClass().getDeclaredField("pid");
f.setAccessible(true);
return f.getLong(process);
} catch (NoSuchFieldException | IllegalAccessException e) {
throw new RuntimeException("Unable to get process ID", e);
}
}

private static void logProcessOutput(Process process) {
try (BufferedReader reader = new BufferedReader(new InputStreamReader(process.getInputStream()))) {
String line;
while ((line = reader.readLine()) != null) {
System.out.println(line);
}
} catch (IOException e) {
e.printStackTrace();
}
}

// Set the HTTP client
Expand Down Expand Up @@ -191,7 +263,6 @@ public static String[] FetchTestSets() {
return null;
}


// Fetch the status of testSet
public static TestRunStatus FetchTestSetStatus(String testRunId) {

Expand All @@ -203,8 +274,7 @@ public static TestRunStatus FetchTestSetStatus(String testRunId) {

String payload = String.format(
"{ \"query\": \"{ testSetStatus(testRunId: \\\"%s\\\") { status } }\" }",
testRunId
);
testRunId);

conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
Expand Down Expand Up @@ -239,8 +309,7 @@ public static TestRunStatus FetchTestSetStatus(String testRunId) {
return null;
}


// Run a particular testSet
// Run a particular testSet
public static String RunTestSet(String testSetName) {
try {
HttpURLConnection conn = setHttpClient();
Expand All @@ -250,8 +319,7 @@ public static String RunTestSet(String testSetName) {

String payload = String.format(
"{ \"query\": \"mutation { runTestSet(testSet: \\\"%s\\\") { success testRunId message } }\" }",
testSetName
);
testSetName);

conn.setDoOutput(true);
try (OutputStream os = conn.getOutputStream()) {
Expand Down Expand Up @@ -279,7 +347,6 @@ public static String RunTestSet(String testSetName) {

}


private static boolean isSuccessfulResponse(HttpURLConnection conn) throws IOException {
int responseCode = conn.getResponseCode();
return (responseCode >= 200 && responseCode < 300);
Expand All @@ -296,9 +363,6 @@ private static String getSimulateResponseBody(HttpURLConnection conn) throws IOE
return content.toString();
}

public static void StopKeployServer() {
killProcessOnPort(serverPort);
}
public static void killProcessOnPort(int port) {
try {
Process process = new ProcessBuilder("sh", "-c", "lsof -t -i:" + port).start();
Expand All @@ -324,7 +388,7 @@ public static void killProcessesAndTheirChildren(int parentPID) {
for (int childPID : pids) {
if (childPID != getCurrentPid()) {
try {
new ProcessBuilder("sudo", "kill", "-9", String.valueOf(childPID)).start();
new ProcessBuilder("sudo", "kill", "-15", String.valueOf(childPID)).start();
logger.debug("Killed child process " + childPID);
} catch (Exception e) {
e.printStackTrace();
Expand Down Expand Up @@ -357,4 +421,3 @@ private static int getCurrentPid() {
return Integer.parseInt(processName.split("@")[0]);
}
}

Binary file added v2/src/main/resources/jacocoagent.jar
Binary file not shown.
Binary file added v2/src/main/resources/jacococli.jar
Binary file not shown.

0 comments on commit baafc13

Please sign in to comment.