Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Create test_jars workflow #993

Merged
merged 13 commits into from
Aug 8, 2024
71 changes: 71 additions & 0 deletions .github/download_jars.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
import requests
import random
import os

print('Job Starting')

BASE_URL = "https://search.maven.org/solrsearch/select"
DOWNLOAD_URL_TEMPLATE = "https://repo1.maven.org/maven2/{group}/{artifact}/{version}/{artifact}-{version}.jar"
OUTPUT_DIR = "downloaded_jars"
NUM_JARS = 100
MAX_SIZE_MB = 5 * 1024 * 1024 # 5MB in bytes

# Ensure output directory exists
if not os.path.exists(OUTPUT_DIR):
os.makedirs(OUTPUT_DIR)


def construct_download_url(group, artifact, version):
group_path = group.replace('.', '/')
return DOWNLOAD_URL_TEMPLATE.format(group=group_path, artifact=artifact, version=version)


def download_file(url, output_path):
response = requests.get(url, stream=True)
response.raise_for_status()
total_size = int(response.headers.get('content-length', 0))
if total_size > MAX_SIZE_MB:
return False
with open(output_path, 'wb') as file:
for chunk in response.iter_content(chunk_size=1024):
if chunk: # filter out keep-alive new chunks
file.write(chunk)
return True


# Function to get a random artifact from Maven Central
def get_random_artifact():
params = {
'q': 'p:jar',
'rows': 1,
'wt': 'json',
'start': random.randint(0, 2000000) # Adjust range for better randomness
}
response = requests.get(BASE_URL, params=params)
response.raise_for_status()
docs = response.json().get('response', {}).get('docs', [])
if not docs:
return None
return docs[0]


downloaded_count = 0
# Download 100 random JARs
while downloaded_count < NUM_JARS:
artifact = get_random_artifact()
if not artifact:
continue
group = artifact['g']
artifact_id = artifact['a']
version = artifact['latestVersion']
download_url = construct_download_url(group, artifact_id, version)
output_path = os.path.join(OUTPUT_DIR, f"{artifact_id}-{version}.jar")
try:
if download_file(download_url, output_path):
print(f"Downloaded: {output_path}")
downloaded_count += 1
else:
print(f"Skipped (too large): {output_path}")
except requests.RequestException as e:
print(f"Failed to download {download_url}: {e}")
print(f"Downloaded {downloaded_count} JAR files.")
63 changes: 63 additions & 0 deletions .github/workflows/test-jars.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,63 @@
name: Download Random JARs from Maven

on:
workflow_dispatch:
jobs:
download-jars:
runs-on: ubuntu-latest

steps:
- name: Checkout repository
uses: actions/checkout@v2

- name: Set up Python
uses: actions/setup-python@v2
with:
python-version: '3.x'

- name: Install dependencies
run:
pip install requests

- name: Download random JARs
run: |
python .github/download_jars.py

- name: Upload JARs
uses: actions/upload-artifact@v3
with:
name: jars
path: downloaded_jars/

- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'zulu'
java-package: 'jdk'
java-version: '8'

- name: Checkout repository
uses: actions/checkout@v2

- name: Install Maven
run: |
sudo apt-get update
sudo apt-get install -y maven

- name: Run Maven
run: |
mvn clean install -DskipTests

- name: Run tests on downloaded JARs
run: |
for jar in ${{ github.workspace }}/downloaded_jars/*.jar; do
echo "Testing $jar"
mvn clean test -Dtest=sootup.java.bytecode.inputlocation.RandomJarTest -DjarPath="$jar" -pl sootup.java.bytecode
done

- name: Upload the Artifact
uses: actions/upload-artifact@v3
with:
name: jar_test_csv
path: sootup.java.bytecode/jar_test.csv

Original file line number Diff line number Diff line change
@@ -0,0 +1,163 @@
package sootup.java.bytecode.inputlocation;

import categories.TestCategories;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.Collection;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import sootup.core.inputlocation.AnalysisInputLocation;
import sootup.java.core.JavaSootClass;
import sootup.java.core.views.JavaView;

@Tag(TestCategories.JAVA_8_CATEGORY)
public class RandomJarTest {

private final String jarPath = System.getProperty("jarPath", "");

@Test
public void testJar() {
if (jarPath.isEmpty()) {
return;
}
System.out.println("Jar file parameter is: " + jarPath);
try {
AnalysisInputLocation inputLocation = new JavaClassPathAnalysisInputLocation(jarPath);
JavaView view = new JavaView(inputLocation);
String exception = "No Exceptions :)";
Collection<JavaSootClass> classes;
long time_taken_for_classes = 0;
long number_of_methods = 0;
long time_taken_for_methods = 0;
long number_of_classes = 0;
try {
long start = System.currentTimeMillis();
classes = getClasses(view);
number_of_classes = classes.size();
time_taken_for_classes = System.currentTimeMillis() - start;
start = System.currentTimeMillis();
number_of_methods = getMethods(classes);
time_taken_for_methods = System.currentTimeMillis() - start;
} catch (Exception e) {
exception = e.getMessage();
} finally {
writeTestMetrics(
new TestMetrics(
jarPath.substring(jarPath.lastIndexOf("/") + 1),
number_of_classes,
number_of_methods,
time_taken_for_classes,
time_taken_for_methods,
exception));
}
} catch (Exception e) {
writeTestMetrics(
new TestMetrics(
jarPath.substring(jarPath.lastIndexOf("/") + 1),
-1,
-1,
-1,
-1,
"Could not create JavaClassPathAnalysisInputLocation"));
}
}

public void writeTestMetrics(TestMetrics testMetrics) {
String file_name = "jar_test.csv";
File file = new File(file_name);
boolean fileExists = file.exists();

try (FileWriter fw = new FileWriter(file, true); // Append mode
PrintWriter writer = new PrintWriter(fw)) {

// Write the header if the file doesn't exist
if (!fileExists) {
writer.println(
"jar_name,number_of_classes,number_of_methods,time_taken_for_classes,time_taken_for_methods,exception");
}

// Write each metric to the file
writer.println(
testMetrics.getJar_name()
+ ","
+ testMetrics.getNumberOfClasses()
+ ","
+ testMetrics.getNumber_of_methods()
+ ","
+ testMetrics.getTime_taken_for_classes()
+ ","
+ testMetrics.getTime_taken_for_classes()
+ ","
+ testMetrics.getException());

} catch (IOException e) {
e.printStackTrace();
}
}

private Collection<JavaSootClass> getClasses(JavaView view) {
try {
return view.getClasses();
} catch (Exception e) {
throw new RuntimeException("Error while getting class list", e);
}
}

private long getMethods(Collection<JavaSootClass> classes) {
try {
return classes.stream().map(JavaSootClass::getMethods).mapToLong(Collection::size).sum();
} catch (Exception e) {
throw new RuntimeException("Error while getting class list", e);
}
}

public static class TestMetrics {
String jar_name;
long number_of_classes;
long number_of_methods;
long time_taken_for_classes;
long time_taken_for_methods;
String exception;

public TestMetrics(
String jar_name,
long number_of_classes,
long number_of_methods,
long time_taken_for_classes,
long time_taken_for_methods,
String exception) {
this.jar_name = jar_name;
this.number_of_classes = number_of_classes;
this.number_of_methods = number_of_methods;
this.time_taken_for_classes = time_taken_for_classes;
this.time_taken_for_methods = time_taken_for_methods;
this.exception = exception;
}

String getJar_name() {
return jar_name;
}

long getNumberOfClasses() {
return number_of_classes;
}

long getNumber_of_methods() {
return number_of_methods;
}

long getTime_taken_for_classes() {
return time_taken_for_classes;
}

long getTime_taken_for_methods() {
return time_taken_for_methods;
}

String getException() {
return exception;
}
}
}
Loading