From a19a69241dae61338e792de2ed889cefd0b6e0be Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 12 Dec 2023 11:50:35 +0100 Subject: [PATCH 001/244] dep: upgrade roseau to latest commit ver (code-review) --- .../com/github/maracas/roseau/Roseau.java | 126 +++++++------- .../maracas/roseau/api/SpoonAPIExtractor.java | 7 +- .../maracas/roseau/api/TypeResolver.java | 27 --- .../github/maracas/roseau/api/model/API.java | 154 +++++++++++++----- .../api/model/reference/TypeReference.java | 6 +- .../roseau/{ => api}/visit/APIAlgebra.java | 2 +- .../{ => api}/visit/AbstractAPIVisitor.java | 2 +- .../maracas/roseau/{ => api}/visit/Visit.java | 2 +- .../github/maracas/roseau/diff/APIDiff.java | 3 +- 9 files changed, 193 insertions(+), 136 deletions(-) delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/TypeResolver.java rename ConfGen/src/main/java/com/github/maracas/roseau/{ => api}/visit/APIAlgebra.java (98%) rename ConfGen/src/main/java/com/github/maracas/roseau/{ => api}/visit/AbstractAPIVisitor.java (98%) rename ConfGen/src/main/java/com/github/maracas/roseau/{ => api}/visit/Visit.java (58%) diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/Roseau.java b/ConfGen/src/main/java/com/github/maracas/roseau/Roseau.java index d9cbd7e7..fb9f40c2 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/Roseau.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/Roseau.java @@ -6,79 +6,87 @@ import com.github.maracas.roseau.diff.APIDiff; import com.github.maracas.roseau.diff.changes.BreakingChange; import com.google.common.base.Stopwatch; +import picocli.CommandLine; import spoon.reflect.CtModel; -import java.io.FileWriter; -import java.io.IOException; import java.nio.file.Path; import java.util.List; +import java.util.concurrent.Callable; +import java.util.concurrent.CompletableFuture; import java.util.stream.Collectors; /** * The `roseau` class is the main entry point of the project. */ -final class Roseau { +@CommandLine.Command(name = "roseau") +final class Roseau implements Callable { + @CommandLine.Option(names = "--api") + private boolean apiMode; + @CommandLine.Option(names = "--diff") + private boolean diffMode; + @CommandLine.Option(names = "--v1", required = true) + private Path libraryV1; + @CommandLine.Option(names = "--v2") + private Path libraryV2; + @CommandLine.Option(names = "--json") + private Path jsonOutput; + @CommandLine.Option(names = "--report") + private Path report; + private static final int SPOON_TIMEOUT = 60; - private Roseau() { + private API buildAPI(Path sources) { + Stopwatch sw = Stopwatch.createStarted(); + + CtModel m = SpoonAPIExtractor.buildModel(sources, SPOON_TIMEOUT) + .orElseThrow(() -> new RuntimeException("Couldn't build in < " + SPOON_TIMEOUT)); + + System.out.println("Parsing: " + sw.elapsed().toMillis()); + sw.reset(); + sw.start(); + + // API extraction + APIExtractor extractor = new SpoonAPIExtractor(m); + API api = extractor.extractAPI(); + System.out.println("API extraction: " + sw.elapsed().toMillis()); + return api; } - public static void main(String[] args) { - try (FileWriter writer = new FileWriter("durations_report.csv")) { - writer.write("Task,Duration\n"); - - Stopwatch sw = Stopwatch.createStarted(); - - // Spoon parsing - CtModel m1 = SpoonAPIExtractor.buildModel(Path.of(args[0]), SPOON_TIMEOUT) - .orElseThrow(() -> new RuntimeException("Couldn't build in < 60s")); - CtModel m2 = SpoonAPIExtractor.buildModel(Path.of(args[1]), SPOON_TIMEOUT) - .orElseThrow(() -> new RuntimeException("Couldn't build in < 60s")); - - writer.write("Spoon model building," + sw.elapsed().toMillis() + "\n"); - System.out.println("Spoon model building: " + sw.elapsed().toSeconds()); - sw.reset(); - sw.start(); - - // API extraction - APIExtractor extractor1 = new SpoonAPIExtractor(m1); - APIExtractor extractor2 = new SpoonAPIExtractor(m2); - API apiV1 = extractor1.extractAPI(); - API apiV2 = extractor2.extractAPI(); - - writer.write("API extraction," + sw.elapsed().toMillis() + "\n"); - System.out.println("API extraction: " + sw.elapsed().toSeconds()); - sw.reset(); - sw.start(); - - // Type resolution - apiV1.resolve(); - apiV2.resolve(); - System.out.println("Type resolution: " + sw.elapsed().toSeconds()); - sw.reset(); - sw.start(); - - // API serialization - apiV1.writeJson(Path.of("api-v1.json")); - apiV2.writeJson(Path.of("api-v2.json")); - - System.out.println("API serialization: " + sw.elapsed().toSeconds()); - sw.reset(); - sw.start(); - - // API diff - APIDiff diff = new APIDiff(apiV1, apiV2); - List bcs = diff.diff(); - - writer.write("DELTA model," + sw.elapsed().toMillis() + "\n"); - System.out.println("API diff: " + sw.elapsed().toSeconds()); - - diff.breakingChangesReport(); - System.out.println(bcs.stream().map(Object::toString).collect(Collectors.joining("\n"))); - } catch (IOException e) { - e.printStackTrace(); - System.exit(1); + private void diff(Path v1, Path v2, Path report) throws Exception { + CompletableFuture futureV1 = CompletableFuture.supplyAsync(() -> buildAPI(v1)); + CompletableFuture futureV2 = CompletableFuture.supplyAsync(() -> buildAPI(v2)); + + CompletableFuture.allOf(futureV1, futureV2).join(); + + API apiV1 = futureV1.get(); + API apiV2 = futureV2.get(); + + // API diff + Stopwatch sw = Stopwatch.createStarted(); + APIDiff diff = new APIDiff(apiV1, apiV2); + List bcs = diff.diff(); + System.out.println("API diff: " + sw.elapsed().toMillis()); + + diff.breakingChangesReport(); + System.out.println(bcs.stream().map(Object::toString).collect(Collectors.joining("\n"))); + } + + @Override + public Integer call() throws Exception { + if (apiMode) { + API api = buildAPI(libraryV1); + api.writeJson(jsonOutput != null ? jsonOutput : Path.of("api.json")); } + + if (diffMode) + diff(libraryV1, libraryV2, report); + + return 0; + } + + public static void main(String[] args) { + int exitCode = new CommandLine(new Roseau()).execute(args); + System.exit(exitCode); } } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/SpoonAPIExtractor.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/SpoonAPIExtractor.java index 732cf555..6db8381a 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/SpoonAPIExtractor.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/SpoonAPIExtractor.java @@ -26,7 +26,7 @@ /** * This class represents roseau's API extraction tool. *
- * Types are resolved within the universe of API types (exported or not). + * Types are resolved within the universe of library types (exported or not). * We don't know anything about the outside world. */ public class SpoonAPIExtractor implements APIExtractor { @@ -109,7 +109,10 @@ public API extractAPI() { List allTypes = model.getAllPackages().stream() - .flatMap(p -> getAllTypes(p).stream().map(factory::convertCtType)) + .parallel() + .flatMap(p -> getAllTypes(p).stream() + .parallel() + .map(factory::convertCtType)) .toList(); return new API(allTypes, factory); diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/TypeResolver.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/TypeResolver.java deleted file mode 100644 index a90ff7ee..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/TypeResolver.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.maracas.roseau.api; - -import com.github.maracas.roseau.api.model.API; -import com.github.maracas.roseau.api.model.SpoonAPIFactory; -import com.github.maracas.roseau.api.model.TypeDecl; -import com.github.maracas.roseau.api.model.reference.TypeReference; -import com.github.maracas.roseau.visit.AbstractAPIVisitor; -import com.github.maracas.roseau.visit.Visit; -import spoon.reflect.factory.TypeFactory; - -public class TypeResolver extends AbstractAPIVisitor { - private final API api; - private final SpoonAPIFactory factory; - - public TypeResolver(API api, SpoonAPIFactory factory) { - this.api = api; - this.factory = factory; - } - - @Override - public Visit typeReference(TypeReference it) { - return () -> { - it.setFactory(factory); - api.findType(it.getQualifiedName()).ifPresent(t -> it.setResolvedApiType((U) t)); - }; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/API.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/API.java index 5e4466c1..d802e32d 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/API.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/API.java @@ -1,12 +1,16 @@ package com.github.maracas.roseau.api.model; +import com.fasterxml.jackson.annotation.JacksonInject; import com.fasterxml.jackson.annotation.JsonCreator; import com.fasterxml.jackson.annotation.JsonIgnore; import com.fasterxml.jackson.annotation.JsonProperty; +import com.fasterxml.jackson.databind.InjectableValues; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jdk8.Jdk8Module; import com.fasterxml.jackson.module.paranamer.ParanamerModule; -import com.github.maracas.roseau.api.TypeResolver; +import com.github.maracas.roseau.api.model.reference.TypeReference; +import com.github.maracas.roseau.api.visit.AbstractAPIVisitor; +import com.github.maracas.roseau.api.visit.Visit; import java.io.IOException; import java.nio.file.Path; @@ -18,92 +22,160 @@ import java.util.stream.Collectors; /** - * Represents the API of a library containing all the types, each of which may have methods, fields, constructors, and - * more information about the type. This class encapsulates a list of {@link TypeDecl} instances, each representing - * distinct types identified by their respective qualified names. + * A representation of all types contained in a given library, including those + * that are exported ({@link #getExportedTypes()}}. The entire API is weakly immutable + * and can be serialized/deserialized from Json. */ public final class API { - private final Map types; + private final Map allTypes; @JsonIgnore private final SpoonAPIFactory factory; + /** + * Initializes an API from the given list of {@link TypeDecl} and the given {@link SpoonAPIFactory}. + * Every {@link com.github.maracas.roseau.api.model.reference.TypeReference} in the given list of types + * is visited to resolve within-library types and assign the {@code factory} for later type resolutions. + * + * @param types Initial set of {@link TypeDecl} instances inferred from the library, exported or not + * @param factory Passed around to every type reference for later {@link TypeDecl} inference and resolution + */ @JsonCreator - public API(@JsonProperty("allTypes") List types, SpoonAPIFactory factory) { - this.types = types.stream() + public API(@JsonProperty("allTypes") List types, @JacksonInject SpoonAPIFactory factory) { + this.allTypes = Objects.requireNonNull(types).stream() .collect(Collectors.toMap( Symbol::getQualifiedName, Function.identity() )); - this.factory = factory; + this.factory = Objects.requireNonNull(factory); + + // Whenever we create an API instance, we need to make sure to resolve within-library types and to pass + // the factory around to lazily resolve type references later + new AbstractAPIVisitor() { + @Override + public Visit typeReference(TypeReference it) { + return () -> { + it.setFactory(factory); + if (allTypes.containsKey(it.getQualifiedName())) + it.setResolvedApiType((U) allTypes.get(it.getQualifiedName())); + }; + } + }.$(this).visit(); } - public void resolve() { - // Within-library type resolution - new TypeResolver(this, factory).$(this).visit(); + /** + * Returns the {@link TypeDecl} that are exported in the API. + * + * @return The list of exported {@link TypeDecl} + */ + @JsonIgnore + public List getExportedTypes() { + return getAllTypes().stream() + .filter(Symbol::isExported) + .toList(); } - public List getAllTypes() { - return types.values().stream().toList(); - } + /** + * Finds an exported type in the API with the given qualified name. + * + * @param qualifiedName The qualified name of the type to find + * @return An {@link Optional} indicating whether the type was found + */ + public Optional findExportedType(String qualifiedName) { + TypeDecl find = allTypes.get(qualifiedName); - public SpoonAPIFactory getFactory() { - return factory; + return find != null && find.isExported() ? Optional.of(find) : Optional.empty(); } + /** + * Returns the {@link ClassDecl} that are exported in the API. + * + * @return The list of exported {@link ClassDecl} + */ @JsonIgnore - public List getAllClasses() { - return types.values().stream() + public List getExportedClasses() { + return getExportedTypes().stream() .filter(ClassDecl.class::isInstance) .map(ClassDecl.class::cast) .toList(); } + /** + * Returns the {@link InterfaceDecl} that are exported in the API. + * + * @return The list of exported {@link InterfaceDecl} + */ @JsonIgnore - public List getExportedTypes() { - return getAllTypes().stream() - .filter(Symbol::isExported) + public List getExportedInterfaces() { + return getExportedTypes().stream() + .filter(InterfaceDecl.class::isInstance) + .map(InterfaceDecl.class::cast) .toList(); } - public Optional getExportedType(String qualifiedName) { - return getExportedTypes().stream() - .filter(t -> Objects.equals(qualifiedName, t.getQualifiedName())) - .findFirst(); + /** + * Returns *all* types in the library, including those that are *not* exported. + * In most cases, you should probably use {@link #getExportedTypes()} instead. + * + * @return The list of *all* {@link TypeDecl} + * @see #getExportedTypes() + */ + public List getAllTypes() { + return allTypes.values().stream().toList(); } + /** + * Finds a type, *exported or not*, with the given qualified name. + * + * @param qualifiedName The qualified name of the type to find + * @return An {@link Optional} indicating whether the type was found + * @see #findExportedType(String) + */ public Optional findType(String qualifiedName) { - return Optional.ofNullable(types.get(qualifiedName)); + return Optional.ofNullable(allTypes.get(qualifiedName)); } - public Optional findClass(String qualifiedName) { - return getAllClasses().stream() - .filter(cls -> cls.getQualifiedName().equals(qualifiedName)) - .findFirst(); + /** + * Retrieves the {@link SpoonAPIFactory} associated with this API. + * + * @return The SpoonAPIFactory instance. + */ + public SpoonAPIFactory getFactory() { + return factory; } + /** + * Serializes the API as Json to the specified file + * + * @param jsonFile The {@link Path} to write to + * @throws IOException If the file cannot be written + */ public void writeJson(Path jsonFile) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new Jdk8Module()); mapper.writerWithDefaultPrettyPrinter().writeValue(jsonFile.toFile(), this); } - public static API fromJson(Path jsonFile) throws IOException { + /** + * Parses the given Json file as an API + * + * @param jsonFile The {@link Path} to read Json from + * @param factory The {@link SpoonAPIFactory} that should be injected in the parsed objects + * @return The API generated from the Json file + * @throws IOException If the file cannot be parsed + */ + public static API fromJson(Path jsonFile, SpoonAPIFactory factory) throws IOException { ObjectMapper mapper = new ObjectMapper(); mapper.registerModule(new Jdk8Module()); // For Optional<> mapper.registerModule(new ParanamerModule()); // For @JsonCreator + mapper.setInjectableValues(new InjectableValues.Std().addValue(SpoonAPIFactory.class, factory)); return mapper.readValue(jsonFile.toFile(), API.class); } @Override public String toString() { - StringBuilder builder = new StringBuilder(); - - for (TypeDecl typeDeclaration : types.values()) { - builder.append(typeDeclaration).append("\n"); - builder.append(" =========================\n\n"); - } - - return builder.toString(); + return getExportedTypes().stream() + .map(TypeDecl::toString) + .collect(Collectors.joining("\n")); } @Override @@ -111,11 +183,11 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; API api = (API) o; - return Objects.equals(types, api.types); + return Objects.equals(allTypes, api.allTypes); } @Override public int hashCode() { - return Objects.hash(types); + return Objects.hash(allTypes); } } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java index cf39a949..0d5822ad 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java @@ -3,8 +3,8 @@ import com.fasterxml.jackson.annotation.JsonValue; import com.github.maracas.roseau.api.model.SpoonAPIFactory; import com.github.maracas.roseau.api.model.TypeDecl; -import com.google.common.base.Objects; +import java.util.Objects; import java.util.Optional; public final class TypeReference implements ITypeReference { @@ -21,6 +21,8 @@ public TypeReference(String qualifiedName, SpoonAPIFactory factory) { this.factory = factory; } + public SpoonAPIFactory getFactory() { return factory; } + @JsonValue @Override public String getQualifiedName() { @@ -60,7 +62,7 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TypeReference other = (TypeReference) o; - return Objects.equal(qualifiedName, other.qualifiedName); + return Objects.equals(qualifiedName, other.qualifiedName); } @Override diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/visit/APIAlgebra.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java similarity index 98% rename from ConfGen/src/main/java/com/github/maracas/roseau/visit/APIAlgebra.java rename to ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java index b330c781..2eb8d491 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/visit/APIAlgebra.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java @@ -1,4 +1,4 @@ -package com.github.maracas.roseau.visit; +package com.github.maracas.roseau.api.visit; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.AnnotationDecl; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/visit/AbstractAPIVisitor.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java similarity index 98% rename from ConfGen/src/main/java/com/github/maracas/roseau/visit/AbstractAPIVisitor.java rename to ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java index 0d8d741d..18a683ff 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/visit/AbstractAPIVisitor.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java @@ -1,4 +1,4 @@ -package com.github.maracas.roseau.visit; +package com.github.maracas.roseau.api.visit; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.AnnotationDecl; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/visit/Visit.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java similarity index 58% rename from ConfGen/src/main/java/com/github/maracas/roseau/visit/Visit.java rename to ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java index 317b4f89..b65b8ce5 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/visit/Visit.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java @@ -1,4 +1,4 @@ -package com.github.maracas.roseau.visit; +package com.github.maracas.roseau.api.visit; @FunctionalInterface public interface Visit { diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java index 80cf6015..26c5dbc7 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java @@ -18,7 +18,6 @@ import java.io.FileWriter; import java.io.IOException; import java.util.ArrayList; -import java.util.Collections; import java.util.HashSet; import java.util.List; import java.util.Objects; @@ -57,7 +56,7 @@ public APIDiff(API v1, API v2) { public List diff() { v1.getExportedTypes().forEach(t1 -> { - Optional findT2 = v2.getExportedType(t1.getQualifiedName()); + Optional findT2 = v2.findExportedType(t1.getQualifiedName()); findT2.ifPresentOrElse( // There is a matching type From 60905d549da37aaa037946173469001ca945c7fa Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 10:28:08 +0100 Subject: [PATCH 002/244] feat: begin refactoring of instrumentation project --- .../maracas/gilesi/instrumentation/Agent.java | 83 +++++++++- .../gilesi/instrumentation/MethodTrace.java | 49 ------ .../gilesi/instrumentation/MethodTracer.java | 147 +++++++++++++----- .../InstrumentationParameter.java | 2 +- .../InstrumentationParameters.java | 2 +- .../instrumentation/models/MethodTrace.java | 90 +++++++++++ .../{ => models}/SerializableData.java | 13 +- .../{ => visitors}/ConstructorVisitor.java | 14 +- .../{ => visitors}/MethodVisitor.java | 16 +- .../{ => visitors}/StaticMethodVisitor.java | 14 +- 10 files changed, 303 insertions(+), 127 deletions(-) delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => models}/InstrumentationParameter.java (71%) rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => models}/InstrumentationParameters.java (69%) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => models}/SerializableData.java (86%) rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => visitors}/ConstructorVisitor.java (55%) rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => visitors}/MethodVisitor.java (53%) rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{ => visitors}/StaticMethodVisitor.java (51%) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 11374572..b538ad31 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -1,32 +1,101 @@ package com.github.maracas.gilesi.instrumentation; import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; import java.io.IOException; import java.lang.instrument.Instrumentation; +/* + Our main agent class + */ public class Agent { + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { + ObjectMapper objectMapper = new ObjectMapper(); + return objectMapper.readValue(file, InstrumentationParameters.class); + } + + /** + * Generates the tracing results text file on disk + */ + public static void SaveTraceResults() { + File outputFile = new File("MethodTraces.json"); + System.out.println("Saving trace results in progress..."); + System.out.println("Output location: " + outputFile.getAbsolutePath()); + + try { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.writeValue(outputFile, MethodTracer.getMethodTraces()); + } catch (Exception e) { + e.printStackTrace(); + } + + System.out.println("Saving trace results in progress... Done!"); + } + + /* + Our primary method to install the agent required to trace methods during execution + We take in as parameter a JSON file with the list of methods to instrument and their class + */ private static void installAgent(String arg, Instrumentation inst) throws IOException { - ByteBuddyAgent.install(); - Runtime.getRuntime().addShutdownHook(new Thread(MethodTracer::SaveTraceResults)); + // First install the ByteBuddy Agent required to redefine classes during execution + // Sometimes this can fail, so try catch it + try { + ByteBuddyAgent.install(); + } catch (Exception e) { + System.err.println("ERROR: Could not install byte buddy agent!"); + System.err.println(e.getMessage()); + e.printStackTrace(); + return; + } - ObjectMapper objectMapper = new ObjectMapper(); - InstrumentationParameters instrumentationParameters = objectMapper.readValue(new File(arg), InstrumentationParameters.class); + // Then add a shutdown hook to save all method execution traces at exit + Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); + + // Get the parameters + File configurationFile = new File(arg); + if (!configurationFile.exists()) { + System.err.println("ERROR: the passed in configuration file (" + arg + ") does not exist or could not be found!"); + return; + } + + InstrumentationParameters instrumentationParameters; + + try { + instrumentationParameters = parseInstrumentationparameters(configurationFile); + } catch (IOException ioException) { + System.err.println("ERROR: Could not parse instrumentation configuration file (" + arg + ")!"); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } - // Note: constructors get "" as their name in bytebuddy methodmatcher code - // Note2: Not possible to specifically say what type with arg list? Maybe looking into it - // Note3: we may want to take in a json because that's gonna be complex otherwise to instrument + // Instrument every class for (InstrumentationParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { MethodTracer.instrumentClassForTracingAgent(inst, instrumentationParameter); } } + /* + premain is invoked when an agent is started before the application. + Agents invoked using premain are specified with the -javaagent switch. + (https://stackoverflow.com/a/19789168) + */ public static void premain(String arg, Instrumentation inst) throws IOException { installAgent(arg, inst); } + /* + agentmain is invoked when an agent is started after the application is already running. + Agents started with agentmain can be attached programatically using the Sun tools API (for Sun/Oracle JVMs only + -- the method for introducing dynamic agents is implementation-dependent). + (https://stackoverflow.com/a/19789168) + */ public static void agentmain(String arg, Instrumentation inst) throws IOException { installAgent(arg, inst); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java deleted file mode 100644 index 18f20e68..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.maracas.gilesi.instrumentation; - -import java.util.List; - -public class MethodTrace { - public String methodSignature; - public SerializableData instance; - public List preCallArguments; - public List postCallArguments; - public SerializableData returnedValue; - public long timeStampEntry; - public long timeStampExit; - - public MethodTrace(String methodSignature, SerializableData instance, List preCallArguments, - List postCallArguments, SerializableData returnedValue, long timeStampEntry, - long timeStampExit) - { - this.instance = instance; - this.methodSignature = methodSignature; - this.timeStampEntry = timeStampEntry; - this.postCallArguments = postCallArguments; - this.preCallArguments = preCallArguments; - this.returnedValue = returnedValue; - this.timeStampExit = timeStampExit; - } - - public MethodTrace() {} - - @Override - public String toString() { - return "MethodTrace{" + - "methodSignature='" + methodSignature + '\'' + - ", instance=" + instance + - ", preCallArguments=" + preCallArguments + - ", postCallArguments=" + postCallArguments + - ", returnedValue=" + returnedValue + - ", timeStampEntry=" + timeStampEntry + - ", timeStampExit=" + timeStampExit + - '}'; - } - - public long getTimeStampEntry() { - return timeStampEntry; - } - - public long getTimeStampExit() { - return timeStampExit; - } -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java index d1bcd5a0..16eccc7a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java @@ -1,12 +1,15 @@ package com.github.maracas.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.MethodTrace; +import com.github.maracas.gilesi.instrumentation.models.SerializableData; +import com.github.maracas.gilesi.instrumentation.visitors.ConstructorVisitor; +import com.github.maracas.gilesi.instrumentation.visitors.MethodVisitor; +import com.github.maracas.gilesi.instrumentation.visitors.StaticMethodVisitor; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.matcher.ElementMatchers; -import java.io.File; import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -18,7 +21,10 @@ import static net.bytebuddy.matcher.ElementMatchers.named; public class MethodTracer { + // Storage for onEntry traces yet to be completed with an onExit trace private static final ArrayList notYetCompletedMethodTraces = new ArrayList<>(); + + // Storage for traces collected so far private static final ArrayList methodTraces = new ArrayList<>(); public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { @@ -77,10 +83,10 @@ private static String getOriginName(Executable origin) { String originName; if (origin instanceof Method) { - Method method = (Method)origin; + Method method = (Method) origin; originName = method.toGenericString(); } else if (origin instanceof Constructor) { - Constructor constructor = (Constructor)origin; + Constructor constructor = (Constructor) origin; originName = constructor.toGenericString(); } else { System.out.println("BUGBUGBUG: Unknown Originating Executable Type!"); @@ -116,11 +122,41 @@ private static List getArgumentsAsSerializableData(Object[] ar * @param arguments The originating trace argument list on entry */ public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arguments, Object instance) { - String originName = getOriginName(origin); - List argumentString = getArgumentsAsSerializableData(arguments); + // Need to fetch this asap to not be off on the measurements! + long entryMarker = System.currentTimeMillis(); + + String methodSignature = getOriginName(origin); + SerializableData serializableInstance = instance == null ? null : SerializableData.GetFromObject(instance); + List preCallArguments = getArgumentsAsSerializableData(arguments); + long timeStampEntry = entryMarker; + + MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1); + notYetCompletedMethodTraces.add(methodTrace); + } + + /** + * Collects information about a method execution call at entry, + * for further collection later on exit + * This method generates an incomplete partial method trace with on entry information, + * and caches it temporarily for use on exit. + * Callers must call later addMethodTrace on exit to complete the trace and make it available. + *

+ * This method is public so it can be accessed as part of the modified instrumented classes + * without security problems at the JVM level + * + * @param origin The originating trace Executable object + * @param arguments The originating trace argument list on entry + */ + public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arguments) { + // Need to fetch this asap to not be off on the measurements! + long entryMarker = System.currentTimeMillis(); + + String methodSignature = getOriginName(origin); + List preCallArguments = getArgumentsAsSerializableData(arguments); + long timeStampEntry = entryMarker; - long timeStampEntry = System.currentTimeMillis(); - notYetCompletedMethodTraces.add(new MethodTrace(originName, SerializableData.GetFromObject(instance), argumentString, null, null, timeStampEntry, -1)); + MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, null, null, timeStampEntry, -1); + notYetCompletedMethodTraces.add(methodTrace); } private static MethodTrace getMatchingIncompleteEntryTrace(String originName, SerializableData serializableInstance, long timeStampExit) { @@ -128,9 +164,9 @@ private static MethodTrace getMatchingIncompleteEntryTrace(String originName, Se if (!serializableInstance.isNull) { for (MethodTrace methodTrace : notYetCompletedMethodTraces) { - if (methodTrace.methodSignature.equals(originName) && - methodTrace.instance.instanceId == serializableInstance.instanceId - && methodTrace.timeStampEntry <= timeStampExit) { + if (methodTrace.getMethodSignature().equals(originName) && + methodTrace.getInstance().instanceId == serializableInstance.instanceId + && methodTrace.getTimeStampEntry() <= timeStampExit) { originatingMethodTrace = methodTrace; break; } @@ -141,8 +177,8 @@ private static MethodTrace getMatchingIncompleteEntryTrace(String originName, Se // In such case, look for other cases if (originatingMethodTrace == null) { for (MethodTrace methodTrace : notYetCompletedMethodTraces) { - if (methodTrace.methodSignature.equals(originName) && methodTrace.instance.isNull - && methodTrace.timeStampEntry <= timeStampExit) { + if (methodTrace.getMethodSignature().equals(originName) && methodTrace.getInstance().isNull + && methodTrace.getTimeStampEntry() <= timeStampExit) { originatingMethodTrace = methodTrace; break; } @@ -170,25 +206,71 @@ private static MethodTrace getMatchingIncompleteEntryTrace(String originName, Se * @param returned The data returned by the originating trace */ public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance) { - long timeStampExit = System.currentTimeMillis(); + // Need to fetch this asap to not be off on the measurements! + long exitMarker = System.currentTimeMillis(); + + String methodSignature = getOriginName(origin); + SerializableData serializableInstance = instance == null ? null : SerializableData.GetFromObject(instance); + List preCallArguments = null; + List postCallArguments = getArgumentsAsSerializableData(arguments); + SerializableData returnedValue = returned == null ? null : SerializableData.GetFromObject(returned); + long timeStampEntry = -1; + long timeStampExit = exitMarker; + + // Attempt to find a matching onEntry trace, if we cannot, stick to defaults (Entry = -1, preCallArguments = null) + MethodTrace originatingMethodTrace = getMatchingIncompleteEntryTrace(methodSignature, serializableInstance, timeStampExit); + if (originatingMethodTrace != null) { + preCallArguments = originatingMethodTrace.getPreCallArguments(); + timeStampEntry = originatingMethodTrace.getTimeStampEntry(); + + // Remove from cache + notYetCompletedMethodTraces.remove(originatingMethodTrace); + } - String originName = getOriginName(origin); - List argumentString = getArgumentsAsSerializableData(arguments); - SerializableData returnString = SerializableData.GetFromObject(returned); + MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit); + methodTraces.add(methodTrace); + } - SerializableData serializableInstance = SerializableData.GetFromObject(instance); - MethodTrace originatingMethodTrace = getMatchingIncompleteEntryTrace(originName, serializableInstance, timeStampExit); + /** + * Collects information about a method execution call at exit, + * with further data completion with an earlier partial trace if available from entry. + * This method generates an incomplete partial method trace with on exit information, + * and completes it with entry information if available, to cache a complete trace. + * Callers must call earlier addNotYetCompletedMethodTrace to provide entry information to + * have complete trace data. + *

+ * Callers must call later getMethodTraces to retrieve the trace information. + *

+ * This method is public so it can be accessed as part of the modified instrumented classes + * without security problems at the JVM level + * + * @param origin The originating trace Executable object + * @param arguments The originating trace argument list on entry + * @param returned The data returned by the originating trace + */ + public static void addMethodTrace(Executable origin, Object[] arguments, Object returned) { + // Need to fetch this asap to not be off on the measurements! + long exitMarker = System.currentTimeMillis(); + String methodSignature = getOriginName(origin); List preCallArguments = null; + List postCallArguments = getArgumentsAsSerializableData(arguments); + SerializableData returnedValue = returned == null ? null : SerializableData.GetFromObject(returned); long timeStampEntry = -1; + long timeStampExit = exitMarker; + // Attempt to find a matching onEntry trace, if we cannot, stick to defaults (Entry = -1, preCallArguments = null) + MethodTrace originatingMethodTrace = getMatchingIncompleteEntryTrace(methodSignature, null, timeStampExit); if (originatingMethodTrace != null) { - preCallArguments = originatingMethodTrace.preCallArguments; - timeStampEntry = originatingMethodTrace.timeStampEntry; + preCallArguments = originatingMethodTrace.getPreCallArguments(); + timeStampEntry = originatingMethodTrace.getTimeStampEntry(); + + // Remove from cache notYetCompletedMethodTraces.remove(originatingMethodTrace); } - methodTraces.add(new MethodTrace(originName, serializableInstance, preCallArguments, argumentString, returnString, timeStampEntry, timeStampExit)); + MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit); + methodTraces.add(methodTrace); } /** @@ -200,23 +282,4 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object public static Collection getMethodTraces() { return methodTraces; } - - /** - * Generates the tracing results text file on disk - */ - public static void SaveTraceResults() { - File outputFile = new File("MethodTraces.json"); - System.out.println("Saving trace results in progress..."); - System.out.println("Output location: " + outputFile.getAbsolutePath()); - - try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - objectMapper.writeValue(outputFile, methodTraces); - } catch (Exception e) { - e.printStackTrace(); - } - - System.out.println("Saving trace results in progress... Done!"); - } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java similarity index 71% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameter.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index 48c9707b..1044eda5 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java similarity index 69% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameters.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 3709c04b..782fefb4 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java new file mode 100644 index 00000000..cb185ed6 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java @@ -0,0 +1,90 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class MethodTrace { + private String methodSignature; + private SerializableData instance; + private List preCallArguments; + private List postCallArguments; + private SerializableData returnedValue; + private long timeStampEntry; + private long timeStampExit; + + @JsonCreator + public MethodTrace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") SerializableData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") SerializableData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit) { + this.methodSignature = methodSignature; + this.instance = instance; + this.preCallArguments = preCallArguments; + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampEntry = timeStampEntry; + this.timeStampExit = timeStampExit; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public SerializableData getInstance() { + return instance; + } + + public void setInstance(SerializableData instance) { + this.instance = instance; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public SerializableData getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(SerializableData returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java similarity index 86% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index 4881f8da..b011e975 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.models; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; @@ -13,7 +13,7 @@ public class SerializableData { public boolean isNull; public boolean isSerialized; - public SerializableData(String fullyQualifiedTypeName, String dataAsJson, int instanceId, boolean isNull, boolean isSerialized) { + private SerializableData(String fullyQualifiedTypeName, String dataAsJson, int instanceId, boolean isNull, boolean isSerialized) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; this.dataAsJson = dataAsJson; this.instanceId = instanceId; @@ -21,7 +21,8 @@ public SerializableData(String fullyQualifiedTypeName, String dataAsJson, int in this.isSerialized = isSerialized; } - public SerializableData() {} + public SerializableData() { + } public static SerializableData GetFromObject(Object object) { if (object == null) { @@ -49,16 +50,12 @@ public static SerializableData GetFromObject(Object object) { serializedString = objectMapper.writeValueAsString(object); isSerialized = true; } catch (JsonProcessingException e) { - //System.out.println("Cannot serialize specific argument: " + e); + System.err.println("ERROR: Cannot serialize specific argument: " + e); } return new SerializableData(objectClassName, serializedString, instanceId, false, isSerialized); } - /*public String getJavaCodeEquivalentAsString() { - return "TODO!"; - }*/ - @Override public String toString() { return "SerializableData{" + diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/ConstructorVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java similarity index 55% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/ConstructorVisitor.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java index 05f7688b..8a985ff9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/ConstructorVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java @@ -1,5 +1,6 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.visitors; +import com.github.maracas.gilesi.instrumentation.MethodTracer; import net.bytebuddy.asm.Advice; import java.lang.reflect.Executable; @@ -10,17 +11,18 @@ public class ConstructorVisitor { @Advice.OnMethodEnter public static Object enter( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, null); + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments) { + MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); return null; } @Advice.OnMethodExit public static void exit( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments, - @Advice.Return(readOnly = false, typing = DYNAMIC) Object returned, - @Advice.This Object instance) { + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, + @Advice.Return(typing = DYNAMIC) Object returned, + @Advice.This(typing = DYNAMIC) Object instance, + @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { MethodTracer.addMethodTrace(origin, arguments, returned, instance); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java similarity index 53% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodVisitor.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java index 9123b712..8210506d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java @@ -1,5 +1,6 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.visitors; +import com.github.maracas.gilesi.instrumentation.MethodTracer; import net.bytebuddy.asm.Advice; import java.lang.reflect.Executable; @@ -10,8 +11,8 @@ public class MethodVisitor { @Advice.OnMethodEnter public static Object enter( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments, - @Advice.This Object instance) { + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, + @Advice.This(typing = DYNAMIC) Object instance) { MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, instance); return null; } @@ -19,9 +20,10 @@ public static Object enter( @Advice.OnMethodExit public static void exit( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments, - @Advice.Return(readOnly = false, typing = DYNAMIC) Object returned, - @Advice.This Object instance) { + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, + @Advice.Return(typing = DYNAMIC) Object returned, + @Advice.This(typing = DYNAMIC) Object instance, + @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { MethodTracer.addMethodTrace(origin, arguments, returned, instance); } -} +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/StaticMethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java similarity index 51% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/StaticMethodVisitor.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java index 7d48908b..b0a8c648 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/StaticMethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java @@ -1,5 +1,6 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.visitors; +import com.github.maracas.gilesi.instrumentation.MethodTracer; import net.bytebuddy.asm.Advice; import java.lang.reflect.Executable; @@ -10,16 +11,17 @@ public class StaticMethodVisitor { @Advice.OnMethodEnter public static Object enter( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, null); + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments) { + MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); return null; } @Advice.OnMethodExit public static void exit( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = DYNAMIC) Object[] arguments, - @Advice.Return(readOnly = false, typing = DYNAMIC) Object returned) { - MethodTracer.addMethodTrace(origin, arguments, returned, null); + @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, + @Advice.Return(typing = DYNAMIC) Object returned, + @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { + MethodTracer.addMethodTrace(origin, arguments, returned); } } From 7af2bdb6b19e946c65d9e19aedd5af7032dcd197 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 10:58:14 +0100 Subject: [PATCH 003/244] fix: missing dependency w/ roseau --- ConfGen/build.gradle | 1 + 1 file changed, 1 insertion(+) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index 8a4c17bd..2c435a06 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -29,6 +29,7 @@ dependencies { implementation 'com.fasterxml.jackson.module:jackson-module-paranamer:2.15.1' implementation 'com.google.guava:guava:32.1.2-jre' implementation 'fr.inria.gforge.spoon:spoon-core:10.4.2' + implementation 'info.picocli:picocli:4.7.5' } jar { From b84504e32b10f483c9bfc6517a09d383633dfe47 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 11:16:44 +0100 Subject: [PATCH 004/244] feat: more factoring on method trace classes --- .../gilesi/instrumentation/MethodTracer.java | 24 +++---- .../instrumentation/models/MethodTrace.java | 13 +++- .../models/SerializableData.java | 71 ++++++++++++------- 3 files changed, 71 insertions(+), 37 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java index 16eccc7a..1c765994 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java @@ -101,7 +101,7 @@ private static List getArgumentsAsSerializableData(Object[] ar if (arguments != null) { for (Object argument : arguments) { - argumentStrings.add(SerializableData.GetFromObject(argument)); + argumentStrings.add(SerializableData.of(argument)); } } @@ -126,11 +126,11 @@ public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arg long entryMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); - SerializableData serializableInstance = instance == null ? null : SerializableData.GetFromObject(instance); + SerializableData serializableInstance = SerializableData.of(instance); List preCallArguments = getArgumentsAsSerializableData(arguments); long timeStampEntry = entryMarker; - MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1); + MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1, null); notYetCompletedMethodTraces.add(methodTrace); } @@ -155,17 +155,17 @@ public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arg List preCallArguments = getArgumentsAsSerializableData(arguments); long timeStampEntry = entryMarker; - MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, null, null, timeStampEntry, -1); + MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, null, null, timeStampEntry, -1, null); notYetCompletedMethodTraces.add(methodTrace); } private static MethodTrace getMatchingIncompleteEntryTrace(String originName, SerializableData serializableInstance, long timeStampExit) { MethodTrace originatingMethodTrace = null; - if (!serializableInstance.isNull) { + if (serializableInstance != null) { for (MethodTrace methodTrace : notYetCompletedMethodTraces) { if (methodTrace.getMethodSignature().equals(originName) && - methodTrace.getInstance().instanceId == serializableInstance.instanceId + methodTrace.getInstance().getInstanceId() == serializableInstance.getInstanceId() && methodTrace.getTimeStampEntry() <= timeStampExit) { originatingMethodTrace = methodTrace; break; @@ -177,7 +177,7 @@ private static MethodTrace getMatchingIncompleteEntryTrace(String originName, Se // In such case, look for other cases if (originatingMethodTrace == null) { for (MethodTrace methodTrace : notYetCompletedMethodTraces) { - if (methodTrace.getMethodSignature().equals(originName) && methodTrace.getInstance().isNull + if (methodTrace.getMethodSignature().equals(originName) && methodTrace.getInstance() == null && methodTrace.getTimeStampEntry() <= timeStampExit) { originatingMethodTrace = methodTrace; break; @@ -210,10 +210,10 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object long exitMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); - SerializableData serializableInstance = instance == null ? null : SerializableData.GetFromObject(instance); + SerializableData serializableInstance = SerializableData.of(instance); List preCallArguments = null; List postCallArguments = getArgumentsAsSerializableData(arguments); - SerializableData returnedValue = returned == null ? null : SerializableData.GetFromObject(returned); + SerializableData returnedValue = SerializableData.of(returned); long timeStampEntry = -1; long timeStampExit = exitMarker; @@ -227,7 +227,7 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object notYetCompletedMethodTraces.remove(originatingMethodTrace); } - MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit); + MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, null); methodTraces.add(methodTrace); } @@ -255,7 +255,7 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object String methodSignature = getOriginName(origin); List preCallArguments = null; List postCallArguments = getArgumentsAsSerializableData(arguments); - SerializableData returnedValue = returned == null ? null : SerializableData.GetFromObject(returned); + SerializableData returnedValue = SerializableData.of(returned); long timeStampEntry = -1; long timeStampExit = exitMarker; @@ -269,7 +269,7 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object notYetCompletedMethodTraces.remove(originatingMethodTrace); } - MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit); + MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, null); methodTraces.add(methodTrace); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java index cb185ed6..a3626a4b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java @@ -13,6 +13,7 @@ public class MethodTrace { private SerializableData returnedValue; private long timeStampEntry; private long timeStampExit; + private SerializableData exceptionThrown; @JsonCreator public MethodTrace( @@ -22,7 +23,8 @@ public MethodTrace( @JsonProperty("postCallArguments") List postCallArguments, @JsonProperty("returnedValue") SerializableData returnedValue, @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit) { + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") SerializableData exceptionThrown) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; @@ -30,6 +32,7 @@ public MethodTrace( this.returnedValue = returnedValue; this.timeStampEntry = timeStampEntry; this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; } public String getMethodSignature() { @@ -87,4 +90,12 @@ public long getTimeStampExit() { public void setTimeStampExit(long timeStampExit) { this.timeStampExit = timeStampExit; } + + public SerializableData getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(SerializableData exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index b011e975..10cd176f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -3,30 +3,64 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; public class SerializableData { private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - public String fullyQualifiedTypeName; - public String dataAsJson; - public int instanceId; - public boolean isNull; - public boolean isSerialized; + private String fullyQualifiedTypeName; + private String dataAsJson; + private int instanceId; + private boolean isSerialized; - private SerializableData(String fullyQualifiedTypeName, String dataAsJson, int instanceId, boolean isNull, boolean isSerialized) { + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public String getDataAsJson() { + return dataAsJson; + } + + public void setDataAsJson(String dataAsJson) { this.dataAsJson = dataAsJson; + } + + public int getInstanceId() { + return instanceId; + } + + public void setInstanceId(int instanceId) { this.instanceId = instanceId; - this.isNull = isNull; - this.isSerialized = isSerialized; } - public SerializableData() { + public boolean isSerialized() { + return isSerialized; } - public static SerializableData GetFromObject(Object object) { + public void setSerialized(boolean serialized) { + isSerialized = serialized; + } + + @JsonCreator + public SerializableData( + @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, + @JsonProperty("dataAsJson") String dataAsJson, + @JsonProperty("instanceId") int instanceId, + @JsonProperty("isSerialized") boolean isSerialized) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + this.dataAsJson = dataAsJson; + this.instanceId = instanceId; + this.isSerialized = isSerialized; + } + + public static SerializableData of(Object object) { if (object == null) { - return new SerializableData(null, null, -1, true, false); + return null; } // /!\ CAUTION @@ -41,7 +75,7 @@ public static SerializableData GetFromObject(Object object) { // PS: if you got a better idea, I'm all ears :) // int instanceId = System.identityHashCode(object); - String objectClassName = object.getClass().getName(); + String objectClassName = object.getClass().getTypeName(); String serializedString = null; boolean isSerialized = false; @@ -53,17 +87,6 @@ public static SerializableData GetFromObject(Object object) { System.err.println("ERROR: Cannot serialize specific argument: " + e); } - return new SerializableData(objectClassName, serializedString, instanceId, false, isSerialized); - } - - @Override - public String toString() { - return "SerializableData{" + - "fullyQualifiedTypeName='" + fullyQualifiedTypeName + '\'' + - ", dataAsJson='" + dataAsJson + '\'' + - ", instanceId=" + instanceId + - ", isNull=" + isNull + - ", isSerialized=" + isSerialized + - '}'; + return new SerializableData(objectClassName, serializedString, instanceId, isSerialized); } } \ No newline at end of file From a448d0959949c4211be41745c19626d6cf933d33 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 12:20:02 +0100 Subject: [PATCH 005/244] fix: broken visitors with thrown (need to fix this later) --- .../gilesi/instrumentation/visitors/ConstructorVisitor.java | 3 +-- .../maracas/gilesi/instrumentation/visitors/MethodVisitor.java | 3 +-- .../gilesi/instrumentation/visitors/StaticMethodVisitor.java | 3 +-- 3 files changed, 3 insertions(+), 6 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java index 8a985ff9..4e6f3f1e 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java @@ -21,8 +21,7 @@ public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.This(typing = DYNAMIC) Object instance, - @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { + @Advice.This(typing = DYNAMIC) Object instance) { MethodTracer.addMethodTrace(origin, arguments, returned, instance); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java index 8210506d..e22bc24c 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java @@ -22,8 +22,7 @@ public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.This(typing = DYNAMIC) Object instance, - @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { + @Advice.This(typing = DYNAMIC) Object instance) { MethodTracer.addMethodTrace(origin, arguments, returned, instance); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java index b0a8c648..5f17d72d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java @@ -20,8 +20,7 @@ public static Object enter( public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.Thrown(typing = DYNAMIC) Throwable thrown) { + @Advice.Return(typing = DYNAMIC) Object returned) { MethodTracer.addMethodTrace(origin, arguments, returned); } } From 818af602488ce088e3486289894d65530bdfc74a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 12:20:25 +0100 Subject: [PATCH 006/244] feat: further refactoring of the code --- .../github/maracas/gilesi/confgen/Main.java | 6 +- .../models}/InstrumentationParameter.java | 2 +- .../models}/InstrumentationParameters.java | 2 +- Instrumentation/build.gradle | 6 +- .../maracas/gilesi/instrumentation/Agent.java | 17 +-- .../gilesi/instrumentation/MethodTracer.java | 4 +- .../models/SerializableData.java | 6 +- .../gilesi/instrumentation/MethodTrace.java | 49 --------- .../instrumentation/models/MethodTrace.java | 101 ++++++++++++++++++ .../{ => models}/SerializableData.java | 80 ++++++++------ .../github/maracas/gilesi/traceview/Main.java | 68 ++++++------ .../maracas/gilesi/traceview/TraceEvent.java | 2 +- run-test-workflow.cmd | 11 +- test.cmd | 1 + 14 files changed, 215 insertions(+), 140 deletions(-) rename ConfGen/src/main/java/com/github/maracas/gilesi/{confgen => instrumentation/models}/InstrumentationParameter.java (71%) rename ConfGen/src/main/java/com/github/maracas/gilesi/{confgen => instrumentation/models}/InstrumentationParameters.java (69%) delete mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java rename TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/{ => models}/SerializableData.java (50%) create mode 100644 test.cmd diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index f59ed04a..140e8541 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -2,12 +2,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.github.maracas.roseau.api.SpoonAPIExtractor; +import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; import com.github.maracas.roseau.api.model.ConstructorDecl; import com.github.maracas.roseau.api.model.MethodDecl; -import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; +import com.github.maracas.roseau.api.SpoonAPIExtractor; import spoon.Launcher; import spoon.reflect.CtModel; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java similarity index 71% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameter.java rename to ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index 46582d6f..1044eda5 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameter.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.confgen; +package com.github.maracas.gilesi.instrumentation.models; import java.util.List; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java similarity index 69% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameters.java rename to ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 7b849ad5..782fefb4 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.confgen; +package com.github.maracas.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 86a9f00d..21320b39 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -26,17 +26,17 @@ dependencies { jar { manifest { attributes 'Premain-Class': 'com.github.maracas.gilesi.instrumentation.Agent', - 'Agent-Class': 'com.github.maracas.gilesi.instrumentation.Agentn', + 'Agent-Class': 'com.github.maracas.gilesi.instrumentation.Agent', 'Launcher-Agent-Class': 'com.github.maracas.gilesi.instrumentation.Agent', 'Can-Retransform-Classes': 'true', 'Can-Redefine-Classes': 'true', - 'Main-Class': 'com.github.maracas.gilesi.instrumentation.Main', + 'Main-Class': 'com.github.maracas.gilesi.instrumentation.Agent', 'Multi-Release': 'true' } } application { - mainClass = 'com.github.maracas.gilesi.instrumentation.Main' + mainClass = 'com.github.maracas.gilesi.instrumentation.Agent' } description = 'Agent distribution.' diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index b538ad31..5ce2d9f0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -32,6 +32,7 @@ public static void SaveTraceResults() { objectMapper.enable(SerializationFeature.INDENT_OUTPUT); objectMapper.writeValue(outputFile, MethodTracer.getMethodTraces()); } catch (Exception e) { + System.err.println("ERROR"); e.printStackTrace(); } @@ -42,7 +43,7 @@ public static void SaveTraceResults() { Our primary method to install the agent required to trace methods during execution We take in as parameter a JSON file with the list of methods to instrument and their class */ - private static void installAgent(String arg, Instrumentation inst) throws IOException { + private static void installAgent(String arg, Instrumentation inst) { // First install the ByteBuddy Agent required to redefine classes during execution // Sometimes this can fail, so try catch it try { @@ -54,9 +55,6 @@ private static void installAgent(String arg, Instrumentation inst) throws IOExce return; } - // Then add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); - // Get the parameters File configurationFile = new File(arg); if (!configurationFile.exists()) { @@ -79,6 +77,9 @@ private static void installAgent(String arg, Instrumentation inst) throws IOExce for (InstrumentationParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { MethodTracer.instrumentClassForTracingAgent(inst, instrumentationParameter); } + + // Then add a shutdown hook to save all method execution traces at exit + Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); } /* @@ -86,7 +87,7 @@ private static void installAgent(String arg, Instrumentation inst) throws IOExce Agents invoked using premain are specified with the -javaagent switch. (https://stackoverflow.com/a/19789168) */ - public static void premain(String arg, Instrumentation inst) throws IOException { + public static void premain(String arg, Instrumentation inst) { installAgent(arg, inst); } @@ -96,7 +97,11 @@ Agents started with agentmain can be attached programatically using the Sun tool -- the method for introducing dynamic agents is implementation-dependent). (https://stackoverflow.com/a/19789168) */ - public static void agentmain(String arg, Instrumentation inst) throws IOException { + public static void agentmain(String arg, Instrumentation inst) { installAgent(arg, inst); } + + public static void main(String[] args) { + System.err.println("This program cannot be executed standalone."); + } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java index 1c765994..a4a2587d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java @@ -89,8 +89,8 @@ private static String getOriginName(Executable origin) { Constructor constructor = (Constructor) origin; originName = constructor.toGenericString(); } else { - System.out.println("BUGBUGBUG: Unknown Originating Executable Type!"); - System.out.println(origin.getClass().getName()); + System.err.println("BUGBUGBUG: Unknown Originating Executable Type!"); + System.err.println(origin.getClass().getName()); originName = origin.toString(); } return originName; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index 10cd176f..5d967273 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -38,12 +38,12 @@ public void setInstanceId(int instanceId) { this.instanceId = instanceId; } - public boolean isSerialized() { + public boolean getIsSerialized() { return isSerialized; } - public void setSerialized(boolean serialized) { - isSerialized = serialized; + public void setIsSerialized(boolean isSerialized) { + this.isSerialized = isSerialized; } @JsonCreator diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java deleted file mode 100644 index beec0f6e..00000000 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTrace.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.maracas.gilesi.instrumentation; - -import java.util.List; - -public class MethodTrace { - public String methodSignature; - public SerializableData instance; - public List preCallArguments; - public List postCallArguments; - public SerializableData returnedValue; - public long timeStampEntry; - public long timeStampExit; - - public MethodTrace(String methodSignature, SerializableData instance, List preCallArguments, - List postCallArguments, SerializableData returnedValue, long timeStampEntry, - long timeStampExit) - { - this.instance = instance; - this.methodSignature = methodSignature; - this.timeStampEntry = timeStampEntry; - this.postCallArguments = postCallArguments; - this.preCallArguments = preCallArguments; - this.returnedValue = returnedValue; - this.timeStampExit = timeStampExit; - } - - public MethodTrace() {} - - @Override - public String toString() { - return "MethodTrace{" + - "methodSignature='" + methodSignature + '\'' + - ", instance=" + instance + - ", preCallArguments=" + preCallArguments + - ", postCallArguments=" + postCallArguments + - ", returnedValue=" + returnedValue + - ", timeStampEntry=" + timeStampEntry + - ", timeStampExit=" + timeStampExit + - '}'; - } - - public long getTimeStampEntry() { - return timeStampEntry; - } - - public long getTimeStampExit() { - return timeStampExit; - } -} diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java new file mode 100644 index 00000000..a3626a4b --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java @@ -0,0 +1,101 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class MethodTrace { + private String methodSignature; + private SerializableData instance; + private List preCallArguments; + private List postCallArguments; + private SerializableData returnedValue; + private long timeStampEntry; + private long timeStampExit; + private SerializableData exceptionThrown; + + @JsonCreator + public MethodTrace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") SerializableData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") SerializableData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") SerializableData exceptionThrown) { + this.methodSignature = methodSignature; + this.instance = instance; + this.preCallArguments = preCallArguments; + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampEntry = timeStampEntry; + this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public SerializableData getInstance() { + return instance; + } + + public void setInstance(SerializableData instance) { + this.instance = instance; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public SerializableData getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(SerializableData returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } + + public SerializableData getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(SerializableData exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } +} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java similarity index 50% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java rename to TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index d38403ed..5d967273 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/SerializableData.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -1,31 +1,66 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.maracas.gilesi.instrumentation.models; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; public class SerializableData { private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - public String fullyQualifiedTypeName; - public String dataAsJson; - public int instanceId; - public boolean isNull; - public boolean isSerialized; + private String fullyQualifiedTypeName; + private String dataAsJson; + private int instanceId; + private boolean isSerialized; - public SerializableData(String fullyQualifiedTypeName, String dataAsJson, int instanceId, boolean isNull, boolean isSerialized) { + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public String getDataAsJson() { + return dataAsJson; + } + + public void setDataAsJson(String dataAsJson) { this.dataAsJson = dataAsJson; + } + + public int getInstanceId() { + return instanceId; + } + + public void setInstanceId(int instanceId) { this.instanceId = instanceId; - this.isNull = isNull; + } + + public boolean getIsSerialized() { + return isSerialized; + } + + public void setIsSerialized(boolean isSerialized) { this.isSerialized = isSerialized; } - public SerializableData() {} + @JsonCreator + public SerializableData( + @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, + @JsonProperty("dataAsJson") String dataAsJson, + @JsonProperty("instanceId") int instanceId, + @JsonProperty("isSerialized") boolean isSerialized) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + this.dataAsJson = dataAsJson; + this.instanceId = instanceId; + this.isSerialized = isSerialized; + } - public static SerializableData GetFromObject(Object object) { + public static SerializableData of(Object object) { if (object == null) { - return new SerializableData(null, null, -1, true, false); + return null; } // /!\ CAUTION @@ -40,7 +75,7 @@ public static SerializableData GetFromObject(Object object) { // PS: if you got a better idea, I'm all ears :) // int instanceId = System.identityHashCode(object); - String objectClassName = object.getClass().getName(); + String objectClassName = object.getClass().getTypeName(); String serializedString = null; boolean isSerialized = false; @@ -49,24 +84,9 @@ public static SerializableData GetFromObject(Object object) { serializedString = objectMapper.writeValueAsString(object); isSerialized = true; } catch (JsonProcessingException e) { - //System.out.println("Cannot serialize specific argument: " + e); + System.err.println("ERROR: Cannot serialize specific argument: " + e); } - return new SerializableData(objectClassName, serializedString, instanceId, false, isSerialized); - } - - /*public String getJavaCodeEquivalentAsString() { - return "TODO!"; - }*/ - - @Override - public String toString() { - return "SerializableData{" + - "fullyQualifiedTypeName='" + fullyQualifiedTypeName + '\'' + - ", dataAsJson='" + dataAsJson + '\'' + - ", instanceId=" + instanceId + - ", isNull=" + isNull + - ", isSerialized=" + isSerialized + - '}'; + return new SerializableData(objectClassName, serializedString, instanceId, isSerialized); } -} +} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 8c8901c7..5e65f838 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -1,8 +1,8 @@ package com.github.maracas.gilesi.traceview; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.maracas.gilesi.instrumentation.MethodTrace; -import com.github.maracas.gilesi.instrumentation.SerializableData; +import com.github.maracas.gilesi.instrumentation.models.MethodTrace; +import com.github.maracas.gilesi.instrumentation.models.SerializableData; import org.apache.commons.text.StringEscapeUtils; import java.io.File; @@ -31,14 +31,14 @@ private static String getInstanceVarName(int instanceId) { } private static String serializableDataToCode(SerializableData arg) { - if (arg.isNull) { + if (arg == null) { return "null"; - } else if (arg.isSerialized) { + } else if (arg.getIsSerialized()) { return serializableDataToJava(arg); - } else if (mapOfInstancesToIndexes.containsKey(arg.instanceId)) { - return getInstanceVarName(arg.instanceId); + } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { + return getInstanceVarName(arg.getInstanceId()); } else { - return "InstanceId{" + arg.instanceId + "}"; + return "InstanceId{" + arg.getInstanceId() + "}"; } } @@ -50,41 +50,41 @@ private static String getCleanedType(String FQN) { } private static String serializableDataToJava(SerializableData serializableData) { - String valueToBeEqualTo = serializableData.dataAsJson; - String FQN = getCleanedType(serializableData.fullyQualifiedTypeName); + String valueToBeEqualTo = serializableData.getDataAsJson(); + String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.String") && !FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Double") && !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long")) { - valueToBeEqualTo = "new ObjectMapper().readValue(\"" + StringEscapeUtils.escapeJava(serializableData.dataAsJson) + "\", " + FQN + ".class)"; + valueToBeEqualTo = "new ObjectMapper().readValue(\"" + StringEscapeUtils.escapeJava(serializableData.getDataAsJson()) + "\", " + FQN + ".class)"; } return valueToBeEqualTo; } private static String getReturnStatementAsCode(SerializableData serializableData) { - if (listOfDefinedInstances.contains(serializableData.instanceId)) { - return getInstanceVarName(serializableData.instanceId); + if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { + return getInstanceVarName(serializableData.getInstanceId()); } else { - String returnType = getCleanedType(serializableData.fullyQualifiedTypeName); - listOfDefinedInstances.add(serializableData.instanceId); - return returnType + " " + getInstanceVarName(serializableData.instanceId); + String returnType = getCleanedType(serializableData.getFullyQualifiedTypeName()); + listOfDefinedInstances.add(serializableData.getInstanceId()); + return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); } } private static String traceToCode(MethodTrace methodTrace) { - String cleanedMethodName = methodTrace.methodSignature.split("\\(")[0]; + String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - boolean isConstructor = !methodTrace.instance.isNull && methodTrace.instance.fullyQualifiedTypeName.equals(cleanedMethodName); - boolean isInstanceCall = !methodTrace.instance.isNull && !methodTrace.instance.fullyQualifiedTypeName.equals(cleanedMethodName); + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + boolean isInstanceCall = methodTrace.getInstance() != null && !methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); if (isConstructor) { cleanedMethodName = "new " + cleanedMethodName; } else if (isInstanceCall) { String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; - cleanedMethodName = getInstanceVarName(methodTrace.instance.instanceId) + "." + methodNameOnly; + cleanedMethodName = getInstanceVarName(methodTrace.getInstance().getInstanceId()) + "." + methodNameOnly; } if (isConstructor) { @@ -95,18 +95,18 @@ private static String traceToCode(MethodTrace methodTrace) { // Value returned is of course, the instance! - cleanedMethodName = getReturnStatementAsCode(methodTrace.instance) + " = " + cleanedMethodName; - } else if (!methodTrace.returnedValue.isNull) { + cleanedMethodName = getReturnStatementAsCode(methodTrace.getInstance()) + " = " + cleanedMethodName; + } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - cleanedMethodName = getReturnStatementAsCode(methodTrace.returnedValue) + " = " + cleanedMethodName; + cleanedMethodName = getReturnStatementAsCode(methodTrace.getReturnedValue()) + " = " + cleanedMethodName; } List argList = new ArrayList<>(); - for (SerializableData arg : methodTrace.preCallArguments) { + for (SerializableData arg : methodTrace.getPreCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); String argumentDeclaration = getReturnStatementAsCode(arg) + " = " + argumentValueAsCode; - argList.add(getInstanceVarName(arg.instanceId)); + argList.add(getInstanceVarName(arg.getInstanceId())); cleanedMethodName = argumentDeclaration + ";\n" + cleanedMethodName; } @@ -115,25 +115,25 @@ private static String traceToCode(MethodTrace methodTrace) { private static String traceArgumentsToAssert(MethodTrace methodTrace) { List argList = new ArrayList<>(); - for (SerializableData arg : methodTrace.postCallArguments) { + for (SerializableData arg : methodTrace.getPostCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); - argList.add("assert " + getInstanceVarName(arg.instanceId) + ".equals(" + argumentValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"); + argList.add("assert " + getInstanceVarName(arg.getInstanceId()) + ".equals(" + argumentValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"); } return String.join("\n", argList); } private static String traceToAssert(MethodTrace methodTrace) { - String cleanedMethodName = methodTrace.methodSignature.split("\\(")[0]; + String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - boolean isConstructor = !methodTrace.instance.isNull && methodTrace.instance.fullyQualifiedTypeName.equals(cleanedMethodName); + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); if (isConstructor) { // Nothing to do! - } else if (!methodTrace.returnedValue.isNull) { + } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - String returnValueAsCode = serializableDataToCode(methodTrace.returnedValue); - return "assert " + getInstanceVarName(methodTrace.returnedValue.instanceId) + ".equals(" + returnValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"; + String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); + return "assert " + getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()) + ".equals(" + returnValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"; } return null; @@ -148,8 +148,8 @@ private static List getTraceEventsFromMethodTraces(MethodTrace[] met List events = new ArrayList<>(); for (MethodTrace methodTrace : methodTraces) { - events.add(new TraceEvent("Entry", methodTrace.timeStampEntry, methodTrace)); - events.add(new TraceEvent("Exit", methodTrace.timeStampExit, methodTrace)); + events.add(new TraceEvent("Entry", methodTrace.getTimeStampEntry(), methodTrace)); + events.add(new TraceEvent("Exit", methodTrace.getTimeStampExit(), methodTrace)); } return events.stream().sorted(Comparator.comparing(TraceEvent::At)).toList(); @@ -180,7 +180,7 @@ public static void main(String[] args) throws IOException { List eventsSortedByTimeStamp = getTraceEventsFromMethodTraces(methodTraces); /*for (TraceEvent event : eventsSortedByTimeStamp) { - System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().methodSignature + "]"); + System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().getMethodSignature() + "]"); }*/ for (TraceEvent event : eventsSortedByTimeStamp) { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java index 5e6d79c8..debbe18e 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java @@ -1,6 +1,6 @@ package com.github.maracas.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.MethodTrace; +import com.github.maracas.gilesi.instrumentation.models.MethodTrace; public record TraceEvent(String What, long At, MethodTrace About) { diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index e9ef45d9..143f1893 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -1,38 +1,33 @@ @echo off + +call run-clean-workflow.cmd + set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 REM build samples cd Samples -rmdir /Q /S sampleclient\build -rmdir /Q /S samplelibrary\build call .\gradlew.bat jar cd .. REM build confgen cd ConfGen -rmdir /Q /S build call .\gradlew.bat shadowJar cd .. REM build traceview cd TraceView -rmdir /Q /S build call .\gradlew.bat shadowJar cd .. REM build tool cd Instrumentation -rmdir /Q /S build call .\gradlew.bat shadowJar cd .. -del "%CD%\TestWorkflowConfiguration.json" %JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.json" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" cd Samples -del sampleclient\MethodTraces.json call .\gradlew.bat sampleclient:test cd .. -del %CD%\Samples\sampleclient\TraceView.Output.txt %JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" > %CD%\Samples\sampleclient\TraceView.Output.txt \ No newline at end of file diff --git a/test.cmd b/test.cmd new file mode 100644 index 00000000..c3921363 --- /dev/null +++ b/test.cmd @@ -0,0 +1 @@ +%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.maracas.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.json" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.maracas.gilesi.samples.sampleclient.Main2 \ No newline at end of file From cdb67a900e489197045e9e6749a6f7a5ea466cdc Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 12:24:58 +0100 Subject: [PATCH 007/244] fix: remove useless IsSerialized boolean from traces --- .../models/SerializableData.java | 17 ++--------------- .../models/SerializableData.java | 17 ++--------------- .../github/maracas/gilesi/traceview/Main.java | 2 +- 3 files changed, 5 insertions(+), 31 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index 5d967273..9c045cb6 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -12,7 +12,6 @@ public class SerializableData { private String fullyQualifiedTypeName; private String dataAsJson; private int instanceId; - private boolean isSerialized; public String getFullyQualifiedTypeName() { return fullyQualifiedTypeName; @@ -38,24 +37,14 @@ public void setInstanceId(int instanceId) { this.instanceId = instanceId; } - public boolean getIsSerialized() { - return isSerialized; - } - - public void setIsSerialized(boolean isSerialized) { - this.isSerialized = isSerialized; - } - @JsonCreator public SerializableData( @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId, - @JsonProperty("isSerialized") boolean isSerialized) { + @JsonProperty("instanceId") int instanceId) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; this.dataAsJson = dataAsJson; this.instanceId = instanceId; - this.isSerialized = isSerialized; } public static SerializableData of(Object object) { @@ -78,15 +67,13 @@ public static SerializableData of(Object object) { String objectClassName = object.getClass().getTypeName(); String serializedString = null; - boolean isSerialized = false; try { serializedString = objectMapper.writeValueAsString(object); - isSerialized = true; } catch (JsonProcessingException e) { System.err.println("ERROR: Cannot serialize specific argument: " + e); } - return new SerializableData(objectClassName, serializedString, instanceId, isSerialized); + return new SerializableData(objectClassName, serializedString, instanceId); } } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index 5d967273..9c045cb6 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -12,7 +12,6 @@ public class SerializableData { private String fullyQualifiedTypeName; private String dataAsJson; private int instanceId; - private boolean isSerialized; public String getFullyQualifiedTypeName() { return fullyQualifiedTypeName; @@ -38,24 +37,14 @@ public void setInstanceId(int instanceId) { this.instanceId = instanceId; } - public boolean getIsSerialized() { - return isSerialized; - } - - public void setIsSerialized(boolean isSerialized) { - this.isSerialized = isSerialized; - } - @JsonCreator public SerializableData( @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId, - @JsonProperty("isSerialized") boolean isSerialized) { + @JsonProperty("instanceId") int instanceId) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; this.dataAsJson = dataAsJson; this.instanceId = instanceId; - this.isSerialized = isSerialized; } public static SerializableData of(Object object) { @@ -78,15 +67,13 @@ public static SerializableData of(Object object) { String objectClassName = object.getClass().getTypeName(); String serializedString = null; - boolean isSerialized = false; try { serializedString = objectMapper.writeValueAsString(object); - isSerialized = true; } catch (JsonProcessingException e) { System.err.println("ERROR: Cannot serialize specific argument: " + e); } - return new SerializableData(objectClassName, serializedString, instanceId, isSerialized); + return new SerializableData(objectClassName, serializedString, instanceId); } } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 5e65f838..1a031173 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -33,7 +33,7 @@ private static String getInstanceVarName(int instanceId) { private static String serializableDataToCode(SerializableData arg) { if (arg == null) { return "null"; - } else if (arg.getIsSerialized()) { + } else if (arg.getDataAsJson() != null) { return serializableDataToJava(arg); } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { return getInstanceVarName(arg.getInstanceId()); From fa66447dc03590fbdc4fc44fe4c54296fe0e14e4 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 13:40:27 +0100 Subject: [PATCH 008/244] fix: simplify bytebuddy visitors --- .../gilesi/instrumentation/MethodTracer.java | 39 +++---------------- .../visitors/ConstructorVisitor.java | 27 ------------- .../visitors/MethodVisitor.java | 16 ++++++-- .../visitors/StaticMethodVisitor.java | 26 ------------- 4 files changed, 18 insertions(+), 90 deletions(-) delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java index a4a2587d..ee908e40 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java @@ -3,17 +3,19 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.MethodTrace; import com.github.maracas.gilesi.instrumentation.models.SerializableData; -import com.github.maracas.gilesi.instrumentation.visitors.ConstructorVisitor; import com.github.maracas.gilesi.instrumentation.visitors.MethodVisitor; -import com.github.maracas.gilesi.instrumentation.visitors.StaticMethodVisitor; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; import net.bytebuddy.matcher.ElementMatchers; +import net.bytebuddy.utility.JavaModule; import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; +import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Collection; import java.util.List; @@ -33,37 +35,8 @@ public static void instrumentClassForTracingAgent(Instrumentation inst, Instrume new AgentBuilder.Default() .type(named(instrumentationParameter.ClassName)) - .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> - builder - .visit(Advice - .to(StaticMethodVisitor.class) - .on(ElementMatchers - .not( - ElementMatchers.isTypeInitializer() - .or(ElementMatchers.isConstructor()) - ).and(ElementMatchers.isStatic()) - .and(ElementMatchers.namedOneOf(methodsArray)) - ) - ) - .visit(Advice - .to(ConstructorVisitor.class) - .on(ElementMatchers - .not( - ElementMatchers.isTypeInitializer() - ).and(ElementMatchers.isConstructor()) - .and(ElementMatchers.namedOneOf(methodsArray)) - ) - ) - .visit(Advice - .to(MethodVisitor.class) - .on(ElementMatchers - .not( - ElementMatchers.isTypeInitializer() - .or(ElementMatchers.isConstructor()) - .or(ElementMatchers.isStatic()) - ).and(ElementMatchers.namedOneOf(methodsArray)) - ) - ) + .transform((DynamicType.Builder builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, ProtectionDomain protectionDomain) -> + builder.visit(Advice.to(MethodVisitor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(methodsArray)))) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) .with(AgentBuilder.TypeStrategy.Default.REDEFINE) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java deleted file mode 100644 index 4e6f3f1e..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorVisitor.java +++ /dev/null @@ -1,27 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.visitors; - -import com.github.maracas.gilesi.instrumentation.MethodTracer; -import net.bytebuddy.asm.Advice; - -import java.lang.reflect.Executable; - -import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC; - -public class ConstructorVisitor { - @Advice.OnMethodEnter - public static Object enter( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); - return null; - } - - @Advice.OnMethodExit - public static void exit( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.This(typing = DYNAMIC) Object instance) { - MethodTracer.addMethodTrace(origin, arguments, returned, instance); - } -} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java index e22bc24c..c71a3c01 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java @@ -12,8 +12,12 @@ public class MethodVisitor { public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.This(typing = DYNAMIC) Object instance) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, instance); + @Advice.This(typing = DYNAMIC, optional = true) Object instance) { + if (instance == null) { + MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); + } else { + MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, instance); + } return null; } @@ -22,7 +26,11 @@ public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.This(typing = DYNAMIC) Object instance) { - MethodTracer.addMethodTrace(origin, arguments, returned, instance); + @Advice.This(typing = DYNAMIC, optional = true) Object instance) { + if (instance == null) { + MethodTracer.addMethodTrace(origin, arguments, returned); + } else { + MethodTracer.addMethodTrace(origin, arguments, returned, instance); + } } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java deleted file mode 100644 index 5f17d72d..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/StaticMethodVisitor.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.visitors; - -import com.github.maracas.gilesi.instrumentation.MethodTracer; -import net.bytebuddy.asm.Advice; - -import java.lang.reflect.Executable; - -import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC; - -public class StaticMethodVisitor { - @Advice.OnMethodEnter - public static Object enter( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); - return null; - } - - @Advice.OnMethodExit - public static void exit( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.Return(typing = DYNAMIC) Object returned) { - MethodTracer.addMethodTrace(origin, arguments, returned); - } -} From 497dc9b2dcf9278ec501230ab6abcc676d4b00b4 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 14:18:20 +0100 Subject: [PATCH 009/244] feat: save information about exceptions being thrown --- .../gilesi/instrumentation/MethodTracer.java | 135 ++---------------- .../models/SerializableData.java | 2 +- .../visitors/MethodVisitor.java | 33 ++--- 3 files changed, 27 insertions(+), 143 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java index ee908e40..4819b5df 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java @@ -17,15 +17,14 @@ import java.lang.reflect.Method; import java.security.ProtectionDomain; import java.util.ArrayList; +import java.util.Arrays; import java.util.Collection; import java.util.List; +import java.util.stream.Collectors; import static net.bytebuddy.matcher.ElementMatchers.named; public class MethodTracer { - // Storage for onEntry traces yet to be completed with an onExit trace - private static final ArrayList notYetCompletedMethodTraces = new ArrayList<>(); - // Storage for traces collected so far private static final ArrayList methodTraces = new ArrayList<>(); @@ -73,9 +72,7 @@ private static List getArgumentsAsSerializableData(Object[] ar List argumentStrings = new ArrayList<>(); if (arguments != null) { - for (Object argument : arguments) { - argumentStrings.add(SerializableData.of(argument)); - } + argumentStrings = Arrays.stream(arguments).map(SerializableData::valueOf).collect(Collectors.toList()); } return argumentStrings; @@ -94,71 +91,16 @@ private static List getArgumentsAsSerializableData(Object[] ar * @param origin The originating trace Executable object * @param arguments The originating trace argument list on entry */ - public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arguments, Object instance) { - // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.currentTimeMillis(); - - String methodSignature = getOriginName(origin); - SerializableData serializableInstance = SerializableData.of(instance); - List preCallArguments = getArgumentsAsSerializableData(arguments); - long timeStampEntry = entryMarker; - - MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1, null); - notYetCompletedMethodTraces.add(methodTrace); - } - - /** - * Collects information about a method execution call at entry, - * for further collection later on exit - * This method generates an incomplete partial method trace with on entry information, - * and caches it temporarily for use on exit. - * Callers must call later addMethodTrace on exit to complete the trace and make it available. - *

- * This method is public so it can be accessed as part of the modified instrumented classes - * without security problems at the JVM level - * - * @param origin The originating trace Executable object - * @param arguments The originating trace argument list on entry - */ - public static void addNotYetCompletedMethodTrace(Executable origin, Object[] arguments) { + public static MethodTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { // Need to fetch this asap to not be off on the measurements! long entryMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); + SerializableData serializableInstance = SerializableData.valueOf(instance); List preCallArguments = getArgumentsAsSerializableData(arguments); long timeStampEntry = entryMarker; - MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, null, null, timeStampEntry, -1, null); - notYetCompletedMethodTraces.add(methodTrace); - } - - private static MethodTrace getMatchingIncompleteEntryTrace(String originName, SerializableData serializableInstance, long timeStampExit) { - MethodTrace originatingMethodTrace = null; - - if (serializableInstance != null) { - for (MethodTrace methodTrace : notYetCompletedMethodTraces) { - if (methodTrace.getMethodSignature().equals(originName) && - methodTrace.getInstance().getInstanceId() == serializableInstance.getInstanceId() - && methodTrace.getTimeStampEntry() <= timeStampExit) { - originatingMethodTrace = methodTrace; - break; - } - } - } - - // It is possible we cannot find a trace with the instanceId, because, it was a constructor entry - // In such case, look for other cases - if (originatingMethodTrace == null) { - for (MethodTrace methodTrace : notYetCompletedMethodTraces) { - if (methodTrace.getMethodSignature().equals(originName) && methodTrace.getInstance() == null - && methodTrace.getTimeStampEntry() <= timeStampExit) { - originatingMethodTrace = methodTrace; - break; - } - } - } - - return originatingMethodTrace; + return new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1, null); } /** @@ -178,71 +120,20 @@ private static MethodTrace getMatchingIncompleteEntryTrace(String originName, Se * @param arguments The originating trace argument list on entry * @param returned The data returned by the originating trace */ - public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance) { + public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, MethodTrace originatingMethodTrace) { // Need to fetch this asap to not be off on the measurements! long exitMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); - SerializableData serializableInstance = SerializableData.of(instance); - List preCallArguments = null; + SerializableData serializableInstance = SerializableData.valueOf(instance); + List preCallArguments = originatingMethodTrace.getPreCallArguments(); List postCallArguments = getArgumentsAsSerializableData(arguments); - SerializableData returnedValue = SerializableData.of(returned); - long timeStampEntry = -1; + SerializableData returnedValue = SerializableData.valueOf(returned); + long timeStampEntry = originatingMethodTrace.getTimeStampEntry(); long timeStampExit = exitMarker; + SerializableData exceptionThrown = SerializableData.valueOf(thrown); - // Attempt to find a matching onEntry trace, if we cannot, stick to defaults (Entry = -1, preCallArguments = null) - MethodTrace originatingMethodTrace = getMatchingIncompleteEntryTrace(methodSignature, serializableInstance, timeStampExit); - if (originatingMethodTrace != null) { - preCallArguments = originatingMethodTrace.getPreCallArguments(); - timeStampEntry = originatingMethodTrace.getTimeStampEntry(); - - // Remove from cache - notYetCompletedMethodTraces.remove(originatingMethodTrace); - } - - MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, null); - methodTraces.add(methodTrace); - } - - /** - * Collects information about a method execution call at exit, - * with further data completion with an earlier partial trace if available from entry. - * This method generates an incomplete partial method trace with on exit information, - * and completes it with entry information if available, to cache a complete trace. - * Callers must call earlier addNotYetCompletedMethodTrace to provide entry information to - * have complete trace data. - *

- * Callers must call later getMethodTraces to retrieve the trace information. - *

- * This method is public so it can be accessed as part of the modified instrumented classes - * without security problems at the JVM level - * - * @param origin The originating trace Executable object - * @param arguments The originating trace argument list on entry - * @param returned The data returned by the originating trace - */ - public static void addMethodTrace(Executable origin, Object[] arguments, Object returned) { - // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.currentTimeMillis(); - - String methodSignature = getOriginName(origin); - List preCallArguments = null; - List postCallArguments = getArgumentsAsSerializableData(arguments); - SerializableData returnedValue = SerializableData.of(returned); - long timeStampEntry = -1; - long timeStampExit = exitMarker; - - // Attempt to find a matching onEntry trace, if we cannot, stick to defaults (Entry = -1, preCallArguments = null) - MethodTrace originatingMethodTrace = getMatchingIncompleteEntryTrace(methodSignature, null, timeStampExit); - if (originatingMethodTrace != null) { - preCallArguments = originatingMethodTrace.getPreCallArguments(); - timeStampEntry = originatingMethodTrace.getTimeStampEntry(); - - // Remove from cache - notYetCompletedMethodTraces.remove(originatingMethodTrace); - } - - MethodTrace methodTrace = new MethodTrace(methodSignature, null, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, null); + MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); methodTraces.add(methodTrace); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java index 9c045cb6..1a6fe96a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java @@ -47,7 +47,7 @@ public SerializableData( this.instanceId = instanceId; } - public static SerializableData of(Object object) { + public static SerializableData valueOf(Object object) { if (object == null) { return null; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java index c71a3c01..ac82809a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java @@ -1,36 +1,29 @@ package com.github.maracas.gilesi.instrumentation.visitors; import com.github.maracas.gilesi.instrumentation.MethodTracer; +import com.github.maracas.gilesi.instrumentation.models.MethodTrace; import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; -import static net.bytebuddy.implementation.bytecode.assign.Assigner.Typing.DYNAMIC; - public class MethodVisitor { - @Advice.OnMethodEnter + @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.This(typing = DYNAMIC, optional = true) Object instance) { - if (instance == null) { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments); - } else { - MethodTracer.addNotYetCompletedMethodTrace(origin, arguments, instance); - } - return null; + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + return MethodTracer.getPartialMethodTrace(origin, arguments, instance); } - @Advice.OnMethodExit + @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) public static void exit( @Advice.Origin Executable origin, - @Advice.AllArguments(typing = DYNAMIC) Object[] arguments, - @Advice.Return(typing = DYNAMIC) Object returned, - @Advice.This(typing = DYNAMIC, optional = true) Object instance) { - if (instance == null) { - MethodTracer.addMethodTrace(origin, arguments, returned); - } else { - MethodTracer.addMethodTrace(origin, arguments, returned, instance); - } + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, + @Advice.Thrown Throwable thrown, + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) MethodTrace entryTrace) { + MethodTracer.addMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); } } \ No newline at end of file From 7d276639d590f37e923718c8531fcf8a20f4e4f3 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 14:44:25 +0100 Subject: [PATCH 010/244] feat: rename a few things around --- .../maracas/gilesi/instrumentation/Agent.java | 5 +- ...{MethodTracer.java => TraceCollector.java} | 71 ++++-------- .../instrumentation/TraceDataFactory.java | 51 ++------- .../instrumentation/models/MethodTrace.java | 101 ------------------ .../instrumentation/models/PartialTrace.java | 57 ++++++++++ .../models/SerializableData.java | 79 -------------- .../gilesi/instrumentation/models/Trace.java | 63 +++++++++++ .../instrumentation/models/TraceData.java | 44 ++++++++ ...{MethodVisitor.java => MethodAdvisor.java} | 12 +-- .../visitors/MethodInstrumentor.java | 33 ++++++ .../instrumentation/models/MethodTrace.java | 101 ------------------ .../instrumentation/models/PartialTrace.java | 57 ++++++++++ .../gilesi/instrumentation/models/Trace.java | 63 +++++++++++ .../instrumentation/models/TraceData.java | 44 ++++++++ .../github/maracas/gilesi/traceview/Main.java | 38 +++---- .../maracas/gilesi/traceview/TraceEvent.java | 4 +- 16 files changed, 420 insertions(+), 403 deletions(-) rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/{MethodTracer.java => TraceCollector.java} (54%) rename TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java => Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java (51%) delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java rename Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/{MethodVisitor.java => MethodAdvisor.java} (69%) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java delete mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 5ce2d9f0..cb8552de 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -4,6 +4,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; @@ -30,7 +31,7 @@ public static void SaveTraceResults() { try { ObjectMapper objectMapper = new ObjectMapper(); objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - objectMapper.writeValue(outputFile, MethodTracer.getMethodTraces()); + objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); } catch (Exception e) { System.err.println("ERROR"); e.printStackTrace(); @@ -75,7 +76,7 @@ private static void installAgent(String arg, Instrumentation inst) { // Instrument every class for (InstrumentationParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { - MethodTracer.instrumentClassForTracingAgent(inst, instrumentationParameter); + MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } // Then add a shutdown hook to save all method execution traces at exit diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java similarity index 54% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 4819b5df..c849c581 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/MethodTracer.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,46 +1,21 @@ package com.github.maracas.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; -import com.github.maracas.gilesi.instrumentation.models.MethodTrace; -import com.github.maracas.gilesi.instrumentation.models.SerializableData; -import com.github.maracas.gilesi.instrumentation.visitors.MethodVisitor; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.type.TypeDescription; -import net.bytebuddy.dynamic.DynamicType; -import net.bytebuddy.matcher.ElementMatchers; -import net.bytebuddy.utility.JavaModule; +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.maracas.gilesi.instrumentation.models.TraceData; -import java.lang.instrument.Instrumentation; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; import java.lang.reflect.Method; -import java.security.ProtectionDomain; import java.util.ArrayList; import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.stream.Collectors; -import static net.bytebuddy.matcher.ElementMatchers.named; - -public class MethodTracer { +public class TraceCollector { // Storage for traces collected so far - private static final ArrayList methodTraces = new ArrayList<>(); - - public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - String[] methodsArray = new String[instrumentationParameter.ClassMethodsOrConstructors.size()]; - instrumentationParameter.ClassMethodsOrConstructors.toArray(methodsArray); - - new AgentBuilder.Default() - .type(named(instrumentationParameter.ClassName)) - .transform((DynamicType.Builder builder, TypeDescription typeDescription, ClassLoader classLoader, JavaModule javaModule, ProtectionDomain protectionDomain) -> - builder.visit(Advice.to(MethodVisitor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(methodsArray)))) - ) - .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) - .with(AgentBuilder.TypeStrategy.Default.REDEFINE) - .installOn(inst); - } + private static final ArrayList TRACES = new ArrayList<>(); /** * Gets the origin name from an Exectuable object with the signature if possible. @@ -68,11 +43,11 @@ private static String getOriginName(Executable origin) { return originName; } - private static List getArgumentsAsSerializableData(Object[] arguments) { - List argumentStrings = new ArrayList<>(); + private static List getArgumentsAsSerializableData(Object[] arguments) { + List argumentStrings = new ArrayList<>(); if (arguments != null) { - argumentStrings = Arrays.stream(arguments).map(SerializableData::valueOf).collect(Collectors.toList()); + argumentStrings = Arrays.stream(arguments).map(TraceDataFactory::valueOf).collect(Collectors.toList()); } return argumentStrings; @@ -91,16 +66,16 @@ private static List getArgumentsAsSerializableData(Object[] ar * @param origin The originating trace Executable object * @param arguments The originating trace argument list on entry */ - public static MethodTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { + public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { // Need to fetch this asap to not be off on the measurements! long entryMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); - SerializableData serializableInstance = SerializableData.valueOf(instance); - List preCallArguments = getArgumentsAsSerializableData(arguments); + TraceData serializableInstance = TraceDataFactory.valueOf(instance); + List preCallArguments = getArgumentsAsSerializableData(arguments); long timeStampEntry = entryMarker; - return new MethodTrace(methodSignature, serializableInstance, preCallArguments, null, null, timeStampEntry, -1, null); + return new PartialTrace(methodSignature, serializableInstance, preCallArguments, timeStampEntry); } /** @@ -120,21 +95,21 @@ public static MethodTrace getPartialMethodTrace(Executable origin, Object[] argu * @param arguments The originating trace argument list on entry * @param returned The data returned by the originating trace */ - public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, MethodTrace originatingMethodTrace) { + public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace) { // Need to fetch this asap to not be off on the measurements! long exitMarker = System.currentTimeMillis(); String methodSignature = getOriginName(origin); - SerializableData serializableInstance = SerializableData.valueOf(instance); - List preCallArguments = originatingMethodTrace.getPreCallArguments(); - List postCallArguments = getArgumentsAsSerializableData(arguments); - SerializableData returnedValue = SerializableData.valueOf(returned); - long timeStampEntry = originatingMethodTrace.getTimeStampEntry(); + TraceData serializableInstance = TraceDataFactory.valueOf(instance); + List preCallArguments = originatingTrace.getPreCallArguments(); + List postCallArguments = getArgumentsAsSerializableData(arguments); + TraceData returnedValue = TraceDataFactory.valueOf(returned); + long timeStampEntry = originatingTrace.getTimeStampEntry(); long timeStampExit = exitMarker; - SerializableData exceptionThrown = SerializableData.valueOf(thrown); + TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); - MethodTrace methodTrace = new MethodTrace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); - methodTraces.add(methodTrace); + Trace trace = new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); + TRACES.add(trace); } /** @@ -143,7 +118,7 @@ public static void addMethodTrace(Executable origin, Object[] arguments, Object * * @return The list of every cached trace during program execution */ - public static Collection getMethodTraces() { - return methodTraces; + public static Collection getMethodTraces() { + return TRACES; } } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java similarity index 51% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 9c045cb6..e9545686 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -1,53 +1,14 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.maracas.gilesi.instrumentation; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; +import com.github.maracas.gilesi.instrumentation.models.TraceData; -public class SerializableData { +public class TraceDataFactory { private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - private String fullyQualifiedTypeName; - private String dataAsJson; - private int instanceId; - - public String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; - } - - public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - } - - public String getDataAsJson() { - return dataAsJson; - } - - public void setDataAsJson(String dataAsJson) { - this.dataAsJson = dataAsJson; - } - - public int getInstanceId() { - return instanceId; - } - - public void setInstanceId(int instanceId) { - this.instanceId = instanceId; - } - - @JsonCreator - public SerializableData( - @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, - @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - this.dataAsJson = dataAsJson; - this.instanceId = instanceId; - } - - public static SerializableData of(Object object) { + public static TraceData valueOf(Object object) { if (object == null) { return null; } @@ -74,6 +35,6 @@ public static SerializableData of(Object object) { System.err.println("ERROR: Cannot serialize specific argument: " + e); } - return new SerializableData(objectClassName, serializedString, instanceId); + return new TraceData(objectClassName, serializedString, instanceId); } -} \ No newline at end of file +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java deleted file mode 100644 index a3626a4b..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class MethodTrace { - private String methodSignature; - private SerializableData instance; - private List preCallArguments; - private List postCallArguments; - private SerializableData returnedValue; - private long timeStampEntry; - private long timeStampExit; - private SerializableData exceptionThrown; - - @JsonCreator - public MethodTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") SerializableData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") SerializableData returnedValue, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") SerializableData exceptionThrown) { - this.methodSignature = methodSignature; - this.instance = instance; - this.preCallArguments = preCallArguments; - this.postCallArguments = postCallArguments; - this.returnedValue = returnedValue; - this.timeStampEntry = timeStampEntry; - this.timeStampExit = timeStampExit; - this.exceptionThrown = exceptionThrown; - } - - public String getMethodSignature() { - return methodSignature; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public SerializableData getInstance() { - return instance; - } - - public void setInstance(SerializableData instance) { - this.instance = instance; - } - - public List getPreCallArguments() { - return preCallArguments; - } - - public void setPreCallArguments(List preCallArguments) { - this.preCallArguments = preCallArguments; - } - - public List getPostCallArguments() { - return postCallArguments; - } - - public void setPostCallArguments(List postCallArguments) { - this.postCallArguments = postCallArguments; - } - - public SerializableData getReturnedValue() { - return returnedValue; - } - - public void setReturnedValue(SerializableData returnedValue) { - this.returnedValue = returnedValue; - } - - public long getTimeStampEntry() { - return timeStampEntry; - } - - public void setTimeStampEntry(long timeStampEntry) { - this.timeStampEntry = timeStampEntry; - } - - public long getTimeStampExit() { - return timeStampExit; - } - - public void setTimeStampExit(long timeStampExit) { - this.timeStampExit = timeStampExit; - } - - public SerializableData getExceptionThrown() { - return exceptionThrown; - } - - public void setExceptionThrown(SerializableData exceptionThrown) { - this.exceptionThrown = exceptionThrown; - } -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java new file mode 100644 index 00000000..b94cb05d --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java @@ -0,0 +1,57 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PartialTrace { + private String methodSignature; + private TraceData instance; + private List preCallArguments; + private long timeStampEntry; + + @JsonCreator + public PartialTrace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("timeStampEntry") long timeStampEntry) { + this.methodSignature = methodSignature; + this.instance = instance; + this.preCallArguments = preCallArguments; + this.timeStampEntry = timeStampEntry; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public TraceData getInstance() { + return instance; + } + + public void setInstance(TraceData instance) { + this.instance = instance; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java deleted file mode 100644 index 1a6fe96a..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/SerializableData.java +++ /dev/null @@ -1,79 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -public class SerializableData { - private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - - private String fullyQualifiedTypeName; - private String dataAsJson; - private int instanceId; - - public String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; - } - - public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - } - - public String getDataAsJson() { - return dataAsJson; - } - - public void setDataAsJson(String dataAsJson) { - this.dataAsJson = dataAsJson; - } - - public int getInstanceId() { - return instanceId; - } - - public void setInstanceId(int instanceId) { - this.instanceId = instanceId; - } - - @JsonCreator - public SerializableData( - @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, - @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - this.dataAsJson = dataAsJson; - this.instanceId = instanceId; - } - - public static SerializableData valueOf(Object object) { - if (object == null) { - return null; - } - - // /!\ CAUTION - // - // The JVM Specification __clearly__ states that the hashcode returned by the Object implementation - // (the one obtained here) is not claimed to be valid, and is not an address in memory. - // Indeed, how come do we have 32 bit integers on a 64 bit addressable system...? - // While it's __unlikely__ to encounter the same value here for our purposes, the risk is NON 0, and - // we must always check other factors to know if a value is identical to one or another, like the - // fully qualified name, or the parameter list! You've been warned... - // - // PS: if you got a better idea, I'm all ears :) - // - int instanceId = System.identityHashCode(object); - String objectClassName = object.getClass().getTypeName(); - - String serializedString = null; - - try { - serializedString = objectMapper.writeValueAsString(object); - } catch (JsonProcessingException e) { - System.err.println("ERROR: Cannot serialize specific argument: " + e); - } - - return new SerializableData(objectClassName, serializedString, instanceId); - } -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java new file mode 100644 index 00000000..43a25a6b --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -0,0 +1,63 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class Trace extends PartialTrace { + private List postCallArguments; + private TraceData returnedValue; + private long timeStampExit; + private TraceData exceptionThrown; + + @JsonCreator + public Trace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") TraceData exceptionThrown) { + super(methodSignature, instance, preCallArguments, timeStampEntry); + + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public TraceData getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(TraceData returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } + + public TraceData getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(TraceData exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java new file mode 100644 index 00000000..bb40ae81 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java @@ -0,0 +1,44 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TraceData { + private String fullyQualifiedTypeName; + private String dataAsJson; + private int instanceId; + + @JsonCreator + public TraceData( + @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, + @JsonProperty("dataAsJson") String dataAsJson, + @JsonProperty("instanceId") int instanceId) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + this.dataAsJson = dataAsJson; + this.instanceId = instanceId; + } + + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public String getDataAsJson() { + return dataAsJson; + } + + public void setDataAsJson(String dataAsJson) { + this.dataAsJson = dataAsJson; + } + + public int getInstanceId() { + return instanceId; + } + + public void setInstanceId(int instanceId) { + this.instanceId = instanceId; + } +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java similarity index 69% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java rename to Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index ac82809a..ba1d528f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodVisitor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,19 +1,19 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.MethodTracer; -import com.github.maracas.gilesi.instrumentation.models.MethodTrace; +import com.github.maracas.gilesi.instrumentation.TraceCollector; +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; -public class MethodVisitor { +public class MethodAdvisor { @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - return MethodTracer.getPartialMethodTrace(origin, arguments, instance); + return TraceCollector.getPartialMethodTrace(origin, arguments, instance); } @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) @@ -23,7 +23,7 @@ public static void exit( @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, - @Advice.Enter(typing = Assigner.Typing.DYNAMIC) MethodTrace entryTrace) { - MethodTracer.addMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + TraceCollector.addMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java new file mode 100644 index 00000000..1238de23 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -0,0 +1,33 @@ +package com.github.maracas.gilesi.instrumentation.visitors; + +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; + +import java.lang.instrument.Instrumentation; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class MethodInstrumentor { + public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { + getAgentBuilderFor(instrumentationParameter).installOn(inst); + } + + private static AgentBuilder getAgentBuilderFor(InstrumentationParameter instrumentationParameter) { + String[] methodsArray = new String[instrumentationParameter.ClassMethodsOrConstructors.size()]; + instrumentationParameter.ClassMethodsOrConstructors.toArray(methodsArray); + + return new AgentBuilder.Default() + .type(named(instrumentationParameter.ClassName)) + .transform((builder, + typeDescription, + classLoader, + javaModule, + protectionDomain) -> + builder.visit(Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(methodsArray)))) + ) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) + .with(AgentBuilder.TypeStrategy.Default.REDEFINE); + } +} diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java deleted file mode 100644 index a3626a4b..00000000 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodTrace.java +++ /dev/null @@ -1,101 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class MethodTrace { - private String methodSignature; - private SerializableData instance; - private List preCallArguments; - private List postCallArguments; - private SerializableData returnedValue; - private long timeStampEntry; - private long timeStampExit; - private SerializableData exceptionThrown; - - @JsonCreator - public MethodTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") SerializableData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") SerializableData returnedValue, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") SerializableData exceptionThrown) { - this.methodSignature = methodSignature; - this.instance = instance; - this.preCallArguments = preCallArguments; - this.postCallArguments = postCallArguments; - this.returnedValue = returnedValue; - this.timeStampEntry = timeStampEntry; - this.timeStampExit = timeStampExit; - this.exceptionThrown = exceptionThrown; - } - - public String getMethodSignature() { - return methodSignature; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public SerializableData getInstance() { - return instance; - } - - public void setInstance(SerializableData instance) { - this.instance = instance; - } - - public List getPreCallArguments() { - return preCallArguments; - } - - public void setPreCallArguments(List preCallArguments) { - this.preCallArguments = preCallArguments; - } - - public List getPostCallArguments() { - return postCallArguments; - } - - public void setPostCallArguments(List postCallArguments) { - this.postCallArguments = postCallArguments; - } - - public SerializableData getReturnedValue() { - return returnedValue; - } - - public void setReturnedValue(SerializableData returnedValue) { - this.returnedValue = returnedValue; - } - - public long getTimeStampEntry() { - return timeStampEntry; - } - - public void setTimeStampEntry(long timeStampEntry) { - this.timeStampEntry = timeStampEntry; - } - - public long getTimeStampExit() { - return timeStampExit; - } - - public void setTimeStampExit(long timeStampExit) { - this.timeStampExit = timeStampExit; - } - - public SerializableData getExceptionThrown() { - return exceptionThrown; - } - - public void setExceptionThrown(SerializableData exceptionThrown) { - this.exceptionThrown = exceptionThrown; - } -} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java new file mode 100644 index 00000000..b94cb05d --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java @@ -0,0 +1,57 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PartialTrace { + private String methodSignature; + private TraceData instance; + private List preCallArguments; + private long timeStampEntry; + + @JsonCreator + public PartialTrace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("timeStampEntry") long timeStampEntry) { + this.methodSignature = methodSignature; + this.instance = instance; + this.preCallArguments = preCallArguments; + this.timeStampEntry = timeStampEntry; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public TraceData getInstance() { + return instance; + } + + public void setInstance(TraceData instance) { + this.instance = instance; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } +} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java new file mode 100644 index 00000000..43a25a6b --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -0,0 +1,63 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class Trace extends PartialTrace { + private List postCallArguments; + private TraceData returnedValue; + private long timeStampExit; + private TraceData exceptionThrown; + + @JsonCreator + public Trace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") TraceData exceptionThrown) { + super(methodSignature, instance, preCallArguments, timeStampEntry); + + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public TraceData getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(TraceData returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } + + public TraceData getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(TraceData exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } +} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java new file mode 100644 index 00000000..bb40ae81 --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java @@ -0,0 +1,44 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +public class TraceData { + private String fullyQualifiedTypeName; + private String dataAsJson; + private int instanceId; + + @JsonCreator + public TraceData( + @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, + @JsonProperty("dataAsJson") String dataAsJson, + @JsonProperty("instanceId") int instanceId) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + this.dataAsJson = dataAsJson; + this.instanceId = instanceId; + } + + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public String getDataAsJson() { + return dataAsJson; + } + + public void setDataAsJson(String dataAsJson) { + this.dataAsJson = dataAsJson; + } + + public int getInstanceId() { + return instanceId; + } + + public void setInstanceId(int instanceId) { + this.instanceId = instanceId; + } +} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 1a031173..a60f5cea 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -1,8 +1,8 @@ package com.github.maracas.gilesi.traceview; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.maracas.gilesi.instrumentation.models.MethodTrace; -import com.github.maracas.gilesi.instrumentation.models.SerializableData; +import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.maracas.gilesi.instrumentation.models.TraceData; import org.apache.commons.text.StringEscapeUtils; import java.io.File; @@ -30,7 +30,7 @@ private static String getInstanceVarName(int instanceId) { return "var" + i; } - private static String serializableDataToCode(SerializableData arg) { + private static String serializableDataToCode(TraceData arg) { if (arg == null) { return "null"; } else if (arg.getDataAsJson() != null) { @@ -49,7 +49,7 @@ private static String getCleanedType(String FQN) { return FQN; } - private static String serializableDataToJava(SerializableData serializableData) { + private static String serializableDataToJava(TraceData serializableData) { String valueToBeEqualTo = serializableData.getDataAsJson(); String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); @@ -63,7 +63,7 @@ private static String serializableDataToJava(SerializableData serializableData) return valueToBeEqualTo; } - private static String getReturnStatementAsCode(SerializableData serializableData) { + private static String getReturnStatementAsCode(TraceData serializableData) { if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { return getInstanceVarName(serializableData.getInstanceId()); } else { @@ -73,7 +73,7 @@ private static String getReturnStatementAsCode(SerializableData serializableData } } - private static String traceToCode(MethodTrace methodTrace) { + private static String traceToCode(Trace methodTrace) { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; @@ -102,7 +102,7 @@ private static String traceToCode(MethodTrace methodTrace) { } List argList = new ArrayList<>(); - for (SerializableData arg : methodTrace.getPreCallArguments()) { + for (TraceData arg : methodTrace.getPreCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); String argumentDeclaration = getReturnStatementAsCode(arg) + " = " + argumentValueAsCode; @@ -113,9 +113,9 @@ private static String traceToCode(MethodTrace methodTrace) { return cleanedMethodName + "(" + String.join(",", argList) + ");"; } - private static String traceArgumentsToAssert(MethodTrace methodTrace) { + private static String traceArgumentsToAssert(Trace methodTrace) { List argList = new ArrayList<>(); - for (SerializableData arg : methodTrace.getPostCallArguments()) { + for (TraceData arg : methodTrace.getPostCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); argList.add("assert " + getInstanceVarName(arg.getInstanceId()) + ".equals(" + argumentValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"); } @@ -123,7 +123,7 @@ private static String traceArgumentsToAssert(MethodTrace methodTrace) { return String.join("\n", argList); } - private static String traceToAssert(MethodTrace methodTrace) { + private static String traceToAssert(Trace methodTrace) { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); @@ -139,15 +139,15 @@ private static String traceToAssert(MethodTrace methodTrace) { return null; } - private static MethodTrace[] readMethodTraces(String filePathStr) throws IOException { + private static Trace[] readTraces(String filePathStr) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(new File(filePathStr), MethodTrace[].class); + return objectMapper.readValue(new File(filePathStr), Trace[].class); } - private static List getTraceEventsFromMethodTraces(MethodTrace[] methodTraces) { + private static List getTraceEventsFromTraces(Trace[] methodTraces) { List events = new ArrayList<>(); - for (MethodTrace methodTrace : methodTraces) { + for (Trace methodTrace : methodTraces) { events.add(new TraceEvent("Entry", methodTrace.getTimeStampEntry(), methodTrace)); events.add(new TraceEvent("Exit", methodTrace.getTimeStampExit(), methodTrace)); } @@ -155,8 +155,8 @@ private static List getTraceEventsFromMethodTraces(MethodTrace[] met return events.stream().sorted(Comparator.comparing(TraceEvent::At)).toList(); } - private static void printMethodTraceAsCode(TraceEvent event) { - MethodTrace trace = event.About(); + private static void printTraceAsCode(TraceEvent event) { + Trace trace = event.About(); String methodCallLine = traceToCode(trace); String returnAssertionLine = traceToAssert(trace); @@ -176,8 +176,8 @@ private static void printMethodTraceAsCode(TraceEvent event) { } public static void main(String[] args) throws IOException { - MethodTrace[] methodTraces = readMethodTraces(args[0]); - List eventsSortedByTimeStamp = getTraceEventsFromMethodTraces(methodTraces); + Trace[] methodTraces = readTraces(args[0]); + List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); /*for (TraceEvent event : eventsSortedByTimeStamp) { System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().getMethodSignature() + "]"); @@ -185,7 +185,7 @@ public static void main(String[] args) throws IOException { for (TraceEvent event : eventsSortedByTimeStamp) { if (event.What().equals("Entry")) { - printMethodTraceAsCode(event); + printTraceAsCode(event); System.out.println(); } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java index debbe18e..083a5418 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.models.MethodTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; -public record TraceEvent(String What, long At, MethodTrace About) { +public record TraceEvent(String What, long At, Trace About) { } From 1e8bd0553e03710b502e6024c9c8155026e033e6 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 14:51:35 +0100 Subject: [PATCH 011/244] feat: cleanup agent entry points --- .../models/InstrumentationParameter.java | 2 +- .../models/InstrumentationParameters.java | 2 +- .../instrumentation/visitors/MethodInstrumentor.java | 11 ++++------- 3 files changed, 6 insertions(+), 9 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index 1044eda5..df80e405 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -4,5 +4,5 @@ public class InstrumentationParameter { public String ClassName; - public List ClassMethodsOrConstructors; + public String[] ClassMethodsOrConstructors; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 782fefb4..e741a30b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -3,5 +3,5 @@ import java.util.List; public class InstrumentationParameters { - public List ClassesToInstrument; + public InstrumentationParameter[] ClassesToInstrument; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index 1238de23..d12d1e87 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -11,21 +11,18 @@ public class MethodInstrumentor { public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - getAgentBuilderFor(instrumentationParameter).installOn(inst); + getAgentBuilderFor(instrumentationParameter.ClassName, instrumentationParameter.ClassMethodsOrConstructors).installOn(inst); } - private static AgentBuilder getAgentBuilderFor(InstrumentationParameter instrumentationParameter) { - String[] methodsArray = new String[instrumentationParameter.ClassMethodsOrConstructors.size()]; - instrumentationParameter.ClassMethodsOrConstructors.toArray(methodsArray); - + private static AgentBuilder getAgentBuilderFor(String className, String[] classMethodsOrConstructors) { return new AgentBuilder.Default() - .type(named(instrumentationParameter.ClassName)) + .type(named(className)) .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> - builder.visit(Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(methodsArray)))) + builder.visit(Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors)))) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) .with(AgentBuilder.TypeStrategy.Default.REDEFINE); From a5172abdf8e4e5db2ebff9115fd6f3a5af37fca9 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 14:57:30 +0100 Subject: [PATCH 012/244] feat: refactor trace collector --- .../instrumentation/TraceCollector.java | 93 +-------------- .../gilesi/instrumentation/TraceFactory.java | 109 ++++++++++++++++++ .../visitors/MethodAdvisor.java | 9 +- 3 files changed, 116 insertions(+), 95 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index c849c581..d9da8dcb 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -17,98 +17,7 @@ public class TraceCollector { // Storage for traces collected so far private static final ArrayList TRACES = new ArrayList<>(); - /** - * Gets the origin name from an Exectuable object with the signature if possible. - *

- * E.g. for a constructor: public com.github.maracas.gilesi.tests.legacy.Foo(java.lang.String) - * for a method: public static java.lang.String com.github.maracas.gilesi.tests.legacy.Foo.HelloEveryone(java.lang.String[]) - * - * @param origin The executable to get an origin name string from - * @return the origin name string matching the passed in executable - */ - private static String getOriginName(Executable origin) { - String originName; - - if (origin instanceof Method) { - Method method = (Method) origin; - originName = method.toGenericString(); - } else if (origin instanceof Constructor) { - Constructor constructor = (Constructor) origin; - originName = constructor.toGenericString(); - } else { - System.err.println("BUGBUGBUG: Unknown Originating Executable Type!"); - System.err.println(origin.getClass().getName()); - originName = origin.toString(); - } - return originName; - } - - private static List getArgumentsAsSerializableData(Object[] arguments) { - List argumentStrings = new ArrayList<>(); - - if (arguments != null) { - argumentStrings = Arrays.stream(arguments).map(TraceDataFactory::valueOf).collect(Collectors.toList()); - } - - return argumentStrings; - } - - /** - * Collects information about a method execution call at entry, - * for further collection later on exit - * This method generates an incomplete partial method trace with on entry information, - * and caches it temporarily for use on exit. - * Callers must call later addMethodTrace on exit to complete the trace and make it available. - *

- * This method is public so it can be accessed as part of the modified instrumented classes - * without security problems at the JVM level - * - * @param origin The originating trace Executable object - * @param arguments The originating trace argument list on entry - */ - public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { - // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.currentTimeMillis(); - - String methodSignature = getOriginName(origin); - TraceData serializableInstance = TraceDataFactory.valueOf(instance); - List preCallArguments = getArgumentsAsSerializableData(arguments); - long timeStampEntry = entryMarker; - - return new PartialTrace(methodSignature, serializableInstance, preCallArguments, timeStampEntry); - } - - /** - * Collects information about a method execution call at exit, - * with further data completion with an earlier partial trace if available from entry. - * This method generates an incomplete partial method trace with on exit information, - * and completes it with entry information if available, to cache a complete trace. - * Callers must call earlier addNotYetCompletedMethodTrace to provide entry information to - * have complete trace data. - *

- * Callers must call later getMethodTraces to retrieve the trace information. - *

- * This method is public so it can be accessed as part of the modified instrumented classes - * without security problems at the JVM level - * - * @param origin The originating trace Executable object - * @param arguments The originating trace argument list on entry - * @param returned The data returned by the originating trace - */ - public static void addMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace) { - // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.currentTimeMillis(); - - String methodSignature = getOriginName(origin); - TraceData serializableInstance = TraceDataFactory.valueOf(instance); - List preCallArguments = originatingTrace.getPreCallArguments(); - List postCallArguments = getArgumentsAsSerializableData(arguments); - TraceData returnedValue = TraceDataFactory.valueOf(returned); - long timeStampEntry = originatingTrace.getTimeStampEntry(); - long timeStampExit = exitMarker; - TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); - - Trace trace = new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); + public static void addMethodTrace(Trace trace) { TRACES.add(trace); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java new file mode 100644 index 00000000..c1daefe1 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -0,0 +1,109 @@ +package com.github.maracas.gilesi.instrumentation; + +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.maracas.gilesi.instrumentation.models.TraceData; + +import java.lang.reflect.Constructor; +import java.lang.reflect.Executable; +import java.lang.reflect.Method; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.stream.Collectors; + +public class TraceFactory { + /** + * Gets the origin name from an Exectuable object with the signature if possible. + *

+ * E.g. for a constructor: public com.github.maracas.gilesi.tests.legacy.Foo(java.lang.String) + * for a method: public static java.lang.String com.github.maracas.gilesi.tests.legacy.Foo.HelloEveryone(java.lang.String[]) + * + * @param origin The executable to get an origin name string from + * @return the origin name string matching the passed in executable + */ + private static String getOriginName(Executable origin) { + String originName; + + if (origin instanceof Method) { + Method method = (Method) origin; + originName = method.toGenericString(); + } else if (origin instanceof Constructor) { + Constructor constructor = (Constructor) origin; + originName = constructor.toGenericString(); + } else { + System.err.println("BUGBUGBUG: Unknown Originating Executable Type!"); + System.err.println(origin.getClass().getName()); + originName = origin.toString(); + } + return originName; + } + + private static List getArgumentsAsSerializableData(Object[] arguments) { + List argumentStrings = new ArrayList<>(); + + if (arguments != null) { + argumentStrings = Arrays.stream(arguments).map(TraceDataFactory::valueOf).collect(Collectors.toList()); + } + + return argumentStrings; + } + + /** + * Collects information about a method execution call at entry, + * for further collection later on exit + * This method generates an incomplete partial method trace with on entry information, + * and caches it temporarily for use on exit. + * Callers must call later addMethodTrace on exit to complete the trace and make it available. + *

+ * This method is public so it can be accessed as part of the modified instrumented classes + * without security problems at the JVM level + * + * @param origin The originating trace Executable object + * @param arguments The originating trace argument list on entry + */ + public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { + // Need to fetch this asap to not be off on the measurements! + long entryMarker = System.currentTimeMillis(); + + String methodSignature = getOriginName(origin); + TraceData serializableInstance = TraceDataFactory.valueOf(instance); + List preCallArguments = getArgumentsAsSerializableData(arguments); + long timeStampEntry = entryMarker; + + return new PartialTrace(methodSignature, serializableInstance, preCallArguments, timeStampEntry); + } + + /** + * Collects information about a method execution call at exit, + * with further data completion with an earlier partial trace if available from entry. + * This method generates an incomplete partial method trace with on exit information, + * and completes it with entry information if available, to cache a complete trace. + * Callers must call earlier addNotYetCompletedMethodTrace to provide entry information to + * have complete trace data. + *

+ * Callers must call later getMethodTraces to retrieve the trace information. + *

+ * This method is public so it can be accessed as part of the modified instrumented classes + * without security problems at the JVM level + * + * @param origin The originating trace Executable object + * @param arguments The originating trace argument list on entry + * @param returned The data returned by the originating trace + */ + public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace) { + // Need to fetch this asap to not be off on the measurements! + long exitMarker = System.currentTimeMillis(); + + String methodSignature = getOriginName(origin); + TraceData serializableInstance = TraceDataFactory.valueOf(instance); + List preCallArguments = originatingTrace.getPreCallArguments(); + List postCallArguments = getArgumentsAsSerializableData(arguments); + TraceData returnedValue = TraceDataFactory.valueOf(returned); + long timeStampEntry = originatingTrace.getTimeStampEntry(); + long timeStampExit = exitMarker; + TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); + + return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); + } +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index ba1d528f..0a445435 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,7 +1,9 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.maracas.gilesi.instrumentation.TraceCollector; +import com.github.maracas.gilesi.instrumentation.TraceFactory; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; @@ -13,7 +15,7 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - return TraceCollector.getPartialMethodTrace(origin, arguments, instance); + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) @@ -24,6 +26,7 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { - TraceCollector.addMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); + TraceCollector.addMethodTrace(trace); } } \ No newline at end of file From 70abb73c80d618cccc1eb6eb612b6d73168561e0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 15:04:47 +0100 Subject: [PATCH 013/244] fix: optimize methods --- .../maracas/gilesi/instrumentation/TraceCollector.java | 8 -------- .../instrumentation/models/InstrumentationParameter.java | 2 -- .../instrumentation/models/InstrumentationParameters.java | 2 -- .../gilesi/instrumentation/visitors/MethodAdvisor.java | 4 ++-- 4 files changed, 2 insertions(+), 14 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index d9da8dcb..61f1b595 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,17 +1,9 @@ package com.github.maracas.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; import com.github.maracas.gilesi.instrumentation.models.Trace; -import com.github.maracas.gilesi.instrumentation.models.TraceData; -import java.lang.reflect.Constructor; -import java.lang.reflect.Executable; -import java.lang.reflect.Method; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; -import java.util.List; -import java.util.stream.Collectors; public class TraceCollector { // Storage for traces collected so far diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index df80e405..0811ebde 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -1,7 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import java.util.List; - public class InstrumentationParameter { public String ClassName; public String[] ClassMethodsOrConstructors; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index e741a30b..968d8c17 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,7 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import java.util.List; - public class InstrumentationParameters { public InstrumentationParameter[] ClassesToInstrument; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 0a445435..18bf1fc6 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,9 +1,9 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; -import com.github.maracas.gilesi.instrumentation.models.Trace; import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.TraceFactory; +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; From 8cf0a961881335fcf02c22e17344bae6203be8f7 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 13 Dec 2023 15:16:30 +0100 Subject: [PATCH 014/244] feat: add stack trace collection --- .../gilesi/instrumentation/TraceFactory.java | 3 ++- .../gilesi/instrumentation/models/Trace.java | 13 ++++++++++++- .../gilesi/instrumentation/models/Trace.java | 13 ++++++++++++- 3 files changed, 26 insertions(+), 3 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index c1daefe1..39b08091 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -103,7 +103,8 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object long timeStampEntry = originatingTrace.getTimeStampEntry(); long timeStampExit = exitMarker; TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); + String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); - return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown); + return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown, stackTrace); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java index 43a25a6b..9b7be17e 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -10,6 +10,7 @@ public class Trace extends PartialTrace { private TraceData returnedValue; private long timeStampExit; private TraceData exceptionThrown; + private String[] stackTrace; @JsonCreator public Trace( @@ -20,13 +21,15 @@ public Trace( @JsonProperty("returnedValue") TraceData returnedValue, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown) { + @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("stackTrace") String[] stackTrace) { super(methodSignature, instance, preCallArguments, timeStampEntry); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; this.timeStampExit = timeStampExit; this.exceptionThrown = exceptionThrown; + this.stackTrace = stackTrace; } public List getPostCallArguments() { @@ -60,4 +63,12 @@ public TraceData getExceptionThrown() { public void setExceptionThrown(TraceData exceptionThrown) { this.exceptionThrown = exceptionThrown; } + + public String[] getStackTrace() { + return stackTrace; + } + + public void setStackTrace(String[] stackTrace) { + this.stackTrace = stackTrace; + } } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java index 43a25a6b..9b7be17e 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -10,6 +10,7 @@ public class Trace extends PartialTrace { private TraceData returnedValue; private long timeStampExit; private TraceData exceptionThrown; + private String[] stackTrace; @JsonCreator public Trace( @@ -20,13 +21,15 @@ public Trace( @JsonProperty("returnedValue") TraceData returnedValue, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown) { + @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("stackTrace") String[] stackTrace) { super(methodSignature, instance, preCallArguments, timeStampEntry); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; this.timeStampExit = timeStampExit; this.exceptionThrown = exceptionThrown; + this.stackTrace = stackTrace; } public List getPostCallArguments() { @@ -60,4 +63,12 @@ public TraceData getExceptionThrown() { public void setExceptionThrown(TraceData exceptionThrown) { this.exceptionThrown = exceptionThrown; } + + public String[] getStackTrace() { + return stackTrace; + } + + public void setStackTrace(String[] stackTrace) { + this.stackTrace = stackTrace; + } } \ No newline at end of file From cb85231fed8611f629ee82787a1ea2020d3fe848 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:04:12 +0100 Subject: [PATCH 015/244] Add test recursive method to troubleshoot an issue with serialization --- .../com/github/maracas/gilesi/samples/samplelibrary/A2.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java index bfcaef3f..2b054c09 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java @@ -13,4 +13,8 @@ public int foo(int i) { public void sideEffect() { this.i *= 2; } + + public A2 getOurselves() { + return this; + } } From 189f22297e2b0549a032124f91eb0d869321f53b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:06:50 +0100 Subject: [PATCH 016/244] Add the option to specify library methods and test methods via config explicitly --- .../github/maracas/gilesi/confgen/Main.java | 78 ++++++++++++++----- .../models/InstrumentationParameters.java | 2 + .../maracas/gilesi/instrumentation/Agent.java | 10 +++ .../models/InstrumentationParameters.java | 2 + .../instrumentation/visitors/TestAdvisor.java | 27 +++++++ .../visitors/TestInstrumentor.java | 30 +++++++ 6 files changed, 131 insertions(+), 18 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 140e8541..6d3132af 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -22,18 +22,28 @@ import java.util.List; public class Main { - private static String getClassNameFromConstructorFQN(String constructorFQN) { - return constructorFQN.split("\\(")[0]; - } + private static String getClassNameFromFQN(String fullyQualifiedName) { + String parameterLessQualifiedName = fullyQualifiedName; + + if (fullyQualifiedName.contains("(")) { + parameterLessQualifiedName = fullyQualifiedName.split("\\(")[0]; + } + + String[] nameElements = parameterLessQualifiedName.split("\\."); - private static String getClassNameFromFQN(String constructorFQN) { - String[] constructClassName = constructorFQN.split("\\(")[0].split("\\."); - return String.join(".", Arrays.stream(constructClassName).limit(constructClassName.length - 1).toArray(String[]::new)); + return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); } - private static String getMethodNameFromFQN(String constructorFQN) { - String[] constructClassName = constructorFQN.split("\\(")[0].split("\\."); - return constructClassName[constructClassName.length - 1]; + private static String getMethodNameFromFQN(String fullyQualifiedName) { + String parameterLessQualifiedName = fullyQualifiedName; + + if (fullyQualifiedName.contains("(")) { + parameterLessQualifiedName = fullyQualifiedName.split("\\(")[0]; + } + + String[] nameElements = parameterLessQualifiedName.split("\\."); + + return nameElements[nameElements.length - 1]; } private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName) { @@ -62,31 +72,59 @@ private static void addToInstrumentationObject(InstrumentationParameters instrum } } + private static void addToInstrumentationObjectTest(InstrumentationParameters instrumentationParameters, String className, String methodName) { + // If we already have a class here, don't add a new one + if (instrumentationParameters.TestClassesToInstrument.stream().anyMatch(t -> t.ClassName.equals(className))) { + // Find the class + for (InstrumentationParameter classToInstrument : instrumentationParameters.TestClassesToInstrument) { + if (classToInstrument.ClassName.equals(className)) { + // Only add if missing + if (classToInstrument.ClassMethodsOrConstructors.stream().noneMatch(t -> t.equals(methodName))) { + classToInstrument.ClassMethodsOrConstructors.add(methodName); + } + + // We found what we wanted so break now. + break; + } + } + } else { + // Otherwise, add a brand new one now. + InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); + instrumentationParameter.ClassName = className; + instrumentationParameter.ClassMethodsOrConstructors = new ArrayList<>(); + instrumentationParameter.ClassMethodsOrConstructors.add(methodName); + + instrumentationParameters.TestClassesToInstrument.add(instrumentationParameter); + } + } + public static void main(String[] args) throws Exception { String apiReportOutputLocation = args[0]; Path apiReportOutputPath = Path.of(apiReportOutputLocation); - System.out.println("Processing Main Project..."); + System.out.println("Processing Library Project..."); - Launcher mainLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); - SpoonLauncherUtilities.applyProjectToLauncher(mainLauncher, Path.of(args[1]), EnumSet.of(CodeType.MAIN)); - CtModel mainModel = mainLauncher.buildModel(); + Launcher libraryLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); + SpoonLauncherUtilities.applyProjectToLauncher(libraryLauncher, Path.of(args[1]), EnumSet.of(CodeType.MAIN)); + CtModel libraryModel = libraryLauncher.buildModel(); // API model for libraries - API mainProjectApiModel = new SpoonAPIExtractor(mainModel).extractAPI(); + API libraryApiModel = new SpoonAPIExtractor(libraryModel).extractAPI(); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.ClassesToInstrument = new ArrayList<>(); + instrumentationParameters.TestClassesToInstrument = new ArrayList<>(); + instrumentationParameters.LibraryMethods = new ArrayList<>(); - for (ClassDecl classDecl : mainProjectApiModel.getExportedTypes().stream() + for (ClassDecl classDecl : libraryApiModel.getExportedTypes().stream() .filter(ClassDecl.class::isInstance) .map(ClassDecl.class::cast).toList()) { for (ConstructorDecl constructor : classDecl.getConstructors()) { - String className = getClassNameFromConstructorFQN(constructor.getQualifiedName()); + String className = getClassNameFromFQN(constructor.getQualifiedName()); String methodName = ""; - addToInstrumentationObject(instrumentationParameters, className, methodName); + //addToInstrumentationObject(instrumentationParameters, className, methodName); // Something breaks here } for (MethodDecl method : classDecl.getMethods()) { @@ -98,6 +136,10 @@ public static void main(String[] args) throws Exception { } } + libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() + .forEach(method -> instrumentationParameters.LibraryMethods + .add(type.getQualifiedName() + "." + method.getSimpleName())))); + System.out.println("Processing Test Project..."); List testMethods = new ArrayList<>(); @@ -116,7 +158,7 @@ public static void main(String[] args) throws Exception { String className = getClassNameFromFQN(testMethod); String methodName = getMethodNameFromFQN(testMethod); - addToInstrumentationObject(instrumentationParameters, className, methodName); + addToInstrumentationObjectTest(instrumentationParameters, className, methodName); } ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 782fefb4..5feb8b4a 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -4,4 +4,6 @@ public class InstrumentationParameters { public List ClassesToInstrument; + public List TestClassesToInstrument; + public List LibraryMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index cb8552de..4df296ed 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -5,6 +5,7 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; +import com.github.maracas.gilesi.instrumentation.visitors.TestInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; @@ -15,6 +16,8 @@ Our main agent class */ public class Agent { + public static String[] LibraryMethods = new String[0]; + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(file, InstrumentationParameters.class); @@ -74,11 +77,18 @@ private static void installAgent(String arg, Instrumentation inst) { return; } + LibraryMethods = instrumentationParameters.LibraryMethods; + // Instrument every class for (InstrumentationParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } + // Instrument every test + for (InstrumentationParameter instrumentationParameter : instrumentationParameters.TestClassesToInstrument) { + TestInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); + } + // Then add a shutdown hook to save all method execution traces at exit Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 968d8c17..516f0ccf 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -2,4 +2,6 @@ public class InstrumentationParameters { public InstrumentationParameter[] ClassesToInstrument; + public InstrumentationParameter[] TestClassesToInstrument; + public String[] LibraryMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java new file mode 100644 index 00000000..40bff9bd --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java @@ -0,0 +1,27 @@ +package com.github.maracas.gilesi.instrumentation.visitors; + +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Executable; + +public class TestAdvisor { + @Advice.OnMethodEnter(inline = false) + public static Object enter( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + return new PartialTrace(null, null, null, 0); // TODO! + } + + @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) + public static void exit( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, + @Advice.Thrown Throwable thrown, + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { // TODO: Change return type! + } +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java new file mode 100644 index 00000000..f0006b0d --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java @@ -0,0 +1,30 @@ +package com.github.maracas.gilesi.instrumentation.visitors; + +import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.matcher.ElementMatchers; + +import java.lang.instrument.Instrumentation; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class TestInstrumentor { + public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { + getAgentBuilderFor(instrumentationParameter.ClassName, instrumentationParameter.ClassMethodsOrConstructors).installOn(inst); + } + + private static AgentBuilder getAgentBuilderFor(String className, String[] classMethodsOrConstructors) { + return new AgentBuilder.Default() + .type(named(className)) + .transform((builder, + typeDescription, + classLoader, + javaModule, + protectionDomain) -> + builder.visit(Advice.to(TestAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors)))) + ) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) + .with(AgentBuilder.TypeStrategy.Default.REDEFINE); + } +} From 70c161d864f9e308edc08d8a780a9746f5c8f0d3 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:07:10 +0100 Subject: [PATCH 017/244] Specify java version for maven launcher --- .../maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java index 56d59b22..c723d0c4 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -28,6 +28,11 @@ public static Launcher getCommonLauncherInstance() { launcher.getEnvironment().setIgnoreDuplicateDeclarations(true); // Ignore files with syntax/JLS violations and proceed launcher.getEnvironment().setIgnoreSyntaxErrors(true); + // Ignore comments + launcher.getEnvironment().setCommentEnabled(false); + // Set Java version + // Note: even when using the MavenLauncher, it's sometimes not properly inferred, better be safe + launcher.getEnvironment().setComplianceLevel(17); return launcher; } From a7ff32ecd97aa27627ac8a18d199af8b0394727e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:07:22 +0100 Subject: [PATCH 018/244] Remove indent feature from serialization --- .../github/maracas/gilesi/instrumentation/TraceDataFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index e9545686..c83d57ff 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -6,7 +6,7 @@ import com.github.maracas.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - private static final ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); + private static final ObjectMapper objectMapper = new ObjectMapper(); public static TraceData valueOf(Object object) { if (object == null) { From 25b9dd417343b238f7852da3687079a8189c93c5 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:07:52 +0100 Subject: [PATCH 019/244] Adjust stack trace content to skip ourselves --- .../com/github/maracas/gilesi/instrumentation/TraceFactory.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 39b08091..93d94889 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -103,7 +103,7 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object long timeStampEntry = originatingTrace.getTimeStampEntry(); long timeStampExit = exitMarker; TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); - String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); + String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).skip(3).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown, stackTrace); } From 070a7283a9a8ca9ac5ad21f953f2350eecbd329d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:08:05 +0100 Subject: [PATCH 020/244] Add filter rules to prevent stack overflow issues --- .../visitors/MethodAdvisor.java | 98 +++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 18bf1fc6..a62b5666 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,5 +1,6 @@ package com.github.maracas.gilesi.instrumentation.visitors; +import com.github.maracas.gilesi.instrumentation.Agent; import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.TraceFactory; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; @@ -8,6 +9,7 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; +import java.util.Arrays; public class MethodAdvisor { @Advice.OnMethodEnter(inline = false) @@ -15,6 +17,54 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 2: The caller: FooTest.mainTest(FooTest.java:50) + // 3: ... + + StackTraceElement callerStackTraceElement = stackTraceElements[2]; + String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); + + // The caller is a method from the library, which we do not want to collect traces for in our case + // Because we focus on API calls here, so do not do anything. + // Note: it's also possible the, tracing, is originating from us, + // so we want to also check if we are not a caller ourselves as well + if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + methodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + return null; + } + + // When we collect traces, we attempt to serialize the data transiting on the API barrier + // Unfortunately for us, some classes may return objects, that are linked to themselves + // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to + // Serialize an object, and while doing so, we go into our entry/exit methods + // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well + + // 0: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 1: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 2: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 3: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 4: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 5: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 6: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 8: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 9: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 10: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 11: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 12: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 13: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { + StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; + String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); + + if (originatingReflectMethodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + return null; + } + } + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } @@ -26,6 +76,54 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 2: The caller: FooTest.mainTest(FooTest.java:50) + // 3: ... + + StackTraceElement callerStackTraceElement = stackTraceElements[2]; + String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); + + // The caller is a method from the library, which we do not want to collect traces for in our case + // Because we focus on API calls here, so do not do anything. + // Note: it's also possible the, tracing, is originating from us, + // so we want to also check if we are not a caller ourselves as well + if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + methodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + return; + } + + // When we collect traces, we attempt to serialize the data transiting on the API barrier + // Unfortunately for us, some classes may return objects, that are linked to themselves + // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to + // Serialize an object, and while doing so, we go into our entry/exit methods + // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well + + // 0: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 1: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 2: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 3: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 4: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 5: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 6: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 8: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 9: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 10: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 11: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 12: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 13: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { + StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; + String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); + + if (originatingReflectMethodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + return; + } + } + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); TraceCollector.addMethodTrace(trace); } From d19e1fa21db028b463e5e7018f5cbbacb0d36ef2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:18:30 +0100 Subject: [PATCH 021/244] Update comments in MethodAdvisor for stacks --- .../visitors/MethodAdvisor.java | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index a62b5666..c8a4aae0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -42,20 +42,22 @@ public static Object enter( // Serialize an object, and while doing so, we go into our entry/exit methods // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well - // 0: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 1: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 2: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 3: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 4: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 5: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 6: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 8: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 9: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 10: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 11: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 12: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 13: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 15: The caller: ... if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); @@ -101,20 +103,22 @@ public static void exit( // Serialize an object, and while doing so, we go into our entry/exit methods // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well - // 0: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 1: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 2: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 3: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 4: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 5: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 6: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 8: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 9: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 10: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 11: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 12: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 13: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 15: The caller: ... if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); From 0b1e22c75930d43f4506bf4e1f28a4a546058d18 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:22:29 +0100 Subject: [PATCH 022/244] A bit of cleanup/comment changes --- .../maracas/gilesi/instrumentation/Agent.java | 2 +- .../instrumentation/TraceDataFactory.java | 2 +- .../visitors/MethodAdvisor.java | 23 +++++++++++-------- 3 files changed, 15 insertions(+), 12 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 4df296ed..c0866f60 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -104,7 +104,7 @@ public static void premain(String arg, Instrumentation inst) { /* agentmain is invoked when an agent is started after the application is already running. - Agents started with agentmain can be attached programatically using the Sun tools API (for Sun/Oracle JVMs only + Agents started with agentmain can be attached programmatically using the Sun tools API (for Sun/Oracle JVMs only -- the method for introducing dynamic agents is implementation-dependent). (https://stackoverflow.com/a/19789168) */ diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index c83d57ff..7ba720d0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -17,7 +17,7 @@ public static TraceData valueOf(Object object) { // // The JVM Specification __clearly__ states that the hashcode returned by the Object implementation // (the one obtained here) is not claimed to be valid, and is not an address in memory. - // Indeed, how come do we have 32 bit integers on a 64 bit addressable system...? + // Indeed, how come do we have 32-bit integers on a 64-bit addressable system...? // While it's __unlikely__ to encounter the same value here for our purposes, the risk is NON 0, and // we must always check other factors to know if a value is identical to one or another, like the // fully qualified name, or the parameter list! You've been warned... diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index c8a4aae0..0c12fded 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -12,6 +12,9 @@ import java.util.Arrays; public class MethodAdvisor { + private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; + private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; + @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, @@ -29,10 +32,10 @@ public static Object enter( // The caller is a method from the library, which we do not want to collect traces for in our case // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the, tracing, is originating from us, + // Note: it's also possible the tracing, is originating from us, // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { return null; } @@ -40,7 +43,7 @@ public static Object enter( // Unfortunately for us, some classes may return objects, that are linked to themselves // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well + // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) @@ -58,11 +61,11 @@ public static Object enter( // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... - if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - if (originatingReflectMethodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { return null; } } @@ -90,10 +93,10 @@ public static void exit( // The caller is a method from the library, which we do not want to collect traces for in our case // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the, tracing, is originating from us, + // Note: it's also possible the tracing, is originating from us, // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { return; } @@ -101,7 +104,7 @@ public static void exit( // Unfortunately for us, some classes may return objects, that are linked to themselves // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below's example, and verify the 10th item isn't us, if it is, skip as well + // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) @@ -119,11 +122,11 @@ public static void exit( // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... - if (methodName.startsWith("jdk.internal.reflect.DirectMethodHandleAccessor.invoke") && stackTraceElements.length >= 11) { + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - if (originatingReflectMethodName.startsWith("com.github.maracas.gilesi.instrumentation.")) { + if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { return; } } From 7a98ccc3b00aa41707550d623736c3d1cef62557 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 11:51:30 +0100 Subject: [PATCH 023/244] Add slicing of traces per test case --- .../instrumentation/TraceCollector.java | 19 ++++++++++++++----- .../gilesi/instrumentation/TraceFactory.java | 11 +++++++++++ .../instrumentation/visitors/TestAdvisor.java | 5 +++++ 3 files changed, 30 insertions(+), 5 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 61f1b595..db31bba9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,16 +1,25 @@ package com.github.maracas.gilesi.instrumentation; import com.github.maracas.gilesi.instrumentation.models.Trace; - import java.util.ArrayList; -import java.util.Collection; +import java.util.HashMap; public class TraceCollector { // Storage for traces collected so far - private static final ArrayList TRACES = new ArrayList<>(); + private static final HashMap> TRACES = new HashMap<>(); + private static String CurrentKey = null; public static void addMethodTrace(Trace trace) { - TRACES.add(trace); + TRACES.get(CurrentKey).add(trace); + } + + public static void setCurrentKey(String currentKey) { + CurrentKey = currentKey; + TRACES.put(CurrentKey, new ArrayList<>()); + } + + public static String getCurrentKey() { + return CurrentKey; } /** @@ -19,7 +28,7 @@ public static void addMethodTrace(Trace trace) { * * @return The list of every cached trace during program execution */ - public static Collection getMethodTraces() { + public static HashMap> getMethodTraces() { return TRACES; } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 93d94889..a7b5e87f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -105,6 +105,17 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).skip(3).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); + String currentTestMethod = TraceCollector.getCurrentKey(); + if (currentTestMethod != null && !currentTestMethod.isEmpty()) { + int index; + for (index = 0; index < stackTrace.length; index++) { + if (stackTrace[index].equals(currentTestMethod)) { + break; + } + } + stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); + } + return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown, stackTrace); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java index 40bff9bd..908c167f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java @@ -1,10 +1,12 @@ package com.github.maracas.gilesi.instrumentation.visitors; +import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; +import java.lang.reflect.Method; public class TestAdvisor { @Advice.OnMethodEnter(inline = false) @@ -12,6 +14,8 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + + TraceCollector.setCurrentKey(origin.getDeclaringClass().getName() + "." + origin.getName()); return new PartialTrace(null, null, null, 0); // TODO! } @@ -23,5 +27,6 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { // TODO: Change return type! + TraceCollector.setCurrentKey(""); } } From 1e5e655cf47f05b46707074843e199a59a5b0a11 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 9 Jan 2024 14:23:04 +0100 Subject: [PATCH 024/244] Improvements --- .../maracas/gilesi/instrumentation/Agent.java | 4 +-- .../instrumentation/TraceCollector.java | 34 ++++++++++++++----- .../instrumentation/TraceDataFactory.java | 1 - .../models/TestTraceResults.java | 8 +++++ .../instrumentation/visitors/TestAdvisor.java | 1 - 5 files changed, 36 insertions(+), 12 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index c0866f60..a73e0dd9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -48,8 +48,8 @@ public static void SaveTraceResults() { We take in as parameter a JSON file with the list of methods to instrument and their class */ private static void installAgent(String arg, Instrumentation inst) { - // First install the ByteBuddy Agent required to redefine classes during execution - // Sometimes this can fail, so try catch it + // First, install the ByteBuddy Agent required to redefine classes during execution + // Sometimes this can fail, so try to catch it try { ByteBuddyAgent.install(); } catch (Exception e) { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index db31bba9..2428a1f0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,25 +1,43 @@ package com.github.maracas.gilesi.instrumentation; +import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; import java.util.ArrayList; -import java.util.HashMap; +import java.util.Collection; public class TraceCollector { // Storage for traces collected so far - private static final HashMap> TRACES = new HashMap<>(); - private static String CurrentKey = null; + private static final ArrayList TRACES = new ArrayList<>(); + private static TestTraceResults CURRENT_TRACES = null; public static void addMethodTrace(Trace trace) { - TRACES.get(CurrentKey).add(trace); + if (CURRENT_TRACES == null) { + return; + } + + CURRENT_TRACES.Traces.add(trace); } public static void setCurrentKey(String currentKey) { - CurrentKey = currentKey; - TRACES.put(CurrentKey, new ArrayList<>()); + if (CURRENT_TRACES != null) { + TRACES.add(CURRENT_TRACES); + } + + if (currentKey == null || currentKey.isEmpty()) { + CURRENT_TRACES = null; + } else { + CURRENT_TRACES = new TestTraceResults(); + CURRENT_TRACES.Test = currentKey; + CURRENT_TRACES.Traces = new ArrayList<>(); + } } public static String getCurrentKey() { - return CurrentKey; + if (CURRENT_TRACES == null) { + return ""; + } + + return CURRENT_TRACES.Test; } /** @@ -28,7 +46,7 @@ public static String getCurrentKey() { * * @return The list of every cached trace during program execution */ - public static HashMap> getMethodTraces() { + public static Collection getMethodTraces() { return TRACES; } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 7ba720d0..3463f0ef 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java new file mode 100644 index 00000000..00b94913 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class TestTraceResults { + public List Traces; + public String Test; +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java index 908c167f..f0ce1d66 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java @@ -6,7 +6,6 @@ import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; -import java.lang.reflect.Method; public class TestAdvisor { @Advice.OnMethodEnter(inline = false) From d6345bf14b6b52fab89c929ffdf0762a71be6eaa Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 11:16:20 +0100 Subject: [PATCH 025/244] fix: adapt traceview to work with the new trace format --- .../models/TestTraceResults.java | 8 +++++ .../github/maracas/gilesi/traceview/Main.java | 31 +++++++++++-------- 2 files changed, 26 insertions(+), 13 deletions(-) create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java new file mode 100644 index 00000000..83d41f4f --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class TestTraceResults { + public Trace[] Traces; + public String Test; +} diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index a60f5cea..940df1ca 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -1,6 +1,7 @@ package com.github.maracas.gilesi.traceview; import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; import com.github.maracas.gilesi.instrumentation.models.TraceData; import org.apache.commons.text.StringEscapeUtils; @@ -139,9 +140,9 @@ private static String traceToAssert(Trace methodTrace) { return null; } - private static Trace[] readTraces(String filePathStr) throws IOException { + private static TestTraceResults[] readTraces(String filePathStr) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(new File(filePathStr), Trace[].class); + return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); } private static List getTraceEventsFromTraces(Trace[] methodTraces) { @@ -176,17 +177,21 @@ private static void printTraceAsCode(TraceEvent event) { } public static void main(String[] args) throws IOException { - Trace[] methodTraces = readTraces(args[0]); - List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); - - /*for (TraceEvent event : eventsSortedByTimeStamp) { - System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().getMethodSignature() + "]"); - }*/ - - for (TraceEvent event : eventsSortedByTimeStamp) { - if (event.What().equals("Entry")) { - printTraceAsCode(event); - System.out.println(); + TestTraceResults[] testTraceResultsList = readTraces(args[0]); + for (TestTraceResults testTraceResults : testTraceResultsList) + { + Trace[] methodTraces = testTraceResults.Traces; + List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); + + /*for (TraceEvent event : eventsSortedByTimeStamp) { + System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().getMethodSignature() + "]"); + }*/ + + for (TraceEvent event : eventsSortedByTimeStamp) { + if (event.What().equals("Entry")) { + printTraceAsCode(event); + System.out.println(); + } } } } From 52ce966ed5d2e04524c24119d907e466fb5fca8b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 11:16:32 +0100 Subject: [PATCH 026/244] fix: cleanup the test advisor --- .../instrumentation/visitors/TestAdvisor.java | 17 +++-------------- 1 file changed, 3 insertions(+), 14 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java index f0ce1d66..94dc2c81 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java @@ -1,31 +1,20 @@ package com.github.maracas.gilesi.instrumentation.visitors; import com.github.maracas.gilesi.instrumentation.TraceCollector; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; import net.bytebuddy.asm.Advice; -import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; public class TestAdvisor { @Advice.OnMethodEnter(inline = false) - public static Object enter( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + public static Object enter(@Advice.Origin Executable origin) { TraceCollector.setCurrentKey(origin.getDeclaringClass().getName() + "." + origin.getName()); - return new PartialTrace(null, null, null, 0); // TODO! + return null; } @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) - public static void exit( - @Advice.Origin Executable origin, - @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, - @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, - @Advice.Thrown Throwable thrown, - @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { // TODO: Change return type! + public static void exit() { TraceCollector.setCurrentKey(""); } } From 91237ef7f1644826e66e0ef02611f894144415ee Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 11:45:39 +0100 Subject: [PATCH 027/244] Debugging things --- .idea/.gitignore | 8 + .idea/gilesi.iml | 9 + .idea/jarRepositories.xml | 30 + .idea/misc.xml | 11 + .idea/modules.xml | 8 + .idea/vcs.xml | 6 + .../github/maracas/gilesi/confgen/Main.java | 2 +- MaracasConfiguration.json | 839 ++++++++++++++++++ maracas-test.cmd | 12 + 9 files changed, 924 insertions(+), 1 deletion(-) create mode 100644 .idea/.gitignore create mode 100644 .idea/gilesi.iml create mode 100644 .idea/jarRepositories.xml create mode 100644 .idea/misc.xml create mode 100644 .idea/modules.xml create mode 100644 .idea/vcs.xml create mode 100644 MaracasConfiguration.json create mode 100644 maracas-test.cmd diff --git a/.idea/.gitignore b/.idea/.gitignore new file mode 100644 index 00000000..13566b81 --- /dev/null +++ b/.idea/.gitignore @@ -0,0 +1,8 @@ +# Default ignored files +/shelf/ +/workspace.xml +# Editor-based HTTP Client requests +/httpRequests/ +# Datasource local storage ignored files +/dataSources/ +/dataSources.local.xml diff --git a/.idea/gilesi.iml b/.idea/gilesi.iml new file mode 100644 index 00000000..d6ebd480 --- /dev/null +++ b/.idea/gilesi.iml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml new file mode 100644 index 00000000..81c692a2 --- /dev/null +++ b/.idea/jarRepositories.xml @@ -0,0 +1,30 @@ + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml new file mode 100644 index 00000000..b6d77f79 --- /dev/null +++ b/.idea/misc.xml @@ -0,0 +1,11 @@ + + + + + + + + + + + \ No newline at end of file diff --git a/.idea/modules.xml b/.idea/modules.xml new file mode 100644 index 00000000..475aaf10 --- /dev/null +++ b/.idea/modules.xml @@ -0,0 +1,8 @@ + + + + + + + + \ No newline at end of file diff --git a/.idea/vcs.xml b/.idea/vcs.xml new file mode 100644 index 00000000..35eb1ddf --- /dev/null +++ b/.idea/vcs.xml @@ -0,0 +1,6 @@ + + + + + + \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 6d3132af..dd952fe1 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -124,7 +124,7 @@ public static void main(String[] args) throws Exception { String className = getClassNameFromFQN(constructor.getQualifiedName()); String methodName = ""; - //addToInstrumentationObject(instrumentationParameters, className, methodName); // Something breaks here + addToInstrumentationObject(instrumentationParameters, className, methodName); // Something breaks here } for (MethodDecl method : classDecl.getMethods()) { diff --git a/MaracasConfiguration.json b/MaracasConfiguration.json new file mode 100644 index 00000000..156cf699 --- /dev/null +++ b/MaracasConfiguration.json @@ -0,0 +1,839 @@ +{ + "ClassesToInstrument": [ + { + "ClassName": "com.github.maracas.visitors.FieldNowFinalVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldNowFinalVisitor", + "ClassMethodsOrConstructors": [ + "visitCtFieldWrite" + ] + }, + { + "ClassName": "com.github.maracas.visitors.CombinedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.CombinedVisitor", + "ClassMethodsOrConstructors": [ + "getBrokenUses", + "visitCtAnnotation", + "visitCtAnnotationFieldAccess", + "visitCtAnnotationMethod", + "visitCtAnnotationType", + "visitCtAnonymousExecutable", + "visitCtArrayRead", + "visitCtArrayTypeReference", + "visitCtArrayWrite", + "visitCtAssert", + "visitCtAssignment", + "visitCtBinaryOperator", + "visitCtBlock", + "visitCtBreak", + "visitCtCase", + "visitCtCatch", + "visitCtCatchVariable", + "visitCtCatchVariableReference", + "visitCtClass", + "visitCtCodeSnippetExpression", + "visitCtCodeSnippetStatement", + "visitCtComment", + "visitCtCompilationUnit", + "visitCtConditional", + "visitCtConstructor", + "visitCtConstructorCall", + "visitCtContinue", + "visitCtDo", + "visitCtEnum", + "visitCtEnumValue", + "visitCtExecutableReference", + "visitCtExecutableReferenceExpression", + "visitCtField", + "visitCtFieldRead", + "visitCtFieldReference", + "visitCtFieldWrite", + "visitCtFor", + "visitCtForEach", + "visitCtIf", + "visitCtImport", + "visitCtInterface", + "visitCtIntersectionTypeReference", + "visitCtInvocation", + "visitCtJavaDoc", + "visitCtJavaDocTag", + "visitCtLambda", + "visitCtLiteral", + "visitCtLocalVariable", + "visitCtLocalVariableReference", + "visitCtMethod", + "visitCtModule", + "visitCtModuleReference", + "visitCtModuleRequirement", + "visitCtNewArray", + "visitCtNewClass", + "visitCtOperatorAssignment", + "visitCtPackage", + "visitCtPackageDeclaration", + "visitCtPackageExport", + "visitCtPackageReference", + "visitCtParameter", + "visitCtParameterReference", + "visitCtProvidedService", + "visitCtReturn", + "visitCtStatementList", + "visitCtSuperAccess", + "visitCtSwitch", + "visitCtSwitchExpression", + "visitCtSynchronized", + "visitCtTextBlock", + "visitCtThisAccess", + "visitCtThrow", + "visitCtTry", + "visitCtTryWithResource", + "visitCtTypeAccess", + "visitCtTypeMemberWildcardImportReference", + "visitCtTypeParameter", + "visitCtTypeParameterReference", + "visitCtTypeReference", + "visitCtUnaryOperator", + "visitCtUnboundVariableReference", + "visitCtUsedService", + "visitCtVariableRead", + "visitCtVariableWrite", + "visitCtWhile", + "visitCtWildcardReference", + "visitCtYieldStatement" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.LibraryJar", + "ClassMethodsOrConstructors": [ + "buildModel", + "equals", + "getClasspath", + "getJar", + "getLabel", + "getSources", + "hasSources", + "hashCode", + "setNoClasspath", + "setSources", + "toString", + "withSources", + "withoutSources" + ] + }, + { + "ClassName": "com.github.maracas.delta.AbstractBreakingChange.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.AbstractBreakingChange", + "ClassMethodsOrConstructors": [ + "getChange", + "getSourceElement", + "setSourceElement" + ] + }, + { + "ClassName": "com.github.maracas.util.SpoonHelpers", + "ClassMethodsOrConstructors": [ + "buildSpoonSignature", + "firstLocatableParent", + "fullyQualifiedName", + "getEnclosingPkgName", + "isImplicit", + "matchingSignatures" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldLessAccessibleVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldLessAccessibleVisitor", + "ClassMethodsOrConstructors": [ + "visitCtFieldRead", + "visitCtFieldWrite" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldReferenceVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldReferenceVisitor", + "ClassMethodsOrConstructors": [ + "visitCtFieldReference" + ] + }, + { + "ClassName": "com.github.maracas.util.PathHelpers", + "ClassMethodsOrConstructors": [ + "isValidDirectory", + "isValidJar" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldTypeChangedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldTypeChangedVisitor", + "ClassMethodsOrConstructors": [ + "visitCtFieldRead", + "visitCtFieldWrite" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodAddedToInterfaceVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodAddedToInterfaceVisitor", + "ClassMethodsOrConstructors": [ + "visitCtClass" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SupertypeRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SupertypeRemovedVisitor", + "ClassMethodsOrConstructors": [ + "visitCtAssignment", + "visitCtFieldReference", + "visitCtInvocation", + "visitCtLocalVariable", + "visitCtMethod" + ] + }, + { + "ClassName": "com.github.maracas.brokenuse.APIUse.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldNowStaticVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.BinaryToSourceMapper.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.BinaryToSourceMapper", + "ClassMethodsOrConstructors": [ + "resolve" + ] + }, + { + "ClassName": "com.github.maracas.visitors.InterfaceAddedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.InterfaceRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.CtElementSerializer.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.CtElementSerializer", + "ClassMethodsOrConstructors": [ + "serialize" + ] + }, + { + "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToFieldVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowAbstractVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowAbstractVisitor", + "ClassMethodsOrConstructors": [ + "visitCtConstructorCall" + ] + }, + { + "ClassName": "com.github.maracas.MaracasOptions.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.MaracasOptions", + "ClassMethodsOrConstructors": [ + "defaultJApiOptions", + "excludeBreakingChange", + "getBuildTimeout", + "getClientsPerModule", + "getCloneTimeout", + "getExcludedBreakingChanges", + "getJApiOptions", + "getMaxClassLines", + "getMinStarsPerClient", + "newDefault", + "setBuildTimeout", + "setClientsPerModule", + "setCloneTimeout", + "setMaxClassLines", + "setMinStarsPerClient" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor", + "ClassMethodsOrConstructors": [ + "visitCtThrow" + ] + }, + { + "ClassName": "com.github.maracas.util.ParentLastURLClassLoader.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.ParentLastURLClassLoader", + "ClassMethodsOrConstructors": [ + "loadClass" + ] + }, + { + "ClassName": "com.github.maracas.delta.Delta.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.Delta", + "ClassMethodsOrConstructors": [ + "fromJApiCmpDelta", + "getBreakingChanges", + "getNewVersion", + "getOldVersion", + "getVisitors", + "isEmpty", + "populateLocations", + "toJson", + "toString" + ] + }, + { + "ClassName": "com.github.maracas.Maracas.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.Maracas", + "ClassMethodsOrConstructors": [ + "analyze", + "computeDelta", + "computeDeltaImpact" + ] + }, + { + "ClassName": "com.github.maracas.AnalysisQuery", + "ClassMethodsOrConstructors": [ + "builder", + "getClients", + "getMaracasOptions", + "getNewVersion", + "getOldVersion" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodNowFinalVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodNowFinalVisitor", + "ClassMethodsOrConstructors": [ + "visitCtMethod" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SuperclassRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodReturnTypeChangedVisitor", + "ClassMethodsOrConstructors": [ + "visitCtInvocation", + "visitCtMethod" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ConstructorRemovedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ConstructorRemovedVisitor", + "ClassMethodsOrConstructors": [ + "visitCtConstructorCall", + "visitCtInvocation", + "visitCtNewClass" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowFinalVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassNowFinalVisitor", + "ClassMethodsOrConstructors": [ + "visitCtClass", + "visitCtNewClass" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SupertypeAddedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SupertypeAddedVisitor", + "ClassMethodsOrConstructors": [ + "visitCtClass" + ] + }, + { + "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToClassVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.SpoonTypeHelpers", + "ClassMethodsOrConstructors": [ + "haveUnimplAbstractMethods", + "inferExpectedType", + "isAssignableFrom", + "isAssignableFromOverride", + "isBoxedType", + "isNarrowedPrimitiveType", + "isNarrowedType", + "isSubtype", + "isUnboxedType", + "isWidenedPrimitiveType", + "isWidenedType" + ] + }, + { + "ClassName": "com.github.maracas.delta.JApiCmpToSpoonVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.JApiCmpToSpoonVisitor", + "ClassMethodsOrConstructors": [ + "getBreakingChanges", + "visit" + ] + }, + { + "ClassName": "com.github.maracas.util.GradleLauncher.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.util.GradleLauncher", + "ClassMethodsOrConstructors": [ + "init" + ] + }, + { + "ClassName": "com.github.maracas.SourcesDirectory", + "ClassMethodsOrConstructors": [ + "buildModel", + "equals", + "getLocation", + "hashCode", + "of", + "setClasspath", + "toString" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldNoLongerStaticVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.FieldNoLongerStaticVisitor", + "ClassMethodsOrConstructors": [ + "visitCtFieldRead", + "visitCtFieldWrite" + ] + }, + { + "ClassName": "com.github.maracas.visitors.SuperclassAddedVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.TypeReferenceVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.TypeReferenceVisitor", + "ClassMethodsOrConstructors": [ + "visitCtTypeReference" + ] + }, + { + "ClassName": "com.github.maracas.delta.FieldBreakingChange.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.FieldBreakingChange", + "ClassMethodsOrConstructors": [ + "getReference", + "getVisitor" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassLessAccessibleVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.ClassLessAccessibleVisitor", + "ClassMethodsOrConstructors": [ + "visitCtTypeReference" + ] + }, + { + "ClassName": "com.github.maracas.AnalysisQuery$Builder", + "ClassMethodsOrConstructors": [ + "build", + "client", + "clients", + "exclude", + "newVersion", + "of", + "oldVersion", + "options" + ] + }, + { + "ClassName": "com.github.maracas.MaracasCLI.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.MaracasCLI", + "ClassMethodsOrConstructors": [ + "main", + "run" + ] + }, + { + "ClassName": "com.github.maracas.delta.TypeBreakingChange.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.TypeBreakingChange", + "ClassMethodsOrConstructors": [ + "getReference", + "getVisitor" + ] + }, + { + "ClassName": "com.github.maracas.visitors.BreakingChangeVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.BreakingChangeVisitor", + "ClassMethodsOrConstructors": [ + "brokenUse", + "getAPIUseByRole", + "getBrokenUses" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodNowAbstractVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodNowAbstractVisitor", + "ClassMethodsOrConstructors": [ + "visitCtClass", + "visitCtInvocation" + ] + }, + { + "ClassName": "com.github.maracas.delta.JApiCmpDeltaFilter.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.JApiCmpDeltaFilter", + "ClassMethodsOrConstructors": [ + "filter" + ] + }, + { + "ClassName": "com.github.maracas.delta.MethodBreakingChange.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.delta.MethodBreakingChange", + "ClassMethodsOrConstructors": [ + "getReference", + "getVisitor" + ] + }, + { + "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToMethodVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodReferenceVisitor.", + "ClassMethodsOrConstructors": [ + "" + ] + }, + { + "ClassName": "com.github.maracas.visitors.MethodReferenceVisitor", + "ClassMethodsOrConstructors": [ + "visitCtInvocation", + "visitCtMethod" + ] + }, + { + "ClassName": "com.github.maracas.forges.analysis.CommitAnalyzerIT", + "ClassMethodsOrConstructors": [ + "analyzeCommits_GumTree", + "analyzeCommits_fixture_moduleA", + "analyzeCommits_fixture_nestedB", + "computeDelta_maracas_withBuildTimeout", + "computeDelta_maracas_withCloneTimeout", + "computeImpact_fixture_withCloneTimeout" + ] + }, + { + "ClassName": "com.github.maracas.forges.analysis.CommitAnalyzerTest", + "ClassMethodsOrConstructors": [ + "analyzeCommits_success", + "computeDelta_buildException", + "computeDelta_cloneException", + "computeDelta_no_JAR_created", + "computeDelta_success", + "computeImpact_no_BC_in_delta", + "computeImpact_no_client", + "computeImpact_two_clients_one_analysis_fails", + "computeImpact_two_clients_one_clone_timeout", + "computeImpact_two_clients_success" + ] + }, + { + "ClassName": "com.github.maracas.forges.analysis.PullRequestAnalyzerTest", + "ClassMethodsOrConstructors": [ + "analyzePullRequest_fixture_two_broken_modules", + "inferImpactedModules_fixture_no_impacted_module", + "inferImpactedModules_fixture_one_impacted_module", + "inferImpactedModules_fixture_two_impacted_modules" + ] + }, + { + "ClassName": "com.github.maracas.forges.build.BuilderTest", + "ClassMethodsOrConstructors": [ + "build_From_GradleProject", + "build_From_MavenProject", + "build_From_UnknownProject" + ] + }, + { + "ClassName": "com.github.maracas.forges.build.gradle.GradleBuilderTest", + "ClassMethodsOrConstructors": [ + "build_compileError", + "build_multi_core_default_with_version", + "build_multi_extra_default", + "build_multi_invalid", + "build_validGradle_default", + "build_validGradle_invalidGoal", + "build_validGradle_withGoal", + "build_validGradle_with_invalidProperty", + "build_validGradle_with_validProperty" + ] + }, + { + "ClassName": "com.github.maracas.forges.build.maven.MavenBuilderTest", + "ClassMethodsOrConstructors": [ + "build_compileError", + "build_invalidGoal", + "build_maracas_timeout", + "build_multi_core_default", + "build_multi_extra_default", + "build_multi_invalid", + "build_no_pom", + "build_validPom_default", + "build_validPom_withGoal", + "build_validPom_withProperty", + "locate_modules_multi", + "locate_modules_valid" + ] + }, + { + "ClassName": "com.github.maracas.forges.clone.ClonerTest", + "ClassMethodsOrConstructors": [ + "cloner_From_GitHub", + "cloner_From_Unknown" + ] + }, + { + "ClassName": "com.github.maracas.forges.clone.git.GitClonerTest", + "ClassMethodsOrConstructors": [ + "clone_commit_HEAD", + "clone_commit_invalid_repository", + "clone_commit_invalid_sha", + "clone_commit_sha_branch", + "clone_commit_sha_main", + "clone_commit_timeout", + "clone_commit_timeout_invalid", + "clone_repository", + "clone_repository_branch", + "clone_repository_branch_invalid", + "clone_repository_invalid", + "clone_repository_invalid_location", + "clone_repository_timeout", + "clone_repository_timeout_invalid" + ] + }, + { + "ClassName": "com.github.maracas.forges.github.GitHubClientsScraperTest", + "ClassMethodsOrConstructors": [ + "fetch_clients_ews", + "fetch_clients_guava_limit", + "fetch_clients_spoon", + "fetch_modules_ews", + "fetch_modules_spoon", + "fetch_modules_unknown", + "fetch_one_module_spoon", + "fetch_unknown_module_spoon" + ] + }, + { + "ClassName": "com.github.maracas.forges.github.GitHubForgeIT", + "ClassMethodsOrConstructors": [ + "fetchAllClients_fixture", + "fetchAllClients_from_fork", + "fetchAllClients_no_module", + "fetchClients_unknown_module", + "fetchCommit_HEAD", + "fetchCommit_short_sha", + "fetchCommit_unknown", + "fetchCommit_valid", + "fetchPullRequest_closed", + "fetchPullRequest_opened", + "fetchPullRequest_that_was_synchronized", + "fetchPullRequest_unknown", + "fetchRepository_branch_unknown", + "fetchRepository_branch_valid", + "fetchRepository_unknown", + "fetchRepository_valid", + "fetchStarredClients_spoon", + "fetchTopClients_spoon" + ] + } + ] +} \ No newline at end of file diff --git a/maracas-test.cmd b/maracas-test.cmd new file mode 100644 index 00000000..20bf16e8 --- /dev/null +++ b/maracas-test.cmd @@ -0,0 +1,12 @@ +@echo off + +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 +set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 + +%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" + +cd C:\Users\Gus\Documents\GitHub\maracas +call "%MAVEN_HOME%\bin\mvn" surefire:test +cd C:\Users\Gus\Documents\GitHub\gilesi + +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\MethodTraces.json" > C:\Users\Gus\Documents\GitHub\maracas\TraceView.Output.txt \ No newline at end of file From bf74e772859a3fd2dba41ec1f0e979c058d055ab Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 11:59:07 +0100 Subject: [PATCH 028/244] Temporarily workaround an issue with constructors --- .../visitors/ConstructorAdvisor.java | 35 +++++++++++++++++++ .../visitors/MethodInstrumentor.java | 8 ++++- 2 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java new file mode 100644 index 00000000..71f11a41 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -0,0 +1,35 @@ +package com.github.maracas.gilesi.instrumentation.visitors; + +import com.github.maracas.gilesi.instrumentation.Agent; +import com.github.maracas.gilesi.instrumentation.TraceCollector; +import com.github.maracas.gilesi.instrumentation.TraceFactory; +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Executable; +import java.util.Arrays; + +public class ConstructorAdvisor { + private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; + private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; + + @Advice.OnMethodEnter + public static Object enter( + @Advice.Origin Executable origin, + @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments) { + return TraceFactory.getPartialMethodTrace(origin, arguments, null); + } + + @Advice.OnMethodExit + public static void exit( + @Advice.Origin Executable origin, + @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This Object instance, + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); + TraceCollector.addMethodTrace(trace); + } +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index d12d1e87..d6d52a9d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -22,7 +22,13 @@ private static AgentBuilder getAgentBuilderFor(String className, String[] classM classLoader, javaModule, protectionDomain) -> - builder.visit(Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors)))) + builder + .visit( + Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(ElementMatchers.namedOneOf(classMethodsOrConstructors))) + ) + .visit( + Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors))) + ) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) .with(AgentBuilder.TypeStrategy.Default.REDEFINE); From b050a198d352701dee637806f8cb83907e8773a5 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 12:06:20 +0100 Subject: [PATCH 029/244] Further improvements for constructor troubleshooting --- .../instrumentation/visitors/ConstructorAdvisor.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 71f11a41..ce4d72b8 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -18,18 +18,19 @@ public class ConstructorAdvisor { @Advice.OnMethodEnter public static Object enter( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments) { + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { return TraceFactory.getPartialMethodTrace(origin, arguments, null); } @Advice.OnMethodExit public static void exit( @Advice.Origin Executable origin, - @Advice.AllArguments(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object[] arguments, - @Advice.Return(readOnly = false, typing = Assigner.Typing.DYNAMIC) Object returned, - @Advice.This Object instance, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); TraceCollector.addMethodTrace(trace); } -} +} \ No newline at end of file From 8b62ad769cbeb04da39c73692140bea0ba5abc07 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 13:27:25 +0100 Subject: [PATCH 030/244] fix: add more code/handling for constructors --- .../visitors/ConstructorAdvisor.java | 56 ++++++++++++++++++- 1 file changed, 53 insertions(+), 3 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index ce4d72b8..391c1167 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -15,15 +15,65 @@ public class ConstructorAdvisor { private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; - @Advice.OnMethodEnter + @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - return TraceFactory.getPartialMethodTrace(origin, arguments, null); + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 2: The caller: FooTest.mainTest(FooTest.java:50) + // 3: ... + + StackTraceElement callerStackTraceElement = stackTraceElements[2]; + String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); + + // The caller is a method from the library, which we do not want to collect traces for in our case + // Because we focus on API calls here, so do not do anything. + // Note: it's also possible the tracing, is originating from us, + // so we want to also check if we are not a caller ourselves as well + if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + return null; + } + + // When we collect traces, we attempt to serialize the data transiting on the API barrier + // Unfortunately for us, some classes may return objects, that are linked to themselves + // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to + // Serialize an object, and while doing so, we go into our entry/exit methods + // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 15: The caller: ... + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { + StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; + String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); + + if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + return null; + } + } + + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } - @Advice.OnMethodExit + @Advice.OnMethodExit(inline = false) public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, From ec5976f6a2416fdf905a785eb1273f329dde0eb2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 13:46:02 +0100 Subject: [PATCH 031/244] More code parity for the constructor advisors --- .../visitors/ConstructorAdvisor.java | 50 +++++++++++++++++++ 1 file changed, 50 insertions(+) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 391c1167..328a643b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -80,6 +80,56 @@ public static void exit( @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 2: The caller: FooTest.mainTest(FooTest.java:50) + // 3: ... + + StackTraceElement callerStackTraceElement = stackTraceElements[2]; + String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); + + // The caller is a method from the library, which we do not want to collect traces for in our case + // Because we focus on API calls here, so do not do anything. + // Note: it's also possible the tracing, is originating from us, + // so we want to also check if we are not a caller ourselves as well + if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + return; + } + + // When we collect traces, we attempt to serialize the data transiting on the API barrier + // Unfortunately for us, some classes may return objects, that are linked to themselves + // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to + // Serialize an object, and while doing so, we go into our entry/exit methods + // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 15: The caller: ... + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { + StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; + String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); + + if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + return; + } + } + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); TraceCollector.addMethodTrace(trace); } From c9daf49ff65d79af89d9531d1a496e4101c3791f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 14 Feb 2024 15:49:57 +0100 Subject: [PATCH 032/244] Update Roseau Later on we will have to take a dependency on it but for now this shall do --- .../maracas/roseau/api/model/ClassDecl.java | 5 ++++ .../roseau/api/model/ExecutableDecl.java | 6 +++++ .../roseau/api/model/SpoonAPIFactory.java | 13 +++-------- .../maracas/roseau/api/model/TypeDecl.java | 1 - .../reference/SpoonTypeReferenceFactory.java | 8 +++---- .../reference/TypeParameterReference.java | 8 ++----- .../api/model/reference/TypeReference.java | 23 ++++++++++++++----- .../model/reference/TypeReferenceFactory.java | 9 ++++++-- .../github/maracas/roseau/diff/APIDiff.java | 18 ++++++++------- 9 files changed, 54 insertions(+), 37 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ClassDecl.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ClassDecl.java index 6057df3f..a084e9ac 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ClassDecl.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ClassDecl.java @@ -60,6 +60,11 @@ public List getAllFields() { @Override public boolean isCheckedException() { + if ("java.lang.Exception".equals(qualifiedName)) + return true; + if ("java.lang.RuntimeException".equals(qualifiedName)) + return false; + return getAllSuperClasses().stream().anyMatch(cls -> "java.lang.Exception".equals(cls.getQualifiedName())) && getAllSuperClasses().stream().noneMatch(cls -> "java.lang.RuntimeException".equals(cls.getQualifiedName())); } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ExecutableDecl.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ExecutableDecl.java index 755b644a..bd13d7b1 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ExecutableDecl.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/ExecutableDecl.java @@ -110,6 +110,12 @@ public List> getThrownExceptions() { return thrownExceptions; } + public List> getThrownCheckedExceptions() { + return thrownExceptions.stream() + .filter(e -> e.getResolvedApiType().map(TypeDecl::isCheckedException).orElse(false)) + .toList(); + } + @Override public boolean equals(Object o) { if (this == o) return true; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/SpoonAPIFactory.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/SpoonAPIFactory.java index 3fbd9317..253ecf65 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/SpoonAPIFactory.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/SpoonAPIFactory.java @@ -47,24 +47,17 @@ public TypeReferenceFactory getTypeReferenceFactory() { } private ITypeReference createITypeReference(CtTypeReference typeRef) { - if (typeRef == null) - return null; - return switch (typeRef) { case CtArrayTypeReference arrayRef -> typeReferenceFactory.createArrayTypeReference(createITypeReference(arrayRef.getComponentType())); - case CtTypeParameterReference tpRef -> { - if (tpRef.getBoundingType() instanceof CtIntersectionTypeReference intersection) - yield typeReferenceFactory.createTypeParameterReference(tpRef.getQualifiedName(), createITypeReferences(intersection.getBounds())); - else - yield typeReferenceFactory.createTypeParameterReference(tpRef.getQualifiedName(), List.of(createITypeReference(tpRef.getBoundingType()))); - } + case CtTypeParameterReference tpRef -> typeReferenceFactory.createTypeParameterReference(tpRef.getQualifiedName()); case CtTypeReference ref when ref.isPrimitive() -> typeReferenceFactory.createPrimitiveTypeReference(ref.getQualifiedName()); + case null -> null; default -> createTypeReference(typeRef); }; } private TypeReference createTypeReference(CtTypeReference typeRef) { - return typeRef != null ? typeReferenceFactory.createTypeReference(typeRef.getQualifiedName()) : null; + return typeRef != null ? typeReferenceFactory.createTypeReference(typeRef.getQualifiedName(), createITypeReferences(typeRef.getActualTypeArguments())) : null; } private TypeReference createTypeReference(CtType type) { diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java index 7a830be2..f14c676a 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java @@ -6,7 +6,6 @@ import com.github.maracas.roseau.api.model.reference.TypeReference; import java.util.ArrayList; -import java.util.Arrays; import java.util.Collection; import java.util.List; import java.util.Objects; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java index 5cf9be0b..fcfa449e 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java @@ -13,8 +13,8 @@ public SpoonTypeReferenceFactory(SpoonAPIFactory apiFactory) { } @Override - public TypeReference createTypeReference(String qualifiedName) { - return new TypeReference<>(qualifiedName, apiFactory); + public TypeReference createTypeReference(String qualifiedName, List typeArguments) { + return new TypeReference<>(qualifiedName, typeArguments, apiFactory); } @Override @@ -28,7 +28,7 @@ public ArrayTypeReference createArrayTypeReference(ITypeReference componentType) } @Override - public TypeParameterReference createTypeParameterReference(String qualifiedName, List bounds) { - return new TypeParameterReference(qualifiedName, bounds); + public TypeParameterReference createTypeParameterReference(String qualifiedName) { + return new TypeParameterReference(qualifiedName); } } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java index 216d0034..6463d265 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java @@ -1,9 +1,6 @@ package com.github.maracas.roseau.api.model.reference; -import java.util.List; -import java.util.stream.Collectors; - -public record TypeParameterReference(String qualifiedName, List bounds) implements ITypeReference { +public record TypeParameterReference(String qualifiedName) implements ITypeReference { @Override public String getQualifiedName() { return qualifiedName; @@ -11,7 +8,6 @@ public String getQualifiedName() { @Override public String toString() { - return "%s<%s>".formatted(qualifiedName, - bounds.stream().map(Object::toString).collect(Collectors.joining(", "))); + return qualifiedName; } } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java index 0d5822ad..8f1ec564 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java @@ -1,34 +1,44 @@ package com.github.maracas.roseau.api.model.reference; -import com.fasterxml.jackson.annotation.JsonValue; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonIgnore; import com.github.maracas.roseau.api.model.SpoonAPIFactory; import com.github.maracas.roseau.api.model.TypeDecl; +import java.util.List; import java.util.Objects; import java.util.Optional; public final class TypeReference implements ITypeReference { private final String qualifiedName; + private final List typeArguments; + @JsonIgnore private SpoonAPIFactory factory; + @JsonIgnore private T resolvedApiType; - public TypeReference(String qualifiedName) { + @JsonCreator + public TypeReference(String qualifiedName, List typeArguments) { this.qualifiedName = qualifiedName; + this.typeArguments = typeArguments; } - public TypeReference(String qualifiedName, SpoonAPIFactory factory) { - this.qualifiedName = qualifiedName; + public TypeReference(String qualifiedName, List typeArguments, SpoonAPIFactory factory) { + this(qualifiedName, typeArguments); this.factory = factory; } public SpoonAPIFactory getFactory() { return factory; } - @JsonValue @Override public String getQualifiedName() { return qualifiedName; } + public List getTypeArguments() { + return typeArguments; + } + public void setFactory(SpoonAPIFactory factory) { this.factory = factory; } @@ -62,7 +72,8 @@ public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; TypeReference other = (TypeReference) o; - return Objects.equals(qualifiedName, other.qualifiedName); + + return Objects.equals(qualifiedName, other.qualifiedName) && Objects.equals(typeArguments, other.typeArguments); } @Override diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java index 4b5632ef..46ebbeb8 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java @@ -2,11 +2,16 @@ import com.github.maracas.roseau.api.model.TypeDecl; +import java.util.Collections; import java.util.List; public interface TypeReferenceFactory { - TypeReference createTypeReference(String qualifiedName); + TypeReference createTypeReference(String qualifiedName, List typeArguments); PrimitiveTypeReference createPrimitiveTypeReference(String name); ArrayTypeReference createArrayTypeReference(ITypeReference componentType); - TypeParameterReference createTypeParameterReference(String qualifiedName, List bounds); + TypeParameterReference createTypeParameterReference(String qualifiedName); + + default TypeReference createTypeReference(String qualifiedName) { + return createTypeReference(qualifiedName, Collections.emptyList()); + } } diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java index 26c5dbc7..8a0aa888 100644 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java +++ b/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java @@ -79,7 +79,9 @@ public List diff() { private void diffFields(TypeDecl t1, TypeDecl t2) { t1.getFields().forEach(f1 -> { - Optional findF2 = t2.findField(f1.getSimpleName()); + Optional findF2 = t2.getAllFields().stream() + .filter(f -> f.getSimpleName().equals(f1.getSimpleName())) + .findFirst(); findF2.ifPresentOrElse( // There is a matching field @@ -92,7 +94,7 @@ private void diffFields(TypeDecl t1, TypeDecl t2) { private void diffMethods(TypeDecl t1, TypeDecl t2) { t1.getMethods().forEach(m1 -> { - Optional matchM2 = t2.getMethods().stream() + Optional matchM2 = t2.getAllMethods().stream() .filter(m -> m.hasSameSignature(m1)) .findFirst(); @@ -122,7 +124,7 @@ private void diffConstructors(ClassDecl c1, ClassDecl c2) { private void diffAddedMethods(TypeDecl t1, TypeDecl t2) { t2.getMethods().stream() - .filter(m2 -> t1.getMethods().stream().noneMatch(m1 -> m1.hasSameSignature(m2))) + .filter(m2 -> t1.getAllMethods().stream().noneMatch(m1 -> m1.hasSameSignature(m2))) .forEach(m2 -> { if (t2.isInterface() && !m2.isDefault()) bc(BreakingChangeKind.METHOD_ADDED_TO_INTERFACE, t1); @@ -134,7 +136,7 @@ private void diffAddedMethods(TypeDecl t1, TypeDecl t2) { private void diffType(TypeDecl t1, TypeDecl t2) { if (t1.isClass()) { - if (!t1.isFinal() && t2.isFinal()) + if (!t1.isEffectivelyFinal() && t2.isEffectivelyFinal()) bc(BreakingChangeKind.CLASS_NOW_FINAL, t1); if (!t1.isSealed() && t2.isSealed()) @@ -241,12 +243,12 @@ private void diffMethod(TypeDecl t1, MethodDecl m1, MethodDecl m2) { if (!m1.getType().equals(m2.getType())) bc(BreakingChangeKind.METHOD_RETURN_TYPE_CHANGED, m1); - List> additionalExceptions1 = m1.getThrownExceptions().stream() - .filter(e -> !m2.getThrownExceptions().contains(e)) + List> additionalExceptions1 = m1.getThrownCheckedExceptions().stream() + .filter(e -> !m2.getThrownCheckedExceptions().contains(e)) .toList(); - List> additionalExceptions2 = m2.getThrownExceptions().stream() - .filter(e -> !m1.getThrownExceptions().contains(e)) + List> additionalExceptions2 = m2.getThrownCheckedExceptions().stream() + .filter(e -> !m1.getThrownCheckedExceptions().contains(e)) .toList(); if (!additionalExceptions1.isEmpty()) From 4df9345d1ded41252098c2887b1cf617db735214 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 15 Feb 2024 15:11:28 +0100 Subject: [PATCH 033/244] Update dependencies --- ConfGen/build.gradle | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index 2c435a06..caafce44 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -24,10 +24,10 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.1' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.15.1' - implementation 'com.fasterxml.jackson.module:jackson-module-paranamer:2.15.1' - implementation 'com.google.guava:guava:32.1.2-jre' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1' + implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.16.1' + implementation 'com.fasterxml.jackson.module:jackson-module-paranamer:2.15.3' + implementation 'com.google.guava:guava:32.1.3-jre' implementation 'fr.inria.gforge.spoon:spoon-core:10.4.2' implementation 'info.picocli:picocli:4.7.5' } From c842a21d3fff06a29d8179c042b9dc68149ca79d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 16 Feb 2024 13:56:09 +0100 Subject: [PATCH 034/244] Use roseau maven package :) --- .idea/jarRepositories.xml | 5 + .idea/misc.xml | 2 + ConfGen/build.gradle | 10 + .../com/github/maracas/roseau/Roseau.java | 92 ----- .../maracas/roseau/api/APIExtractor.java | 7 - .../maracas/roseau/api/JarAPIExtractor.java | 10 - .../roseau/api/JavaParserAPIExtractor.java | 12 - .../maracas/roseau/api/SpoonAPIExtractor.java | 140 ------- .../github/maracas/roseau/api/model/API.java | 193 ---------- .../roseau/api/model/AccessModifier.java | 31 -- .../roseau/api/model/AnnotationDecl.java | 31 -- .../maracas/roseau/api/model/ClassDecl.java | 137 ------- .../roseau/api/model/ConstructorDecl.java | 33 -- .../maracas/roseau/api/model/EnumDecl.java | 31 -- .../roseau/api/model/ExecutableDecl.java | 134 ------- .../maracas/roseau/api/model/FieldDecl.java | 35 -- .../roseau/api/model/FormalTypeParameter.java | 12 - .../roseau/api/model/InterfaceDecl.java | 31 -- .../maracas/roseau/api/model/MethodDecl.java | 61 --- .../maracas/roseau/api/model/Modifier.java | 66 ---- .../roseau/api/model/ParameterDecl.java | 14 - .../maracas/roseau/api/model/RecordDecl.java | 31 -- .../roseau/api/model/SourceLocation.java | 10 - .../roseau/api/model/SpoonAPIFactory.java | 342 ----------------- .../maracas/roseau/api/model/Symbol.java | 102 ----- .../maracas/roseau/api/model/TypeDecl.java | 270 -------------- .../maracas/roseau/api/model/TypeMember.java | 20 - .../roseau/api/model/TypeMemberDecl.java | 70 ---- .../roseau/api/model/package-info.java | 4 - .../model/reference/ArrayTypeReference.java | 16 - .../api/model/reference/ITypeReference.java | 9 - .../reference/PrimitiveTypeReference.java | 13 - .../reference/SpoonTypeReferenceFactory.java | 34 -- .../reference/TypeParameterReference.java | 13 - .../api/model/reference/TypeReference.java | 83 ----- .../model/reference/TypeReferenceFactory.java | 17 - .../maracas/roseau/api/visit/APIAlgebra.java | 66 ---- .../roseau/api/visit/AbstractAPIVisitor.java | 124 ------- .../maracas/roseau/api/visit/Visit.java | 6 - .../github/maracas/roseau/diff/APIDiff.java | 349 ------------------ .../roseau/diff/changes/BreakingChange.java | 20 - .../diff/changes/BreakingChangeKind.java | 87 ----- .../diff/changes/BreakingChangeNature.java | 21 -- .../roseau/diff/changes/package-info.java | 4 - .../github/maracas/roseau/package-info.java | 5 - 45 files changed, 17 insertions(+), 2786 deletions(-) delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/Roseau.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/APIExtractor.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/JarAPIExtractor.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/JavaParserAPIExtractor.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/SpoonAPIExtractor.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/API.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/AccessModifier.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/AnnotationDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/ClassDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/ConstructorDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/EnumDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/ExecutableDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/FieldDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/FormalTypeParameter.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/InterfaceDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/MethodDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/Modifier.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/ParameterDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/RecordDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/SourceLocation.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/SpoonAPIFactory.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/Symbol.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMember.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMemberDecl.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/package-info.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ArrayTypeReference.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ITypeReference.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/PrimitiveTypeReference.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChange.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeKind.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeNature.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/package-info.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/roseau/package-info.java diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index 81c692a2..cf47410e 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -26,5 +26,10 @@

- * It provides information about the symbol's qualified qualifiedName, visibility, modifiers, - * and position within the source code. - */ -public abstract sealed class Symbol permits TypeDecl, TypeMemberDecl { - /** - * The qualifiedName of the symbol. - */ - protected final String qualifiedName; - - /** - * The visibility of the symbol. - */ - protected final AccessModifier visibility; - - /** - * List of non-access modifiers applied to the symbol. - */ - protected final List modifiers; - - /** - * The exact location of the symbol - */ - protected final SourceLocation location; - - protected Symbol(String qualifiedName, AccessModifier visibility, List modifiers, SourceLocation location) { - this.qualifiedName = qualifiedName; - this.visibility = visibility; - this.modifiers = modifiers; - this.location = location; - } - - /** - * Retrieves the qualifiedName of the symbol. - * - * @return The symbol's qualifiedName - */ - public String getQualifiedName() { - return qualifiedName; - } - - /** - * Retrieves the visibility of the symbol. - * - * @return The symbol's visibility - */ - public AccessModifier getVisibility() { - return visibility; - } - - /** - * Checks whether the symbol is accessible/exported - * - * @return exported or not - */ - @JsonIgnore - public abstract boolean isExported(); - - /** - * Retrieves the list of non-access modifiers applied to the symbol. - * - * @return The symbol's non-access modifiers - */ - public List getModifiers() { - return modifiers; - } - - /** - * Retrieves the position of the symbol. - * - * @return The symbol's position. - */ - public SourceLocation getLocation() { - return location; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - Symbol symbol = (Symbol) o; - return Objects.equals(qualifiedName, symbol.qualifiedName) - && visibility == symbol.visibility - && Objects.equals(modifiers, symbol.modifiers) - && Objects.equals(location, symbol.location); - } - - @Override - public int hashCode() { - return Objects.hash(qualifiedName, visibility, modifiers, location); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java deleted file mode 100644 index f14c676a..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeDecl.java +++ /dev/null @@ -1,270 +0,0 @@ -package com.github.maracas.roseau.api.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.fasterxml.jackson.annotation.JsonTypeInfo; -import com.github.maracas.roseau.api.model.reference.ITypeReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; - -import java.util.ArrayList; -import java.util.Collection; -import java.util.List; -import java.util.Objects; -import java.util.Optional; -import java.util.stream.Stream; - - -/** - * Represents a type declaration in the library. - * This class extends the {@link Symbol} class and contains information about the type's kind, fields, methods, constructors, and more. - */ -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "typeKind") -public abstract sealed class TypeDecl extends Symbol permits ClassDecl, InterfaceDecl, AnnotationDecl { - protected final List> implementedInterfaces; - - /** - * List of formal type parameters for generic types. - */ - protected final List formalTypeParameters; - - /** - * List of fields declared within the type. - */ - protected final List fields; - - /** - * List of methods declared within the type. - */ - protected final List methods; - - protected final TypeReference enclosingType; - - protected TypeDecl(String qualifiedName, - AccessModifier visibility, - List modifiers, - SourceLocation location, - List> implementedInterfaces, - List formalTypeParameters, - List fields, - List methods, - TypeReference enclosingType) { - super(qualifiedName, visibility, modifiers, location); - this.implementedInterfaces = implementedInterfaces; - this.formalTypeParameters = formalTypeParameters; - this.fields = fields; - this.methods = methods; - this.enclosingType = enclosingType; - } - - @JsonIgnore - @Override - public boolean isExported() { - return (isPublic() || (isProtected() && !isEffectivelyFinal())) - && (enclosingType == null || enclosingType.getResolvedApiType().map(TypeDecl::isExported).orElse(true)); - } - - @JsonIgnore - public boolean isNested() { - return enclosingType != null; - } - - @JsonIgnore - public boolean isClass() { - return false; - } - - @JsonIgnore - public boolean isInterface() { - return false; - } - - @JsonIgnore - public boolean isEnum() { - return false; - } - - @JsonIgnore - public boolean isRecord() { - return false; - } - - @JsonIgnore - public boolean isAnnotation() { - return false; - } - - @JsonIgnore - public boolean isCheckedException() { - return false; - } - - @JsonIgnore - public boolean isStatic() { - return modifiers.contains(Modifier.STATIC); - } - - @JsonIgnore - public boolean isFinal() { - return modifiers.contains(Modifier.FINAL); - } - - @JsonIgnore - public boolean isSealed() { - return modifiers.contains(Modifier.SEALED); - } - - @JsonIgnore - public boolean isEffectivelyFinal() { - // FIXME: in fact, a sealed class may not be final if one of its permitted subclass - // is explicitly marked as non-sealed - return !modifiers.contains(Modifier.NON_SEALED) && (isFinal() || isSealed()); - } - - @JsonIgnore - public boolean isPublic() { - return AccessModifier.PUBLIC == visibility; - } - - @JsonIgnore - public boolean isProtected() { - return AccessModifier.PROTECTED == visibility; - } - - @JsonIgnore - public boolean isPrivate() { - return AccessModifier.PRIVATE == visibility; - } - - @JsonIgnore - public boolean isPackagePrivate() { - return AccessModifier.PACKAGE_PRIVATE == visibility; - } - - @JsonIgnore - public boolean isAbstract() { - return modifiers.contains(Modifier.ABSTRACT); - } - - @JsonIgnore - public List getAllMethods() { - List allMethods = Stream.concat( - methods.stream(), - getSuperMethods().stream() - ).toList(); - - return allMethods.stream() - .filter(m -> allMethods.stream().noneMatch(m2 -> !m2.equals(m) && m2.isOverriding(m))) - .toList(); - } - - @JsonIgnore - public List> getAllSuperTypes() { - return new ArrayList<>(getAllImplementedInterfaces()); - } - - protected List getSuperMethods() { - return implementedInterfaces.stream() - .map(TypeReference::getResolvedApiType) - .flatMap(Optional::stream) - .map(InterfaceDecl::getAllMethods) - .flatMap(Collection::stream) - .toList(); - } - - @JsonIgnore - public List getAllFields() { - return Stream.concat( - fields.stream(), - implementedInterfaces.stream() - .map(TypeReference::getResolvedApiType) - .flatMap(Optional::stream) - .map(InterfaceDecl::getAllFields) - .flatMap(Collection::stream) - ).toList(); - } - - /** - * Retrieves the superinterfaces of the type as typeDeclarations. - * - * @return Type's superinterfaces as typeDeclarations - */ - public List> getImplementedInterfaces() { - return implementedInterfaces; - } - - /** - * Retrieves the list of formal type parameters for generic types. - * - * @return List of formal type parameters - */ - public List getFormalTypeParameters() { - return formalTypeParameters; - } - - /** - * Retrieves the list of fields declared within the type. - * - * @return List of fields declared within the type - */ - public List getFields() { - return fields; - } - - public List getMethods() { - return methods; - } - - public Optional> getEnclosingType() { - return Optional.ofNullable(enclosingType); - } - - public Optional findField(String name) { - return fields.stream() - .filter(f -> f.getSimpleName().equals(name)) - .findFirst(); - } - - public Optional findMethod(String name, List parameterTypes, boolean varargs) { - return methods.stream() - .filter(m -> m.hasSignature(name, parameterTypes, varargs)) - .findFirst(); - } - - public Optional findMethod(String name, List parameterTypes) { - return findMethod(name, parameterTypes, false); - } - - public Optional findMethod(String name) { - return methods.stream() - .filter(m -> m.getSimpleName().equals(name)) - .findFirst(); - } - - @JsonIgnore - public List> getAllImplementedInterfaces() { - return Stream.concat( - implementedInterfaces.stream(), - implementedInterfaces.stream() - .map(TypeReference::getResolvedApiType) - .flatMap(Optional::stream) - .map(InterfaceDecl::getAllImplementedInterfaces) - .flatMap(Collection::stream) - ).distinct().toList(); - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - TypeDecl typeDecl = (TypeDecl) o; - return Objects.equals(implementedInterfaces, typeDecl.implementedInterfaces) - && Objects.equals(formalTypeParameters, typeDecl.formalTypeParameters) - && Objects.equals(fields, typeDecl.fields) - && Objects.equals(methods, typeDecl.methods); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), implementedInterfaces, formalTypeParameters, fields, methods); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMember.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMember.java deleted file mode 100644 index 8f00d0cc..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMember.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.maracas.roseau.api.model; - -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.github.maracas.roseau.api.model.reference.ITypeReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; - -public interface TypeMember { - TypeReference getContainingType(); - ITypeReference getType(); - @JsonIgnore - String getSimpleName(); - @JsonIgnore - boolean isStatic(); - @JsonIgnore - boolean isFinal(); - @JsonIgnore - boolean isPublic(); - @JsonIgnore - boolean isProtected(); -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMemberDecl.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMemberDecl.java deleted file mode 100644 index 0d219541..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/TypeMemberDecl.java +++ /dev/null @@ -1,70 +0,0 @@ -package com.github.maracas.roseau.api.model; - -import com.github.maracas.roseau.api.model.reference.ITypeReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; - -import java.util.List; -import java.util.Objects; - -public abstract sealed class TypeMemberDecl extends Symbol implements TypeMember permits FieldDecl, ExecutableDecl { - protected final TypeReference containingType; - protected final ITypeReference type; - - protected TypeMemberDecl(String qualifiedName, AccessModifier visibility, List modifiers, - SourceLocation location, TypeReference containingType, ITypeReference type) { - super(qualifiedName, visibility, modifiers, location); - this.containingType = containingType; - this.type = type; - } - - @Override - public TypeReference getContainingType() { - return containingType; - } - - @Override - public ITypeReference getType() { - return type; - } - - @Override - public boolean isExported() { - return (isPublic() - || (isProtected() && !containingType.getResolvedApiType().map(TypeDecl::isEffectivelyFinal).orElse(true))) - && containingType.getResolvedApiType().map(TypeDecl::isExported).orElse(true); - } - - @Override - public boolean isStatic() { - return modifiers.contains(Modifier.STATIC); - } - - @Override - public boolean isFinal() { - return modifiers.contains(Modifier.FINAL); - } - - @Override - public boolean isPublic() { - return AccessModifier.PUBLIC == visibility; - } - - @Override - public boolean isProtected() { - return AccessModifier.PROTECTED == visibility; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - if (!super.equals(o)) return false; - TypeMemberDecl other = (TypeMemberDecl) o; - return Objects.equals(type, other.type); - } - - @Override - public int hashCode() { - return Objects.hash(super.hashCode(), type); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/package-info.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/package-info.java deleted file mode 100644 index 7ba99615..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This package contains the classes and types needed for API extraction. - */ -package com.github.maracas.roseau.api.model; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ArrayTypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ArrayTypeReference.java deleted file mode 100644 index 32c777d1..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ArrayTypeReference.java +++ /dev/null @@ -1,16 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -import com.fasterxml.jackson.annotation.JsonIgnore; - -public record ArrayTypeReference(ITypeReference componentType) implements ITypeReference { - @JsonIgnore - @Override - public String getQualifiedName() { - return componentType().getQualifiedName() + "[]"; - } - - @Override - public String toString() { - return getQualifiedName(); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ITypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ITypeReference.java deleted file mode 100644 index b0b70daf..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/ITypeReference.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -import com.fasterxml.jackson.annotation.JsonTypeInfo; - -@JsonTypeInfo(use = JsonTypeInfo.Id.CLASS, property = "refKind") -public sealed interface ITypeReference - permits TypeReference, ArrayTypeReference, PrimitiveTypeReference, TypeParameterReference { - String getQualifiedName(); -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/PrimitiveTypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/PrimitiveTypeReference.java deleted file mode 100644 index 4a3914e1..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/PrimitiveTypeReference.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -public record PrimitiveTypeReference(String qualifiedName) implements ITypeReference { - @Override - public String getQualifiedName() { - return qualifiedName; - } - - @Override - public String toString() { - return qualifiedName; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java deleted file mode 100644 index fcfa449e..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/SpoonTypeReferenceFactory.java +++ /dev/null @@ -1,34 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -import com.github.maracas.roseau.api.model.SpoonAPIFactory; -import com.github.maracas.roseau.api.model.TypeDecl; - -import java.util.List; - -public class SpoonTypeReferenceFactory implements TypeReferenceFactory { - private final SpoonAPIFactory apiFactory; - - public SpoonTypeReferenceFactory(SpoonAPIFactory apiFactory) { - this.apiFactory = apiFactory; - } - - @Override - public TypeReference createTypeReference(String qualifiedName, List typeArguments) { - return new TypeReference<>(qualifiedName, typeArguments, apiFactory); - } - - @Override - public PrimitiveTypeReference createPrimitiveTypeReference(String name) { - return new PrimitiveTypeReference(name); - } - - @Override - public ArrayTypeReference createArrayTypeReference(ITypeReference componentType) { - return componentType != null ? new ArrayTypeReference(componentType) : null; - } - - @Override - public TypeParameterReference createTypeParameterReference(String qualifiedName) { - return new TypeParameterReference(qualifiedName); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java deleted file mode 100644 index 6463d265..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeParameterReference.java +++ /dev/null @@ -1,13 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -public record TypeParameterReference(String qualifiedName) implements ITypeReference { - @Override - public String getQualifiedName() { - return qualifiedName; - } - - @Override - public String toString() { - return qualifiedName; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java deleted file mode 100644 index 8f1ec564..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReference.java +++ /dev/null @@ -1,83 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonIgnore; -import com.github.maracas.roseau.api.model.SpoonAPIFactory; -import com.github.maracas.roseau.api.model.TypeDecl; - -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -public final class TypeReference implements ITypeReference { - private final String qualifiedName; - private final List typeArguments; - @JsonIgnore - private SpoonAPIFactory factory; - @JsonIgnore - private T resolvedApiType; - - @JsonCreator - public TypeReference(String qualifiedName, List typeArguments) { - this.qualifiedName = qualifiedName; - this.typeArguments = typeArguments; - } - - public TypeReference(String qualifiedName, List typeArguments, SpoonAPIFactory factory) { - this(qualifiedName, typeArguments); - this.factory = factory; - } - - public SpoonAPIFactory getFactory() { return factory; } - - @Override - public String getQualifiedName() { - return qualifiedName; - } - - public List getTypeArguments() { - return typeArguments; - } - - public void setFactory(SpoonAPIFactory factory) { - this.factory = factory; - } - - public Optional getResolvedApiType() { - if (resolvedApiType == null && factory != null) - resolvedApiType = (T) factory.convertCtType(qualifiedName); - - return Optional.ofNullable(resolvedApiType); - } - - public void setResolvedApiType(T type) { - resolvedApiType = type; - } - - public boolean isSubtypeOf(TypeReference other) { - return equals(other) || getResolvedApiType().map(t -> t.getAllSuperTypes().contains(other)).orElse(false); - } - - public boolean isSameHierarchy(TypeReference other) { - return isSubtypeOf(other) || other.isSubtypeOf(this); - } - - @Override - public String toString() { - return qualifiedName; - } - - @Override - public boolean equals(Object o) { - if (this == o) return true; - if (o == null || getClass() != o.getClass()) return false; - TypeReference other = (TypeReference) o; - - return Objects.equals(qualifiedName, other.qualifiedName) && Objects.equals(typeArguments, other.typeArguments); - } - - @Override - public int hashCode() { - return Objects.hashCode(qualifiedName); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java deleted file mode 100644 index 46ebbeb8..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/model/reference/TypeReferenceFactory.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.maracas.roseau.api.model.reference; - -import com.github.maracas.roseau.api.model.TypeDecl; - -import java.util.Collections; -import java.util.List; - -public interface TypeReferenceFactory { - TypeReference createTypeReference(String qualifiedName, List typeArguments); - PrimitiveTypeReference createPrimitiveTypeReference(String name); - ArrayTypeReference createArrayTypeReference(ITypeReference componentType); - TypeParameterReference createTypeParameterReference(String qualifiedName); - - default TypeReference createTypeReference(String qualifiedName) { - return createTypeReference(qualifiedName, Collections.emptyList()); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java deleted file mode 100644 index 2eb8d491..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/APIAlgebra.java +++ /dev/null @@ -1,66 +0,0 @@ -package com.github.maracas.roseau.api.visit; - -import com.github.maracas.roseau.api.model.API; -import com.github.maracas.roseau.api.model.AnnotationDecl; -import com.github.maracas.roseau.api.model.ClassDecl; -import com.github.maracas.roseau.api.model.ConstructorDecl; -import com.github.maracas.roseau.api.model.EnumDecl; -import com.github.maracas.roseau.api.model.FieldDecl; -import com.github.maracas.roseau.api.model.InterfaceDecl; -import com.github.maracas.roseau.api.model.MethodDecl; -import com.github.maracas.roseau.api.model.ParameterDecl; -import com.github.maracas.roseau.api.model.RecordDecl; -import com.github.maracas.roseau.api.model.Symbol; -import com.github.maracas.roseau.api.model.TypeDecl; -import com.github.maracas.roseau.api.model.reference.ArrayTypeReference; -import com.github.maracas.roseau.api.model.reference.ITypeReference; -import com.github.maracas.roseau.api.model.reference.PrimitiveTypeReference; -import com.github.maracas.roseau.api.model.reference.TypeParameterReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; - -public interface APIAlgebra { - T api(API it); - T classDecl(ClassDecl it); - T interfaceDecl(InterfaceDecl it); - T enumDecl(EnumDecl it); - T annotationDecl(AnnotationDecl it); - T recordDecl(RecordDecl it); - T methodDecl(MethodDecl it); - T constructorDecl(ConstructorDecl it); - T fieldDecl(FieldDecl it); - T parameterDecl(ParameterDecl it); - T typeReference(TypeReference it); - T primitiveTypeReference(PrimitiveTypeReference it); - T arrayTypeReference(ArrayTypeReference it); - T typeParameterReference(TypeParameterReference it); - - default T $(API it) { - return api(it); - } - - default T $(Symbol it) { - return switch (it) { - case RecordDecl r -> recordDecl(r); - case EnumDecl e -> enumDecl(e); - case ClassDecl c -> classDecl(c); - case InterfaceDecl i -> interfaceDecl(i); - case AnnotationDecl a -> annotationDecl(a); - case MethodDecl m -> methodDecl(m); - case ConstructorDecl c -> constructorDecl(c); - case FieldDecl f -> fieldDecl(f); - }; - } - - default T $(ParameterDecl it) { - return parameterDecl(it); - } - - default T $(ITypeReference it) { - return switch (it) { - case TypeReference typeRef -> typeReference(typeRef); - case PrimitiveTypeReference primitiveRef -> primitiveTypeReference(primitiveRef); - case ArrayTypeReference arrayRef -> arrayTypeReference(arrayRef); - case TypeParameterReference tpRef -> typeParameterReference(tpRef); - }; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java deleted file mode 100644 index 18a683ff..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/AbstractAPIVisitor.java +++ /dev/null @@ -1,124 +0,0 @@ -package com.github.maracas.roseau.api.visit; - -import com.github.maracas.roseau.api.model.API; -import com.github.maracas.roseau.api.model.AnnotationDecl; -import com.github.maracas.roseau.api.model.ClassDecl; -import com.github.maracas.roseau.api.model.ConstructorDecl; -import com.github.maracas.roseau.api.model.EnumDecl; -import com.github.maracas.roseau.api.model.ExecutableDecl; -import com.github.maracas.roseau.api.model.FieldDecl; -import com.github.maracas.roseau.api.model.InterfaceDecl; -import com.github.maracas.roseau.api.model.MethodDecl; -import com.github.maracas.roseau.api.model.ParameterDecl; -import com.github.maracas.roseau.api.model.RecordDecl; -import com.github.maracas.roseau.api.model.Symbol; -import com.github.maracas.roseau.api.model.TypeDecl; -import com.github.maracas.roseau.api.model.reference.ArrayTypeReference; -import com.github.maracas.roseau.api.model.reference.PrimitiveTypeReference; -import com.github.maracas.roseau.api.model.reference.TypeParameterReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; - -public class AbstractAPIVisitor implements APIAlgebra { - public Visit api(API it) { - return () -> it.getAllTypes().forEach(t -> $(t).visit()); - } - - @Override - public Visit classDecl(ClassDecl it) { - return () -> { - typeDecl(it).visit(); - it.getSuperClass().ifPresent(sup -> $(sup).visit()); - it.getConstructors().forEach(cons -> $(cons).visit()); - }; - } - - @Override - public Visit interfaceDecl(InterfaceDecl it) { - return typeDecl(it); - } - - @Override - public Visit enumDecl(EnumDecl it) { - return classDecl(it); - } - - @Override - public Visit annotationDecl(AnnotationDecl it) { - return typeDecl(it); - } - - @Override - public Visit recordDecl(RecordDecl it) { - return classDecl(it); - } - - @Override - public Visit methodDecl(MethodDecl it) { - return executableDecl(it); - } - - @Override - public Visit constructorDecl(ConstructorDecl it) { - return executableDecl(it); - } - - @Override - public Visit fieldDecl(FieldDecl it) { - return () -> { - symbol(it).visit(); - if (it.getType() != null) - $(it.getType()).visit(); - }; - } - - @Override - public Visit parameterDecl(ParameterDecl it) { - return () -> { - if (it.type() != null) - $(it.type()).visit(); - }; - } - - @Override - public Visit typeReference(TypeReference it) { - return () -> {}; - } - - @Override - public Visit primitiveTypeReference(PrimitiveTypeReference it) { - return () -> {}; - } - - @Override - public Visit arrayTypeReference(ArrayTypeReference it) { - return () -> {}; - } - - @Override - public Visit typeParameterReference(TypeParameterReference it) { - return () -> {}; - } - - public Visit symbol(Symbol it) { - return () -> {}; - } - - public Visit typeDecl(TypeDecl it) { - return () -> { - symbol(it).visit(); - it.getImplementedInterfaces().forEach(intf -> $(intf).visit()); - it.getFields().forEach(field -> $(field).visit()); - it.getMethods().forEach(meth -> $(meth).visit()); - }; - } - - public Visit executableDecl(ExecutableDecl it) { - return () -> { - symbol(it).visit(); - if (it.getType() != null) - $(it.getType()).visit(); - it.getParameters().forEach(p -> $(p).visit()); - it.getThrownExceptions().forEach(e -> $(e).visit()); - }; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java b/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java deleted file mode 100644 index b65b8ce5..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/api/visit/Visit.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.github.maracas.roseau.api.visit; - -@FunctionalInterface -public interface Visit { - void visit(); -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java deleted file mode 100644 index 8a0aa888..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/APIDiff.java +++ /dev/null @@ -1,349 +0,0 @@ -package com.github.maracas.roseau.diff; - -import com.github.maracas.roseau.api.model.API; -import com.github.maracas.roseau.api.model.ClassDecl; -import com.github.maracas.roseau.api.model.ConstructorDecl; -import com.github.maracas.roseau.api.model.ExecutableDecl; -import com.github.maracas.roseau.api.model.FieldDecl; -import com.github.maracas.roseau.api.model.FormalTypeParameter; -import com.github.maracas.roseau.api.model.MethodDecl; -import com.github.maracas.roseau.api.model.SourceLocation; -import com.github.maracas.roseau.api.model.Symbol; -import com.github.maracas.roseau.api.model.TypeDecl; -import com.github.maracas.roseau.api.model.reference.ITypeReference; -import com.github.maracas.roseau.api.model.reference.TypeReference; -import com.github.maracas.roseau.diff.changes.BreakingChange; -import com.github.maracas.roseau.diff.changes.BreakingChangeKind; - -import java.io.FileWriter; -import java.io.IOException; -import java.util.ArrayList; -import java.util.HashSet; -import java.util.List; -import java.util.Objects; -import java.util.Optional; - -/** - * This class represents Roseau's comparison tool for detecting breaking changes between two API versions. - */ -public class APIDiff { - /** - * The first version of the API to be compared. - */ - private final API v1; - - /** - * The second version of the API to be compared. - */ - private final API v2; - - /** - * List of all the breaking changes identified in the comparison. - */ - private final List breakingChanges; - - /** - * Constructs an APIDiff instance to compare two API versions for breaking changes detection. - * - * @param v1 The first version of the API to compare. - * @param v2 The second version of the API to compare. - */ - public APIDiff(API v1, API v2) { - this.v1 = Objects.requireNonNull(v1); - this.v2 = Objects.requireNonNull(v2); - breakingChanges = new ArrayList<>(); - } - - public List diff() { - v1.getExportedTypes().forEach(t1 -> { - Optional findT2 = v2.findExportedType(t1.getQualifiedName()); - - findT2.ifPresentOrElse( - // There is a matching type - t2 -> { - diffType(t1, t2); - diffFields(t1, t2); - diffMethods(t1, t2); - diffAddedMethods(t1, t2); - - if (t1 instanceof ClassDecl c1 && t2 instanceof ClassDecl c2) - diffConstructors(c1, c2); - }, - // Type has been removed - () -> bc(BreakingChangeKind.TYPE_REMOVED, t1) - ); - }); - - return breakingChanges; - } - - private void diffFields(TypeDecl t1, TypeDecl t2) { - t1.getFields().forEach(f1 -> { - Optional findF2 = t2.getAllFields().stream() - .filter(f -> f.getSimpleName().equals(f1.getSimpleName())) - .findFirst(); - - findF2.ifPresentOrElse( - // There is a matching field - f2 -> diffField(f1, f2), - // The field has been removed - () -> bc(BreakingChangeKind.FIELD_REMOVED, f1) - ); - }); - } - - private void diffMethods(TypeDecl t1, TypeDecl t2) { - t1.getMethods().forEach(m1 -> { - Optional matchM2 = t2.getAllMethods().stream() - .filter(m -> m.hasSameSignature(m1)) - .findFirst(); - - matchM2.ifPresentOrElse( - // There is a matching method - m2 -> diffMethod(t1, m1, m2), - // The method has been removed - () -> bc(BreakingChangeKind.METHOD_REMOVED, m1) - ); - }); - } - - private void diffConstructors(ClassDecl c1, ClassDecl c2) { - c1.getConstructors().forEach(cons1 -> { - Optional matchCons2 = c2.getConstructors().stream() - .filter(cons -> cons.hasSameSignature(cons1)) - .findFirst(); - - matchCons2.ifPresentOrElse( - // There is a matching constructor - cons2 -> diffConstructor(cons1, cons2), - // The constructor has been removed - () -> bc(BreakingChangeKind.CONSTRUCTOR_REMOVED, cons1) - ); - }); - } - - private void diffAddedMethods(TypeDecl t1, TypeDecl t2) { - t2.getMethods().stream() - .filter(m2 -> t1.getAllMethods().stream().noneMatch(m1 -> m1.hasSameSignature(m2))) - .forEach(m2 -> { - if (t2.isInterface() && !m2.isDefault()) - bc(BreakingChangeKind.METHOD_ADDED_TO_INTERFACE, t1); - - if (t2.isClass() && m2.isAbstract()) - bc(BreakingChangeKind.METHOD_ABSTRACT_ADDED_TO_CLASS, t1); - }); - } - - private void diffType(TypeDecl t1, TypeDecl t2) { - if (t1.isClass()) { - if (!t1.isEffectivelyFinal() && t2.isEffectivelyFinal()) - bc(BreakingChangeKind.CLASS_NOW_FINAL, t1); - - if (!t1.isSealed() && t2.isSealed()) - bc(BreakingChangeKind.CLASS_NOW_FINAL, t1); - - if (!t1.isAbstract() && t2.isAbstract()) - bc(BreakingChangeKind.CLASS_NOW_ABSTRACT, t1); - - if (!t1.isStatic() && t2.isStatic() && t1.isNested() && t2.isNested()) - bc(BreakingChangeKind.NESTED_CLASS_NOW_STATIC, t1); - - if (t1.isStatic() && !t2.isStatic() && t1.isNested() && t2.isNested()) - bc(BreakingChangeKind.NESTED_CLASS_NO_LONGER_STATIC, t1); - - if (!t1.isCheckedException() && t2.isCheckedException()) - bc(BreakingChangeKind.CLASS_NOW_CHECKED_EXCEPTION, t1); - } - - if (t1.isPublic() && t2.isProtected()) - bc(BreakingChangeKind.TYPE_NOW_PROTECTED, t1); - - if (t1 instanceof ClassDecl cls1 && t2 instanceof ClassDecl cls2) { - if (cls1.getSuperClass().isPresent() && cls2.getSuperClass().isEmpty()) - bc(BreakingChangeKind.SUPERCLASS_MODIFIED_INCOMPATIBLE, t1); - } - - // Deleted super-interfaces - if (t1.getImplementedInterfaces().stream() - .anyMatch(intf1 -> t2.getImplementedInterfaces().stream() - .noneMatch(intf2 -> intf1.getQualifiedName().equals(intf2.getQualifiedName())))) - bc(BreakingChangeKind.SUPERCLASS_MODIFIED_INCOMPATIBLE, t1); - - if (!t1.getClass().equals(t2.getClass())) - bc(BreakingChangeKind.CLASS_TYPE_CHANGED, t1); - - int formalParametersCount1 = t1.getFormalTypeParameters().size(); - int formalParametersCount2 = t2.getFormalTypeParameters().size(); - if (formalParametersCount1 == formalParametersCount2) { - for (int i = 0; i < formalParametersCount1; i++) { - FormalTypeParameter p1 = t1.getFormalTypeParameters().get(i); - FormalTypeParameter p2 = t2.getFormalTypeParameters().get(i); - - List bounds1 = p1.bounds().stream() - .map(ITypeReference::getQualifiedName) - .toList(); - List bounds2 = p2.bounds().stream() - .map(ITypeReference::getQualifiedName) - .toList(); - - if (bounds1.size() != bounds2.size() - || !(new HashSet<>(bounds1)).equals(new HashSet<>(bounds2))) { - bc(BreakingChangeKind.TYPE_FORMAL_TYPE_PARAMETERS_CHANGED, t1); - } - } - } else if (formalParametersCount1 < formalParametersCount2) { - bc(BreakingChangeKind.TYPE_FORMAL_TYPE_PARAMETERS_REMOVED, t1); - } else { - bc(BreakingChangeKind.TYPE_FORMAL_TYPE_PARAMETERS_ADDED, t1); - } - } - - private void diffField(FieldDecl f1, FieldDecl f2) { - if (!f1.isFinal() && f2.isFinal()) - bc(BreakingChangeKind.FIELD_NOW_FINAL, f1); - - if (!f1.isStatic() && f2.isStatic()) - bc(BreakingChangeKind.FIELD_NOW_STATIC, f1); - - if (f1.isStatic() && !f2.isStatic()) - bc(BreakingChangeKind.FIELD_NO_LONGER_STATIC, f1); - - if (!f1.getType().equals(f2.getType())) - bc(BreakingChangeKind.FIELD_TYPE_CHANGED, f1); - - if (f1.isPublic() && f2.isProtected()) - bc(BreakingChangeKind.FIELD_LESS_ACCESSIBLE, f1); - } - - private void diffMethod(TypeDecl t1, MethodDecl m1, MethodDecl m2) { - if (!m1.isFinal() && m2.isFinal()) - bc(BreakingChangeKind.METHOD_NOW_FINAL, m1); - - if (!m1.isStatic() && m2.isStatic()) - bc(BreakingChangeKind.METHOD_NOW_STATIC, m1); - - if (!m1.isNative() && m2.isNative()) - bc(BreakingChangeKind.METHOD_NOW_NATIVE, m1); - - if (m1.isStatic() && !m2.isStatic()) - bc(BreakingChangeKind.METHOD_NO_LONGER_STATIC, m1); - - if (m1.isStrictFp() && !m2.isStrictFp()) - bc(BreakingChangeKind.METHOD_NO_LONGER_STRICTFP, m1); - - if (!m1.isAbstract() && m2.isAbstract()) - bc(BreakingChangeKind.METHOD_NOW_ABSTRACT, m1); - - if (m1.isAbstract() && m2.isDefault()) // Careful - bc(BreakingChangeKind.METHOD_ABSTRACT_NOW_DEFAULT, m1); - - if (m1.isPublic() && m2.isProtected()) - bc(BreakingChangeKind.METHOD_LESS_ACCESSIBLE, m1); - - if (!m1.getType().equals(m2.getType())) - bc(BreakingChangeKind.METHOD_RETURN_TYPE_CHANGED, m1); - - List> additionalExceptions1 = m1.getThrownCheckedExceptions().stream() - .filter(e -> !m2.getThrownCheckedExceptions().contains(e)) - .toList(); - - List> additionalExceptions2 = m2.getThrownCheckedExceptions().stream() - .filter(e -> !m1.getThrownCheckedExceptions().contains(e)) - .toList(); - - if (!additionalExceptions1.isEmpty()) - bc(BreakingChangeKind.METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION, m1); - - if (!additionalExceptions2.isEmpty()) - bc(BreakingChangeKind.METHOD_NOW_THROWS_CHECKED_EXCEPTION, m1); - - // JLS says only one vararg per method, in last position - if (!m1.getParameters().isEmpty() && m1.getParameters().getLast().isVarargs() - && (m2.getParameters().isEmpty() || !m2.getParameters().getLast().isVarargs())) - bc(BreakingChangeKind.METHOD_NO_LONGER_VARARGS, m1); - - if (!m2.getParameters().isEmpty() && m2.getParameters().getLast().isVarargs() - && (m1.getParameters().isEmpty() || !m1.getParameters().getLast().isVarargs())) - bc(BreakingChangeKind.METHOD_NOW_VARARGS, m1); - - // FIXME: no checks for parameters??? - - diffFormalTypeParameters(m1, m2); - } - - private void diffConstructor(ConstructorDecl cons1, ConstructorDecl cons2) { - if (cons1.isPublic() && cons2.isProtected()) - bc(BreakingChangeKind.CONSTRUCTOR_LESS_ACCESSIBLE, cons1); - - diffFormalTypeParameters(cons1, cons2); - } - - private void diffFormalTypeParameters(ExecutableDecl e1, ExecutableDecl e2) { - if (e1.getFormalTypeParameters().size() > e2.getFormalTypeParameters().size()) - bc(BreakingChangeKind.METHOD_FORMAL_TYPE_PARAMETERS_REMOVED, e1); - - if (e1.getFormalTypeParameters().size() < e2.getFormalTypeParameters().size()) - bc(BreakingChangeKind.METHOD_FORMAL_TYPE_PARAMETERS_ADDED, e1); - - for (int i = 0; i < e1.getFormalTypeParameters().size(); i++) { - List bounds1 = e1.getFormalTypeParameters().get(i).bounds(); - - if (i < e2.getFormalTypeParameters().size()) { - List bounds2 = e2.getFormalTypeParameters().get(i).bounds(); - - if (bounds1.size() != bounds2.size() - || !new HashSet<>(bounds1).equals(new HashSet<>(bounds2))) - bc(BreakingChangeKind.METHOD_FORMAL_TYPE_PARAMETERS_CHANGED, e1); - } - } - } - - private void bc(BreakingChangeKind kind, Symbol impactedSymbol) { - breakingChanges.add(new BreakingChange(kind, impactedSymbol)); - } - - /** - * Retrieves the list of all the breaking changes detected between the two API versions. - * - * @return List of all the breaking changes - */ - public List getBreakingChanges() { - return breakingChanges; - } - - /** - * Generates a csv report for the detected breaking changes. This report includes the kind, type qualifiedName, - *

- * position, associated element, and nature of each detected BC. - */ - public void breakingChangesReport() throws IOException { - try (FileWriter writer = new FileWriter("breaking_changes_report.csv")) { - writer.write("Kind,Element,Nature,Position\n"); - - for (BreakingChange breakingChange : breakingChanges) { - String kind = breakingChange.kind().toString(); - String element = breakingChange.impactedSymbol().getQualifiedName(); - String nature = breakingChange.kind().getNature().toString(); - SourceLocation location = breakingChange.impactedSymbol().getLocation(); - - writer.write(kind + "," + element + "," + nature + "," + location + "\n"); - } - } - } - - /** - * Generates a string representation of the breaking changes list. - * - * @return A formatted string containing all the breaking changes and their info. - */ - @Override - public String toString() { - StringBuilder result = new StringBuilder(); - for (BreakingChange breakingChange : breakingChanges) { - result.append(breakingChange.toString()).append("\n"); - result.append(" =========================\n\n"); - } - - return result.toString(); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChange.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChange.java deleted file mode 100644 index 7929f2ef..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChange.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.maracas.roseau.diff.changes; - -import com.github.maracas.roseau.api.model.Symbol; - -/** - * Represents a breaking change identified during the comparison of APIs between the two library versions. - * This class encapsulates information about the breaking change's kind and impacted symbol. - * - * @param kind The kind of the breaking change. - * @param impactedSymbol The element associated with the breaking change. - */ -public record BreakingChange( - BreakingChangeKind kind, - Symbol impactedSymbol -) { - @Override - public String toString() { - return "BC[kind=%s, symbol=%s]".formatted(kind, impactedSymbol.getQualifiedName()); - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeKind.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeKind.java deleted file mode 100644 index 3d9362cb..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeKind.java +++ /dev/null @@ -1,87 +0,0 @@ -package com.github.maracas.roseau.diff.changes; - -import static com.github.maracas.roseau.diff.changes.BreakingChangeNature.ADDITION; -import static com.github.maracas.roseau.diff.changes.BreakingChangeNature.DELETION; -import static com.github.maracas.roseau.diff.changes.BreakingChangeNature.MUTATION; - -/** - * Enumerates the source and binary breaking changes taken into account. - */ -public enum BreakingChangeKind { - TYPE_REMOVED(DELETION), - CLASS_NOW_ABSTRACT(MUTATION), - CLASS_NOW_FINAL(MUTATION), - NESTED_CLASS_NOW_STATIC(MUTATION), - NESTED_CLASS_NO_LONGER_STATIC(MUTATION), - CLASS_TYPE_CHANGED(MUTATION), - CLASS_NOW_CHECKED_EXCEPTION(MUTATION), - TYPE_NOW_PROTECTED(MUTATION), - SUPERCLASS_MODIFIED_INCOMPATIBLE(MUTATION), - TYPE_FORMAL_TYPE_PARAMETERS_ADDED(MUTATION), - TYPE_FORMAL_TYPE_PARAMETERS_REMOVED(MUTATION), - TYPE_FORMAL_TYPE_PARAMETERS_CHANGED(MUTATION), - - METHOD_REMOVED(DELETION), - METHOD_LESS_ACCESSIBLE(MUTATION), - METHOD_RETURN_TYPE_CHANGED(MUTATION), - METHOD_NOW_ABSTRACT(MUTATION), - METHOD_NOW_FINAL(MUTATION), - METHOD_NOW_STATIC(MUTATION), - METHOD_NOW_NATIVE(MUTATION), - METHOD_NOW_VARARGS(MUTATION), - METHOD_NO_LONGER_VARARGS(MUTATION), - METHOD_NO_LONGER_STATIC(MUTATION), - METHOD_NO_LONGER_STRICTFP(MUTATION), - METHOD_ADDED_TO_INTERFACE(ADDITION), - METHOD_NOW_THROWS_CHECKED_EXCEPTION(MUTATION), - METHOD_NO_LONGER_THROWS_CHECKED_EXCEPTION(MUTATION), - METHOD_ABSTRACT_ADDED_TO_CLASS(ADDITION), - METHOD_ABSTRACT_NOW_DEFAULT(MUTATION), - METHOD_FORMAL_TYPE_PARAMETERS_ADDED(MUTATION), - METHOD_FORMAL_TYPE_PARAMETERS_REMOVED(MUTATION), - METHOD_FORMAL_TYPE_PARAMETERS_CHANGED(MUTATION), - - FIELD_NOW_FINAL(MUTATION), - FIELD_NOW_STATIC(MUTATION), - FIELD_NO_LONGER_STATIC(MUTATION), - FIELD_TYPE_CHANGED(MUTATION), - FIELD_REMOVED(DELETION), - FIELD_LESS_ACCESSIBLE(MUTATION), - - CONSTRUCTOR_REMOVED(DELETION), - CONSTRUCTOR_LESS_ACCESSIBLE(MUTATION); - - // Do not make sense or unsupported or not implemented yet - /*ANNOTATION_DEPRECATED_ADDED, - - TYPE_GENERICS_CHANGED, - - METHOD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS, - METHOD_IS_STATIC_AND_OVERRIDES_NOT_STATIC, - METHOD_IS_NOT_STATIC_AND_OVERRIDES_STATIC, - METHOD_RETURN_TYPE_GENERICS_CHANGED, - METHOD_PARAMETER_GENERICS_CHANGED, - METHOD_NEW_DEFAULT, - METHOD_MOVED_TO_SUPERCLASS, - - FIELD_STATIC_AND_OVERRIDES_NON_STATIC, - FIELD_NON_STATIC_AND_OVERRIDES_STATIC, - FIELD_LESS_ACCESSIBLE_THAN_IN_SUPERCLASS, - FIELD_GENERICS_CHANGED, - - CONSTRUCTOR_PARAMS_GENERICS_CHANGED, - CONSTRUCTOR_GENERICS_CHANGED, - CONSTRUCTOR_FORMAL_TYPE_PARAMETERS_CHANGED, - CONSTRUCTOR_FORMAL_TYPE_PARAMETERS_ADDED, - CONSTRUCTOR_FORMAL_TYPE_PARAMETERS_REMOVED;*/ - - private final BreakingChangeNature nature; - - BreakingChangeKind(BreakingChangeNature nature) { - this.nature = nature; - } - - public BreakingChangeNature getNature() { - return nature; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeNature.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeNature.java deleted file mode 100644 index 7da6ce52..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/BreakingChangeNature.java +++ /dev/null @@ -1,21 +0,0 @@ -package com.github.maracas.roseau.diff.changes; - -/** - * Enumerates the three possible natures of a breaking change: ADDITION, MUTATION, and DELETION. - */ -public enum BreakingChangeNature { - /** - * Indicates that the breaking change is a result of an addition to the API. - */ - ADDITION, - - /** - * Indicates that the breaking change results from an alteration of existing elements within the API. - */ - MUTATION, - - /** - * Indicates that the breaking change is a result of a deletion from the API. - */ - DELETION -} diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/package-info.java b/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/package-info.java deleted file mode 100644 index a775b2ef..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/diff/changes/package-info.java +++ /dev/null @@ -1,4 +0,0 @@ -/** - * This package contains the classes and types needed for API comparisons and breaking changes detection. - */ -package com.github.maracas.roseau.diff.changes; diff --git a/ConfGen/src/main/java/com/github/maracas/roseau/package-info.java b/ConfGen/src/main/java/com/github/maracas/roseau/package-info.java deleted file mode 100644 index d5a13a68..00000000 --- a/ConfGen/src/main/java/com/github/maracas/roseau/package-info.java +++ /dev/null @@ -1,5 +0,0 @@ -/** - * This package contains the main API extraction and comparison tools. - */ - -package com.github.maracas.roseau; From 7d437472592dc5d9250f32c072160953735eacc2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 19 Feb 2024 15:04:41 +0100 Subject: [PATCH 035/244] CodeGen: Implement Descriptor gen --- .../gilesi/confgen/RoseauDescriptor.java | 80 +++++++++++++++++++ .../github/maracas/gilesi/traceview/Main.java | 4 +- 2 files changed, 82 insertions(+), 2 deletions(-) create mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java new file mode 100644 index 00000000..2e36f269 --- /dev/null +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java @@ -0,0 +1,80 @@ +package com.github.maracas.gilesi.confgen; + +import com.github.maracas.roseau.api.model.MethodDecl; +import com.github.maracas.roseau.api.model.ParameterDecl; +import com.github.maracas.roseau.api.model.reference.*; + +import java.util.List; + +public class RoseauDescriptor { + public static String getDescriptor(MethodDecl methodDecl) throws Exception { + StringBuilder descriptor = new StringBuilder().append('('); + for (ParameterDecl parameterType : methodDecl.getParameters()) { + descriptor.append(getDescriptor(parameterType)); + } + return descriptor.append(')').append(getDescriptor(methodDecl.getType())).toString(); + } + + public static String getDescriptor(ParameterDecl parameterDecl) throws Exception { + return getDescriptor(parameterDecl.type()); + } + + public static String getDescriptor(ITypeReference iTypeReference) throws Exception { + switch (iTypeReference) { + case ArrayTypeReference arrayTypeReference -> { + return "[" + getDescriptor(arrayTypeReference.componentType()); + } + case PrimitiveTypeReference primitiveTypeReference -> { + String name = primitiveTypeReference.getQualifiedName(); + if (name.equals("int")) { + return "I"; + } else if (name.equals("void")) { + return "V"; + } else if (name.equals("boolean")) { + return "Z"; + } else if (name.equals("byte")) { + return "B"; + } else if (name.equals("char")) { + return "C"; + } else if (name.equals("short")) { + return "S"; + } else if (name.equals("double")) { + return "D"; + } else if (name.equals("float")) { + return "F"; + } else if (name.equals("long")) { + return "J"; + } + throw new Exception("Unsupported primitive type: " + name); + } + case TypeParameterReference ignored -> { + //String name = typeParameterReference.getQualifiedName(); + //return "L" + name.replace('.', '/') + ";"; + // That's going to be U getSmething() in the JVM, so return object. + return "Ljava/lang/Object;"; + } + case WildcardTypeReference ignored -> { + //String name = typeDecl.getQualifiedName(); + //return name; + // That's going to be U getSmething() in the JVM, so return object. + return "Ljava/lang/Object;"; + } + case TypeReference typeReference -> { + String typeArgumentString = ""; + List typeArgs = typeReference.getTypeArguments(); + if (!typeArgs.isEmpty()) { + // Check join string here to be very sure against spec and test it + typeArgumentString = "<" + String.join("", typeArgs.stream().map(t -> { + try { + return getDescriptor(t); + } catch (Exception e) { + throw new RuntimeException(e); + } + }).toList()) + ">"; + } + String name = typeReference.getQualifiedName(); + return "L" + name.replace('.', '/') + typeArgumentString + ";"; + } + } + } +} diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 940df1ca..ca15d651 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -14,9 +14,9 @@ public class Main { // The currently free index for variables to define in our java source code private static int varIndex = 0; // The map of instance ids to variable indexes - private static HashMap mapOfInstancesToIndexes = new HashMap(); + private static final HashMap mapOfInstancesToIndexes = new HashMap(); // The list of instance ids we already defined - private static List listOfDefinedInstances = new ArrayList(); + private static final List listOfDefinedInstances = new ArrayList(); private static String getInstanceVarName(int instanceId) { int i; From 69ad118f41f6a97d5d19cb78f4aca1dceb08ef4d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 11:31:59 +0100 Subject: [PATCH 036/244] Code cleanup --- .../confgen/spoon/SpoonLauncherUtilities.java | 6 +----- .../SpoonFullyQualifiedNameExtractor.java | 5 ++++- .../gilesi/instrumentation/TraceCollector.java | 17 +++++++++-------- .../gilesi/samples/sampleclient/Main2.java | 2 -- Samples/sampleclient/src/test/java/FooTest.java | 16 ++++++++-------- .../maracas/gilesi/samples/samplelibrary/A.java | 1 + .../gilesi/samples/samplelibrary/A2.java | 1 + .../models/TestTraceResults.java | 2 -- .../github/maracas/gilesi/traceview/Main.java | 14 ++++++++------ 9 files changed, 32 insertions(+), 32 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java index c723d0c4..bb8a2478 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -11,11 +11,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.security.InvalidParameterException; -import java.util.ArrayList; -import java.util.Collection; -import java.util.EnumSet; -import java.util.HashSet; -import java.util.List; +import java.util.*; import java.util.regex.Pattern; public class SpoonLauncherUtilities { diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java index 95be976e..33642b5f 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java @@ -4,7 +4,10 @@ import spoon.reflect.code.CtFieldRead; import spoon.reflect.code.CtFieldWrite; import spoon.reflect.code.CtInvocation; -import spoon.reflect.declaration.*; +import spoon.reflect.declaration.CtConstructor; +import spoon.reflect.declaration.CtField; +import spoon.reflect.declaration.CtMethod; +import spoon.reflect.declaration.CtType; import spoon.reflect.reference.CtExecutableReference; import spoon.reflect.reference.CtFieldReference; import spoon.reflect.reference.CtTypeReference; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 2428a1f0..ee9f13e4 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -2,6 +2,7 @@ import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; + import java.util.ArrayList; import java.util.Collection; @@ -18,6 +19,14 @@ public static void addMethodTrace(Trace trace) { CURRENT_TRACES.Traces.add(trace); } + public static String getCurrentKey() { + if (CURRENT_TRACES == null) { + return ""; + } + + return CURRENT_TRACES.Test; + } + public static void setCurrentKey(String currentKey) { if (CURRENT_TRACES != null) { TRACES.add(CURRENT_TRACES); @@ -31,14 +40,6 @@ public static void setCurrentKey(String currentKey) { CURRENT_TRACES.Traces = new ArrayList<>(); } } - - public static String getCurrentKey() { - if (CURRENT_TRACES == null) { - return ""; - } - - return CURRENT_TRACES.Test; - } /** * This method returns the complete list of every cached complete method traces diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java b/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java index 5dfa4462..036bb3d0 100644 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java +++ b/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java @@ -92,8 +92,6 @@ public static void main(String[] args) { Foo.SomeValueStoredHere = Foo.SomeValueStoredHere + Foo.SomeValueStoredHere; - - Foo2 ff = new Foo2("yo"); System.out.println(ff.sayHelloFoo()); diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/sampleclient/src/test/java/FooTest.java index 1534ca9c..ae9dfdab 100644 --- a/Samples/sampleclient/src/test/java/FooTest.java +++ b/Samples/sampleclient/src/test/java/FooTest.java @@ -51,15 +51,15 @@ public void mainTest() { assertEquals(var10, "420"); assertEquals(var11, "testestest696969696"); - java.lang.String[] var15 = new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }; + java.lang.String[] var15 = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; java.lang.String var14 = Foo.HelloEveryone(var15); assertEquals(var14, "Hello [Toto, Tata, Titi, JP, PA, JR]"); - assertArrayEquals(var15, new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }); + assertArrayEquals(var15, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); java.util.ArrayList var17 = new ArrayList(); - var17.addAll(Arrays.stream(new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }).toList()); + var17.addAll(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); java.util.ArrayList var171 = new ArrayList(); - var171.addAll(Arrays.stream(new String[] { "NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD" }).toList()); + var171.addAll(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); java.lang.String var16 = Foo.HelloEveryone2(var17); assertEquals(var16, "Hello TotoTataTitiJPPAJR"); assertEquals(var17, var171); @@ -109,15 +109,15 @@ public void mainTest() { assertEquals(var10, "420"); assertEquals(var11, "testestest696969696"); - java.lang.String[] var27 = new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }; + java.lang.String[] var27 = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; java.lang.String var26 = Foo2.jhgbjtjbh(var27); assertEquals(var26, "Hello [Toto, Tata, Titi, JP, PA, JR]"); - assertArrayEquals(var27, new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }); + assertArrayEquals(var27, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); java.util.ArrayList var29 = new ArrayList(); java.util.ArrayList var291 = new ArrayList(); - var29.addAll(Arrays.stream(new String[] { "Toto", "Tata", "Titi", "JP", "PA", "JR" }).toList()); - var291.addAll(Arrays.stream(new String[] { "NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD" }).toList()); + var29.addAll(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); + var291.addAll(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); java.lang.String var28 = Foo2.njrhbgtujhu(var29); assertEquals(var28, "Hello TotoTataTitiJPPAJR"); assertEquals(var29, var291); diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java index 2957916b..3bbae35a 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java @@ -2,6 +2,7 @@ public class A { private int j = 0; + public A(int j) { this.j = j; } diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java index 2b054c09..00c497c6 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java @@ -2,6 +2,7 @@ public class A2 { private int i; + public A2(int i) { this.i = i; } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java index 83d41f4f..7cf11727 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java @@ -1,7 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import java.util.List; - public class TestTraceResults { public Trace[] Traces; public String Test; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index ca15d651..bc1408bb 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -8,15 +8,18 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; public class Main { - // The currently free index for variables to define in our java source code - private static int varIndex = 0; // The map of instance ids to variable indexes private static final HashMap mapOfInstancesToIndexes = new HashMap(); // The list of instance ids we already defined private static final List listOfDefinedInstances = new ArrayList(); + // The currently free index for variables to define in our java source code + private static int varIndex = 0; private static String getInstanceVarName(int instanceId) { int i; @@ -66,7 +69,7 @@ private static String serializableDataToJava(TraceData serializableData) { private static String getReturnStatementAsCode(TraceData serializableData) { if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { - return getInstanceVarName(serializableData.getInstanceId()); + return getInstanceVarName(serializableData.getInstanceId()); } else { String returnType = getCleanedType(serializableData.getFullyQualifiedTypeName()); listOfDefinedInstances.add(serializableData.getInstanceId()); @@ -178,8 +181,7 @@ private static void printTraceAsCode(TraceEvent event) { public static void main(String[] args) throws IOException { TestTraceResults[] testTraceResultsList = readTraces(args[0]); - for (TestTraceResults testTraceResults : testTraceResultsList) - { + for (TestTraceResults testTraceResults : testTraceResultsList) { Trace[] methodTraces = testTraceResults.Traces; List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); From ce6c87fd653be88dacc67d2b4fe45daa14f7acd3 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 11:32:56 +0100 Subject: [PATCH 037/244] Improve descriptor generation Also remove type args handling, turns out not even asm and bytebuddy generates those (...this could be a problem no?, should we edit both, we could totally have two methods with diff type args for a map for example............) --- .../maracas/gilesi/confgen/RoseauDescriptor.java | 13 +++++++++++-- 1 file changed, 11 insertions(+), 2 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java index 2e36f269..c2ee31a8 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java @@ -1,5 +1,6 @@ package com.github.maracas.gilesi.confgen; +import com.github.maracas.roseau.api.model.ConstructorDecl; import com.github.maracas.roseau.api.model.MethodDecl; import com.github.maracas.roseau.api.model.ParameterDecl; import com.github.maracas.roseau.api.model.reference.*; @@ -7,6 +8,14 @@ import java.util.List; public class RoseauDescriptor { + public static String getDescriptor(ConstructorDecl constructorDecl) throws Exception { + StringBuilder descriptor = new StringBuilder().append('('); + for (ParameterDecl parameterType : constructorDecl.getParameters()) { + descriptor.append(getDescriptor(parameterType)); + } + return descriptor.append(")V").toString(); + } + public static String getDescriptor(MethodDecl methodDecl) throws Exception { StringBuilder descriptor = new StringBuilder().append('('); for (ParameterDecl parameterType : methodDecl.getParameters()) { @@ -62,7 +71,7 @@ public static String getDescriptor(ITypeReference iTypeReference) throws Excepti case TypeReference typeReference -> { String typeArgumentString = ""; List typeArgs = typeReference.getTypeArguments(); - if (!typeArgs.isEmpty()) { + /*if (!typeArgs.isEmpty()) { // Check join string here to be very sure against spec and test it typeArgumentString = "<" + String.join("", typeArgs.stream().map(t -> { try { @@ -71,7 +80,7 @@ public static String getDescriptor(ITypeReference iTypeReference) throws Excepti throw new RuntimeException(e); } }).toList()) + ">"; - } + }*/ String name = typeReference.getQualifiedName(); return "L" + name.replace('.', '/') + typeArgumentString + ";"; } From 2d6673c966efc3fe7e36b679fd37804a320fdc6c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 11:33:36 +0100 Subject: [PATCH 038/244] Revamp config models and data to match on descriptors too --- .../github/maracas/gilesi/confgen/Main.java | 77 ++++++------------- .../models/InstrumentationParameter.java | 5 +- .../models/InstrumentationParameters.java | 4 +- .../maracas/gilesi/instrumentation/Agent.java | 4 +- .../models/InstrumentationParameter.java | 3 +- .../models/InstrumentationParameters.java | 4 +- .../visitors/MethodInstrumentor.java | 26 +++---- .../visitors/TestInstrumentor.java | 14 ++-- 8 files changed, 52 insertions(+), 85 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index dd952fe1..e30176c9 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -16,10 +16,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.List; +import java.util.*; public class Main { private static String getClassNameFromFQN(String fullyQualifiedName) { @@ -46,56 +43,22 @@ private static String getMethodNameFromFQN(String fullyQualifiedName) { return nameElements[nameElements.length - 1]; } - private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName) { - // If we already have a class here, don't add a new one - if (instrumentationParameters.ClassesToInstrument.stream().anyMatch(t -> t.ClassName.equals(className))) { - // Find the class - for (InstrumentationParameter classToInstrument : instrumentationParameters.ClassesToInstrument) { - if (classToInstrument.ClassName.equals(className)) { - // Only add if missing - if (classToInstrument.ClassMethodsOrConstructors.stream().noneMatch(t -> t.equals(methodName))) { - classToInstrument.ClassMethodsOrConstructors.add(methodName); - } - - // We found what we wanted so break now. - break; - } - } - } else { - // Otherwise, add a brand new one now. - InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); - instrumentationParameter.ClassName = className; - instrumentationParameter.ClassMethodsOrConstructors = new ArrayList<>(); - instrumentationParameter.ClassMethodsOrConstructors.add(methodName); - - instrumentationParameters.ClassesToInstrument.add(instrumentationParameter); - } + private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName, String methodDescriptor) { + InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); + instrumentationParameter.ClassName = className; + instrumentationParameter.MethodName = methodName; + instrumentationParameter.MethodDescriptor = methodDescriptor; + + instrumentationParameters.MethodsToInstrument.add(instrumentationParameter); } private static void addToInstrumentationObjectTest(InstrumentationParameters instrumentationParameters, String className, String methodName) { - // If we already have a class here, don't add a new one - if (instrumentationParameters.TestClassesToInstrument.stream().anyMatch(t -> t.ClassName.equals(className))) { - // Find the class - for (InstrumentationParameter classToInstrument : instrumentationParameters.TestClassesToInstrument) { - if (classToInstrument.ClassName.equals(className)) { - // Only add if missing - if (classToInstrument.ClassMethodsOrConstructors.stream().noneMatch(t -> t.equals(methodName))) { - classToInstrument.ClassMethodsOrConstructors.add(methodName); - } - - // We found what we wanted so break now. - break; - } - } - } else { - // Otherwise, add a brand new one now. - InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); - instrumentationParameter.ClassName = className; - instrumentationParameter.ClassMethodsOrConstructors = new ArrayList<>(); - instrumentationParameter.ClassMethodsOrConstructors.add(methodName); - - instrumentationParameters.TestClassesToInstrument.add(instrumentationParameter); - } + InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); + instrumentationParameter.ClassName = className; + instrumentationParameter.MethodName = methodName; + instrumentationParameter.MethodDescriptor = null; + + instrumentationParameters.TestsToInstrument.add(instrumentationParameter); } public static void main(String[] args) throws Exception { @@ -112,8 +75,8 @@ public static void main(String[] args) throws Exception { API libraryApiModel = new SpoonAPIExtractor(libraryModel).extractAPI(); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); - instrumentationParameters.ClassesToInstrument = new ArrayList<>(); - instrumentationParameters.TestClassesToInstrument = new ArrayList<>(); + instrumentationParameters.MethodsToInstrument = new ArrayList<>(); + instrumentationParameters.TestsToInstrument = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); for (ClassDecl classDecl : libraryApiModel.getExportedTypes().stream() @@ -123,19 +86,23 @@ public static void main(String[] args) throws Exception { for (ConstructorDecl constructor : classDecl.getConstructors()) { String className = getClassNameFromFQN(constructor.getQualifiedName()); String methodName = ""; + String methodDescriptor = RoseauDescriptor.getDescriptor(constructor); - addToInstrumentationObject(instrumentationParameters, className, methodName); // Something breaks here + addToInstrumentationObject(instrumentationParameters, className, methodName, methodDescriptor); } for (MethodDecl method : classDecl.getMethods()) { String FQN = method.getQualifiedName(); String className = getClassNameFromFQN(FQN); String methodName = getMethodNameFromFQN(FQN); + String methodDescriptor = RoseauDescriptor.getDescriptor(method); - addToInstrumentationObject(instrumentationParameters, className, methodName); + addToInstrumentationObject(instrumentationParameters, className, methodName, methodDescriptor); } } + System.out.println("Processing Library Project..."); + libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() .forEach(method -> instrumentationParameters.LibraryMethods .add(type.getQualifiedName() + "." + method.getSimpleName())))); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index 1044eda5..339789b1 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -1,8 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; -import java.util.List; - public class InstrumentationParameter { public String ClassName; - public List ClassMethodsOrConstructors; + public String MethodName; + public String MethodDescriptor; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 5feb8b4a..bc574ea5 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -3,7 +3,7 @@ import java.util.List; public class InstrumentationParameters { - public List ClassesToInstrument; - public List TestClassesToInstrument; + public List MethodsToInstrument; + public List TestsToInstrument; public List LibraryMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index a73e0dd9..795507bc 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -80,12 +80,12 @@ private static void installAgent(String arg, Instrumentation inst) { LibraryMethods = instrumentationParameters.LibraryMethods; // Instrument every class - for (InstrumentationParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { + for (InstrumentationParameter instrumentationParameter : instrumentationParameters.MethodsToInstrument) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } // Instrument every test - for (InstrumentationParameter instrumentationParameter : instrumentationParameters.TestClassesToInstrument) { + for (InstrumentationParameter instrumentationParameter : instrumentationParameters.TestsToInstrument) { TestInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java index 0811ebde..339789b1 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java @@ -2,5 +2,6 @@ public class InstrumentationParameter { public String ClassName; - public String[] ClassMethodsOrConstructors; + public String MethodName; + public String MethodDescriptor; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 516f0ccf..ca9b61e7 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; public class InstrumentationParameters { - public InstrumentationParameter[] ClassesToInstrument; - public InstrumentationParameter[] TestClassesToInstrument; + public InstrumentationParameter[] MethodsToInstrument; + public InstrumentationParameter[] TestsToInstrument; public String[] LibraryMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index d6d52a9d..eebfed13 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -3,6 +3,8 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import java.lang.instrument.Instrumentation; @@ -11,26 +13,24 @@ public class MethodInstrumentor { public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - getAgentBuilderFor(instrumentationParameter.ClassName, instrumentationParameter.ClassMethodsOrConstructors).installOn(inst); - } + ElementMatcher.Junction methodMatcher = named(instrumentationParameter.MethodName);//.and(ElementMatchers.hasDescriptor(instrumentationParameter.MethodDescriptor)); - private static AgentBuilder getAgentBuilderFor(String className, String[] classMethodsOrConstructors) { - return new AgentBuilder.Default() - .type(named(className)) + new AgentBuilder.Default() + .type(named(instrumentationParameter.ClassName)) .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> builder - .visit( - Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(ElementMatchers.namedOneOf(classMethodsOrConstructors))) - ) - .visit( - Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors))) - ) + .visit( + Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(methodMatcher)) + ) + .visit( + Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(methodMatcher)) + ) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) - .with(AgentBuilder.TypeStrategy.Default.REDEFINE); + .with(AgentBuilder.TypeStrategy.Default.REDEFINE).installOn(inst); } -} +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java index f0006b0d..3e17f98c 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java @@ -3,6 +3,8 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; import net.bytebuddy.matcher.ElementMatchers; import java.lang.instrument.Instrumentation; @@ -11,20 +13,18 @@ public class TestInstrumentor { public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - getAgentBuilderFor(instrumentationParameter.ClassName, instrumentationParameter.ClassMethodsOrConstructors).installOn(inst); - } + ElementMatcher.Junction methodMatcher = ElementMatchers.namedOneOf(instrumentationParameter.MethodName); - private static AgentBuilder getAgentBuilderFor(String className, String[] classMethodsOrConstructors) { - return new AgentBuilder.Default() - .type(named(className)) + new AgentBuilder.Default() + .type(named(instrumentationParameter.ClassName)) .transform((builder, typeDescription, classLoader, javaModule, protectionDomain) -> - builder.visit(Advice.to(TestAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.namedOneOf(classMethodsOrConstructors)))) + builder.visit(Advice.to(TestAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(methodMatcher))) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) - .with(AgentBuilder.TypeStrategy.Default.REDEFINE); + .with(AgentBuilder.TypeStrategy.Default.REDEFINE).installOn(inst); } } From bf53a9ed58f5684d178a9e352413fb6041af631e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 11:33:46 +0100 Subject: [PATCH 039/244] Normalize timestamps --- .../java/com/github/maracas/gilesi/instrumentation/Agent.java | 1 + .../github/maracas/gilesi/instrumentation/TraceFactory.java | 4 ++-- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 795507bc..dca2abe1 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -17,6 +17,7 @@ */ public class Agent { public static String[] LibraryMethods = new String[0]; + public static long ProcessEntryTimeStamp = System.currentTimeMillis(); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index a7b5e87f..3b275856 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -64,7 +64,7 @@ private static List getArgumentsAsSerializableData(Object[] arguments */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.currentTimeMillis(); + long entryMarker = System.currentTimeMillis() - Agent.ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); @@ -93,7 +93,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg */ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace) { // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.currentTimeMillis(); + long exitMarker = System.currentTimeMillis() - Agent.ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); From 9ff27df8e4e4844e67f5fd63cb9cab271508de1a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 13:25:43 +0100 Subject: [PATCH 040/244] Implement gathering of client methods --- .../github/maracas/gilesi/confgen/Main.java | 15 ++++++-- .../models/InstrumentationParameters.java | 1 + .../maracas/gilesi/instrumentation/Agent.java | 2 + .../models/InstrumentationParameters.java | 1 + .../visitors/ConstructorAdvisor.java | 37 +++++++++++++++++-- .../visitors/MethodAdvisor.java | 37 +++++++++++++++++-- 6 files changed, 83 insertions(+), 10 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index e30176c9..5661ecb5 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -78,6 +78,7 @@ public static void main(String[] args) throws Exception { instrumentationParameters.MethodsToInstrument = new ArrayList<>(); instrumentationParameters.TestsToInstrument = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); + instrumentationParameters.ClientMethods = new ArrayList<>(); for (ClassDecl classDecl : libraryApiModel.getExportedTypes().stream() .filter(ClassDecl.class::isInstance) @@ -111,11 +112,11 @@ public static void main(String[] args) throws Exception { List testMethods = new ArrayList<>(); - Launcher launcher = SpoonLauncherUtilities.getCommonLauncherInstance(); - SpoonLauncherUtilities.applyProjectToLauncher(launcher, Path.of(args[2]), EnumSet.of(CodeType.TEST)); - CtModel model = launcher.buildModel(); + Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); + SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(args[2]), CodeType.ALL); + CtModel clientModel = clientLauncher.buildModel(); - model.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() + clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() .forEach(method -> method.getAnnotations().stream() .filter(annotation -> annotation.getName().contains("Test")) .map(annotation -> type.getQualifiedName() + "." + method.getSignature()) @@ -128,6 +129,12 @@ public static void main(String[] args) throws Exception { addToInstrumentationObjectTest(instrumentationParameters, className, methodName); } + System.out.println("Processing Client Project..."); + + clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() + .forEach(method -> instrumentationParameters.ClientMethods + .add(type.getQualifiedName() + "." + method.getSimpleName())))); + ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); String apiJson = objectMapper.writeValueAsString(instrumentationParameters); Files.writeString(apiReportOutputPath, apiJson, StandardOpenOption.CREATE); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index bc574ea5..57009bd2 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -6,4 +6,5 @@ public class InstrumentationParameters { public List MethodsToInstrument; public List TestsToInstrument; public List LibraryMethods; + public List ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index dca2abe1..de499573 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -17,6 +17,7 @@ */ public class Agent { public static String[] LibraryMethods = new String[0]; + public static String[] ClientMethods = new String[0]; public static long ProcessEntryTimeStamp = System.currentTimeMillis(); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { @@ -79,6 +80,7 @@ private static void installAgent(String arg, Instrumentation inst) { } LibraryMethods = instrumentationParameters.LibraryMethods; + ClientMethods = instrumentationParameters.ClientMethods; // Instrument every class for (InstrumentationParameter instrumentationParameter : instrumentationParameters.MethodsToInstrument) { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index ca9b61e7..e1eaa112 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -4,4 +4,5 @@ public class InstrumentationParameters { public InstrumentationParameter[] MethodsToInstrument; public InstrumentationParameter[] TestsToInstrument; public String[] LibraryMethods; + public String[] ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 328a643b..0d736c63 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -70,7 +70,23 @@ public static Object enter( } } - return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + // Start with the caller + for (int i = 2; i < stackTraceElements.length; i++) { + StackTraceElement stackTraceElement = stackTraceElements[i]; + String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); + + if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + return null; + } + + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + } + } + + // We never found any trace of the client, something is up... + return null; } @Advice.OnMethodExit(inline = false) @@ -130,7 +146,22 @@ public static void exit( } } - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); - TraceCollector.addMethodTrace(trace); + // Start with the caller + for (int i = 2; i < stackTraceElements.length; i++) { + StackTraceElement stackTraceElement = stackTraceElements[i]; + String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); + + if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + return; + } + + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); + TraceCollector.addMethodTrace(trace); + } + } + + // We never found any trace of the client, something is up... } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 0c12fded..edc53205 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -70,7 +70,23 @@ public static Object enter( } } - return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + // Start with the caller + for (int i = 2; i < stackTraceElements.length; i++) { + StackTraceElement stackTraceElement = stackTraceElements[i]; + String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); + + if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + return null; + } + + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + } + } + + // We never found any trace of the client, something is up... + return null; } @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) @@ -131,7 +147,22 @@ public static void exit( } } - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); - TraceCollector.addMethodTrace(trace); + // Start with the caller + for (int i = 2; i < stackTraceElements.length; i++) { + StackTraceElement stackTraceElement = stackTraceElements[i]; + String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); + + if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + return; + } + + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); + TraceCollector.addMethodTrace(trace); + } + } + + // We never found any trace of the client, something is up... } } \ No newline at end of file From 62fcf95f73a0b6cdbdf2c8ee61a6240dc7beded2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 13:55:22 +0100 Subject: [PATCH 041/244] Cleanup code gen a tiny bit --- .../github/maracas/gilesi/traceview/Main.java | 56 ++++++++++++++----- 1 file changed, 41 insertions(+), 15 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index bc1408bb..3848127a 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -8,10 +8,7 @@ import java.io.File; import java.io.IOException; -import java.util.ArrayList; -import java.util.Comparator; -import java.util.HashMap; -import java.util.List; +import java.util.*; public class Main { // The map of instance ids to variable indexes @@ -111,7 +108,7 @@ private static String traceToCode(Trace methodTrace) { String argumentDeclaration = getReturnStatementAsCode(arg) + " = " + argumentValueAsCode; argList.add(getInstanceVarName(arg.getInstanceId())); - cleanedMethodName = argumentDeclaration + ";\n" + cleanedMethodName; + cleanedMethodName = argumentDeclaration + ";\n\t\t" + cleanedMethodName; } return cleanedMethodName + "(" + String.join(",", argList) + ");"; @@ -124,7 +121,7 @@ private static String traceArgumentsToAssert(Trace methodTrace) { argList.add("assert " + getInstanceVarName(arg.getInstanceId()) + ".equals(" + argumentValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"); } - return String.join("\n", argList); + return String.join("\n\t\t", argList); } private static String traceToAssert(Trace methodTrace) { @@ -167,34 +164,63 @@ private static void printTraceAsCode(TraceEvent event) { String postCallParameterAssertionLine = traceArgumentsToAssert(trace); if (methodCallLine != null && !methodCallLine.isEmpty()) { - System.out.println(methodCallLine); + System.out.println("\t\t" + methodCallLine); } if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - System.out.println(returnAssertionLine); + System.out.println("\t\t" + returnAssertionLine); } if (postCallParameterAssertionLine != null && !postCallParameterAssertionLine.isEmpty()) { - System.out.println(postCallParameterAssertionLine); + System.out.println("\t\t" + postCallParameterAssertionLine); } } public static void main(String[] args) throws IOException { TestTraceResults[] testTraceResultsList = readTraces(args[0]); for (TestTraceResults testTraceResults : testTraceResultsList) { + + var splitTestName = testTraceResults.Test.split("\\."); + + String packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); + String className = splitTestName[splitTestName.length - 2]; + String testName = splitTestName[splitTestName.length - 1]; + + if (!packageName.isEmpty()) { + System.out.println("package " + packageName + ";"); + System.out.println(); + } + + System.out.println("public class " + className + " {"); + + System.out.println("\t@Test"); + System.out.println("\tpublic static " + testName + "() {"); + Trace[] methodTraces = testTraceResults.Traces; List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); + TraceEvent[] entryTraceEvents = eventsSortedByTimeStamp.stream().filter(event -> event.What().equals("Entry")).toArray(TraceEvent[]::new); - /*for (TraceEvent event : eventsSortedByTimeStamp) { - System.out.println("[" + event.At() + "] " + event.What() + " of [" + event.About().getMethodSignature() + "]"); - }*/ + for (int i = 0; i < entryTraceEvents.length; i++) { + TraceEvent event = entryTraceEvents[i]; + printTraceAsCode(event); - for (TraceEvent event : eventsSortedByTimeStamp) { - if (event.What().equals("Entry")) { - printTraceAsCode(event); + if (i != entryTraceEvents.length - 1) { System.out.println(); } } + + System.out.println("\t}"); + + System.out.println("}"); + + System.out.println(); + + // The map of instance ids to variable indexes + mapOfInstancesToIndexes.clear(); + // The list of instance ids we already defined + listOfDefinedInstances.clear(); + // The currently free index for variables to define in our java source code + varIndex = 0; } } } \ No newline at end of file From 6a99e9fee87f7ef575d8f7b2ad3facfc23a6b5b9 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:21:12 +0100 Subject: [PATCH 042/244] Add logger --- .../maracas/gilesi/instrumentation/Agent.java | 6 ++- .../visitors/ConstructorAdvisor.java | 47 ++++++++++++++++--- .../visitors/MethodAdvisor.java | 35 ++++++++++++++ 3 files changed, 81 insertions(+), 7 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index de499573..27efd4c9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -11,6 +11,8 @@ import java.io.File; import java.io.IOException; import java.lang.instrument.Instrumentation; +import java.nio.file.Files; +import java.util.ArrayList; /* Our main agent class @@ -19,6 +21,7 @@ public class Agent { public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; public static long ProcessEntryTimeStamp = System.currentTimeMillis(); + public static ArrayList LOGGER = new ArrayList<>(); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); @@ -28,7 +31,7 @@ public static InstrumentationParameters parseInstrumentationparameters(File file /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults() { + public static void SaveTraceResults() throws IOException { File outputFile = new File("MethodTraces.json"); System.out.println("Saving trace results in progress..."); System.out.println("Output location: " + outputFile.getAbsolutePath()); @@ -43,6 +46,7 @@ public static void SaveTraceResults() { } System.out.println("Saving trace results in progress... Done!"); + Files.write(new File("MethodTraces.log").toPath(), LOGGER); } /* diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 0d736c63..54e653aa 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -22,7 +22,14 @@ public static Object enter( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + Agent.LOGGER.add("++ConstructorAdvisor::Entry"); + Agent.LOGGER.add(" StackTrace:"); + for (StackTraceElement s : stackTraceElements) { + String methodName = s.getClassName() + "." + s.getMethodName(); + Agent.LOGGER.add(" " + methodName); + } + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) // 3: ... @@ -36,6 +43,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 1)"); + Agent.LOGGER.add("--ConstructorAdvisor::Entry"); return null; } @@ -45,7 +54,7 @@ public static Object enter( // Serialize an object, and while doing so, we go into our entry/exit methods // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) @@ -58,7 +67,7 @@ public static Object enter( // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { @@ -66,6 +75,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 2)"); + Agent.LOGGER.add("--ConstructorAdvisor::Entry"); return null; } } @@ -76,16 +87,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Rejected Trace (Case 3)"); + Agent.LOGGER.add("--ConstructorAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Accepted Trace"); + Agent.LOGGER.add("--ConstructorAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... + Agent.LOGGER.add(" Rejected Trace (Case 4)"); + Agent.LOGGER.add("--ConstructorAdvisor::Entry"); return null; } @@ -98,7 +115,14 @@ public static void exit( @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + Agent.LOGGER.add("++ConstructorAdvisor::Exit"); + Agent.LOGGER.add(" StackTrace:"); + for (StackTraceElement s : stackTraceElements) { + String methodName = s.getClassName() + "." + s.getMethodName(); + Agent.LOGGER.add(" " + methodName); + } + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) // 3: ... @@ -112,6 +136,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 1)"); + Agent.LOGGER.add("--ConstructorAdvisor::Exit"); return; } @@ -121,7 +147,7 @@ public static void exit( // Serialize an object, and while doing so, we go into our entry/exit methods // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) @@ -134,7 +160,7 @@ public static void exit( // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { @@ -142,6 +168,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 2)"); + Agent.LOGGER.add("--ConstructorAdvisor::Exit"); return; } } @@ -152,6 +180,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Rejected Trace (Case 3)"); + Agent.LOGGER.add("--ConstructorAdvisor::Exit"); return; } @@ -159,9 +189,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); TraceCollector.addMethodTrace(trace); + Agent.LOGGER.add(" Accepted Trace"); + Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + return; } } // We never found any trace of the client, something is up... + Agent.LOGGER.add(" Rejected Trace (Case 4)"); + Agent.LOGGER.add("--ConstructorAdvisor::Exit"); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index edc53205..8fe396be 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -22,6 +22,13 @@ public static Object enter( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + Agent.LOGGER.add("++MethodAdvisor::Entry"); + Agent.LOGGER.add(" StackTrace:"); + for (StackTraceElement s : stackTraceElements) { + String methodName = s.getClassName() + "." + s.getMethodName(); + Agent.LOGGER.add(" " + methodName); + } + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) @@ -36,6 +43,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 1)"); + Agent.LOGGER.add("--MethodAdvisor::Entry"); return null; } @@ -66,6 +75,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 2)"); + Agent.LOGGER.add("--MethodAdvisor::Entry"); return null; } } @@ -76,16 +87,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Rejected Trace (Case 3)"); + Agent.LOGGER.add("--MethodAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Accepted Trace"); + Agent.LOGGER.add("--MethodAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... + Agent.LOGGER.add(" Rejected Trace (Case 4)"); + Agent.LOGGER.add("--MethodAdvisor::Entry"); return null; } @@ -99,6 +116,13 @@ public static void exit( @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + Agent.LOGGER.add("++MethodAdvisor::Exit"); + Agent.LOGGER.add(" StackTrace:"); + for (StackTraceElement s : stackTraceElements) { + String methodName = s.getClassName() + "." + s.getMethodName(); + Agent.LOGGER.add(" " + methodName); + } + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) @@ -113,6 +137,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 1)"); + Agent.LOGGER.add("--MethodAdvisor::Exit"); return; } @@ -143,6 +169,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { + Agent.LOGGER.add(" Rejected Trace (Case 2)"); + Agent.LOGGER.add("--MethodAdvisor::Exit"); return; } } @@ -153,6 +181,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + Agent.LOGGER.add(" Rejected Trace (Case 3)"); + Agent.LOGGER.add("--MethodAdvisor::Exit"); return; } @@ -160,9 +190,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); TraceCollector.addMethodTrace(trace); + Agent.LOGGER.add(" Accepted Trace"); + Agent.LOGGER.add("--MethodAdvisor::Exit"); + return; } } // We never found any trace of the client, something is up... + Agent.LOGGER.add(" Rejected Trace (Case 4)"); + Agent.LOGGER.add("--MethodAdvisor::Exit"); } } \ No newline at end of file From 6aa407b4d4ca03e3af7b769474c3d53060cae8e2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:21:23 +0100 Subject: [PATCH 043/244] Reenable descriptor matching --- .../gilesi/instrumentation/visitors/MethodInstrumentor.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index eebfed13..72442784 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -13,7 +13,7 @@ public class MethodInstrumentor { public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - ElementMatcher.Junction methodMatcher = named(instrumentationParameter.MethodName);//.and(ElementMatchers.hasDescriptor(instrumentationParameter.MethodDescriptor)); + ElementMatcher.Junction methodMatcher = named(instrumentationParameter.MethodName).and(ElementMatchers.hasDescriptor(instrumentationParameter.MethodDescriptor)); new AgentBuilder.Default() .type(named(instrumentationParameter.ClassName)) From b6676527086f8de6c4b00814254d999dd077fcda Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:23:05 +0100 Subject: [PATCH 044/244] Add lambda test --- .../com/github/maracas/gilesi/samples/samplelibrary/A.java | 4 ++++ .../maracas/gilesi/samples/samplelibrary/IDoSomething.java | 5 +++++ Samples/samplelibrary/src/test/java/ATest.java | 2 ++ 3 files changed, 11 insertions(+) create mode 100644 Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java index 3bbae35a..4f9003a5 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java @@ -14,4 +14,8 @@ public int foo(int i) { return j + (i * 2); } + + public void CallBack(IDoSomething doSomething) { + doSomething.Do(); + } } diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java new file mode 100644 index 00000000..ee407447 --- /dev/null +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java @@ -0,0 +1,5 @@ +package com.github.maracas.gilesi.samples.samplelibrary; + +public interface IDoSomething { + void Do(); +} diff --git a/Samples/samplelibrary/src/test/java/ATest.java b/Samples/samplelibrary/src/test/java/ATest.java index 6ae67154..f7cef7a7 100644 --- a/Samples/samplelibrary/src/test/java/ATest.java +++ b/Samples/samplelibrary/src/test/java/ATest.java @@ -16,5 +16,7 @@ public void TestFooIsLifeNice() { A a = new A(42); int result = a.foo(1); assertEquals(result, 69); + + a.CallBack(this::TestFoo); } } From 399ef43f37c3fe9d31990eb1d8d9048cba0795b3 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:23:22 +0100 Subject: [PATCH 045/244] make lib code also call something --- .../java/com/github/maracas/gilesi/samples/samplelibrary/A.java | 1 + 1 file changed, 1 insertion(+) diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java index 4f9003a5..4c6726e9 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java @@ -17,5 +17,6 @@ public int foo(int i) { public void CallBack(IDoSomething doSomething) { doSomething.Do(); + foo(2); } } From 36b822c805d99a8c5bb073ce3a71a4fcca8a218f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:25:32 +0100 Subject: [PATCH 046/244] fix: exception --- .../github/maracas/gilesi/instrumentation/Agent.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 27efd4c9..085311e0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -31,7 +31,7 @@ public static InstrumentationParameters parseInstrumentationparameters(File file /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults() throws IOException { + public static void SaveTraceResults() { File outputFile = new File("MethodTraces.json"); System.out.println("Saving trace results in progress..."); System.out.println("Output location: " + outputFile.getAbsolutePath()); @@ -45,8 +45,13 @@ public static void SaveTraceResults() throws IOException { e.printStackTrace(); } - System.out.println("Saving trace results in progress... Done!"); - Files.write(new File("MethodTraces.log").toPath(), LOGGER); + try { + System.out.println("Saving trace results in progress... Done!"); + Files.write(new File("MethodTraces.log").toPath(), LOGGER); + } catch (Exception e) { + System.err.println("ERROR"); + e.printStackTrace(); + } } /* From 1b601b03fdeb3b6677cacac05ffaf49b817f4a4c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:30:02 +0100 Subject: [PATCH 047/244] Add missing test case --- Samples/sampleclient/src/test/java/FooTest.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/sampleclient/src/test/java/FooTest.java index ae9dfdab..ac8ec93a 100644 --- a/Samples/sampleclient/src/test/java/FooTest.java +++ b/Samples/sampleclient/src/test/java/FooTest.java @@ -1,3 +1,4 @@ +import com.github.maracas.gilesi.samples.samplelibrary.A; import com.github.maracas.gilesi.samples.samplelibrary.Foo; import com.github.maracas.gilesi.samples.samplelibrary.Foo2; import org.junit.jupiter.api.Test; @@ -127,4 +128,20 @@ public void mainTest() { assertEquals(var18, "the life the universe and everything"); assertEquals(var19, 42); } + + @Test + public void TestFoo() { + A a = new A(5); + int result = a.foo(1); + assertEquals(result, 7); + } + + @Test + public void TestFooIsLifeNice() { + A a = new A(42); + int result = a.foo(1); + assertEquals(result, 69); + + a.CallBack(this::TestFoo); + } } \ No newline at end of file From fd78ed1c40aef7a177d32596003d2d7635eaf4fe Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:33:32 +0100 Subject: [PATCH 048/244] fix: logging ids --- .../maracas/gilesi/instrumentation/Agent.java | 1 + .../visitors/ConstructorAdvisor.java | 56 ++++++++++--------- .../visitors/MethodAdvisor.java | 56 ++++++++++--------- 3 files changed, 61 insertions(+), 52 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 085311e0..dcf755bf 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -22,6 +22,7 @@ public class Agent { public static String[] ClientMethods = new String[0]; public static long ProcessEntryTimeStamp = System.currentTimeMillis(); public static ArrayList LOGGER = new ArrayList<>(); + public static int LOGGERINSTANCE = 0; public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 54e653aa..52af80ac 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -20,13 +20,15 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + int loggerInstance = Agent.LOGGERINSTANCE++; + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add("++ConstructorAdvisor::Entry"); - Agent.LOGGER.add(" StackTrace:"); + Agent.LOGGER.add(loggerInstance + ":++ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(" " + methodName); + Agent.LOGGER.add(loggerInstance + ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) @@ -43,8 +45,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 1)"); - Agent.LOGGER.add("--ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); return null; } @@ -75,8 +77,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 2)"); - Agent.LOGGER.add("--ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); return null; } } @@ -87,22 +89,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Rejected Trace (Case 3)"); - Agent.LOGGER.add("--ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Accepted Trace"); - Agent.LOGGER.add("--ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(" Rejected Trace (Case 4)"); - Agent.LOGGER.add("--ConstructorAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); return null; } @@ -113,13 +115,15 @@ public static void exit( @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + int loggerInstance = Agent.LOGGERINSTANCE++; + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add("++ConstructorAdvisor::Exit"); - Agent.LOGGER.add(" StackTrace:"); + Agent.LOGGER.add(loggerInstance + ":++ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(" " + methodName); + Agent.LOGGER.add(loggerInstance + ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) @@ -136,8 +140,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 1)"); - Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); return; } @@ -168,8 +172,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 2)"); - Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); return; } } @@ -180,8 +184,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Rejected Trace (Case 3)"); - Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); return; } @@ -189,14 +193,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); TraceCollector.addMethodTrace(trace); - Agent.LOGGER.add(" Accepted Trace"); - Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); return; } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(" Rejected Trace (Case 4)"); - Agent.LOGGER.add("--ConstructorAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); + Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 8fe396be..451dc38e 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -20,13 +20,15 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + int loggerInstance = Agent.LOGGERINSTANCE++; + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add("++MethodAdvisor::Entry"); - Agent.LOGGER.add(" StackTrace:"); + Agent.LOGGER.add(loggerInstance + ":++MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(" " + methodName); + Agent.LOGGER.add(loggerInstance + ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) @@ -43,8 +45,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 1)"); - Agent.LOGGER.add("--MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); return null; } @@ -75,8 +77,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 2)"); - Agent.LOGGER.add("--MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); return null; } } @@ -87,22 +89,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Rejected Trace (Case 3)"); - Agent.LOGGER.add("--MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Accepted Trace"); - Agent.LOGGER.add("--MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(" Rejected Trace (Case 4)"); - Agent.LOGGER.add("--MethodAdvisor::Entry"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); return null; } @@ -114,13 +116,15 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { + int loggerInstance = Agent.LOGGERINSTANCE++; + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add("++MethodAdvisor::Exit"); - Agent.LOGGER.add(" StackTrace:"); + Agent.LOGGER.add(loggerInstance + ":++MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(" " + methodName); + Agent.LOGGER.add(loggerInstance + ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) @@ -137,8 +141,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 1)"); - Agent.LOGGER.add("--MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); return; } @@ -169,8 +173,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(" Rejected Trace (Case 2)"); - Agent.LOGGER.add("--MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); return; } } @@ -181,8 +185,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(" Rejected Trace (Case 3)"); - Agent.LOGGER.add("--MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); return; } @@ -190,14 +194,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); TraceCollector.addMethodTrace(trace); - Agent.LOGGER.add(" Accepted Trace"); - Agent.LOGGER.add("--MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); return; } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(" Rejected Trace (Case 4)"); - Agent.LOGGER.add("--MethodAdvisor::Exit"); + Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); + Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); } } \ No newline at end of file From c30740a18002359fe69d329bd5a86bfa1c37cca1 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 14:36:49 +0100 Subject: [PATCH 049/244] fix: test order --- Samples/sampleclient/src/test/java/FooTest.java | 3 ++- Samples/samplelibrary/src/test/java/ATest.java | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/sampleclient/src/test/java/FooTest.java index ac8ec93a..383ac573 100644 --- a/Samples/sampleclient/src/test/java/FooTest.java +++ b/Samples/sampleclient/src/test/java/FooTest.java @@ -140,8 +140,9 @@ public void TestFoo() { public void TestFooIsLifeNice() { A a = new A(42); int result = a.foo(1); - assertEquals(result, 69); a.CallBack(this::TestFoo); + + assertEquals(result, 69); } } \ No newline at end of file diff --git a/Samples/samplelibrary/src/test/java/ATest.java b/Samples/samplelibrary/src/test/java/ATest.java index f7cef7a7..f524f813 100644 --- a/Samples/samplelibrary/src/test/java/ATest.java +++ b/Samples/samplelibrary/src/test/java/ATest.java @@ -15,8 +15,9 @@ public void TestFoo() { public void TestFooIsLifeNice() { A a = new A(42); int result = a.foo(1); - assertEquals(result, 69); a.CallBack(this::TestFoo); + + assertEquals(result, 69); } } From a6e4275993c8d3b4ed89de493ebd76687cccbecf Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 15:49:27 +0100 Subject: [PATCH 050/244] feat: improve code gen with assertEquals --- .../github/maracas/gilesi/traceview/Main.java | 51 ++++++++++++------- 1 file changed, 32 insertions(+), 19 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 3848127a..2910f154 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -28,7 +28,7 @@ private static String getInstanceVarName(int instanceId) { mapOfInstancesToIndexes.put(instanceId, i); } - return "var" + i; + return "var%d".formatted(i); } private static String serializableDataToCode(TraceData arg) { @@ -39,13 +39,13 @@ private static String serializableDataToCode(TraceData arg) { } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { return getInstanceVarName(arg.getInstanceId()); } else { - return "InstanceId{" + arg.getInstanceId() + "}"; + return "InstanceId{%d}".formatted(arg.getInstanceId()); } } private static String getCleanedType(String FQN) { if (FQN.startsWith("[L") && FQN.endsWith(";")) { - FQN = FQN.substring(2, FQN.length() - 1) + "[]"; + FQN = "%s[]".formatted(FQN.substring(2, FQN.length() - 1)); } return FQN; } @@ -59,7 +59,7 @@ private static String serializableDataToJava(TraceData serializableData) { !FQN.equals("java.lang.Double") && !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long")) { - valueToBeEqualTo = "new ObjectMapper().readValue(\"" + StringEscapeUtils.escapeJava(serializableData.getDataAsJson()) + "\", " + FQN + ".class)"; + valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); } return valueToBeEqualTo; } @@ -82,7 +82,7 @@ private static String traceToCode(Trace methodTrace) { boolean isInstanceCall = methodTrace.getInstance() != null && !methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); if (isConstructor) { - cleanedMethodName = "new " + cleanedMethodName; + cleanedMethodName = "new %s".formatted(cleanedMethodName); } else if (isInstanceCall) { String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; cleanedMethodName = getInstanceVarName(methodTrace.getInstance().getInstanceId()) + "." + methodNameOnly; @@ -105,20 +105,25 @@ private static String traceToCode(Trace methodTrace) { List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); - String argumentDeclaration = getReturnStatementAsCode(arg) + " = " + argumentValueAsCode; + String argumentDeclaration = "%s = %s".formatted(getReturnStatementAsCode(arg), argumentValueAsCode); argList.add(getInstanceVarName(arg.getInstanceId())); - cleanedMethodName = argumentDeclaration + ";\n\t\t" + cleanedMethodName; + cleanedMethodName = ("%s;\n" + + "\t\t%s").formatted(argumentDeclaration, cleanedMethodName); } - return cleanedMethodName + "(" + String.join(",", argList) + ");"; + return "%s(%s);".formatted(cleanedMethodName, String.join(",", argList)); } private static String traceArgumentsToAssert(Trace methodTrace) { List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPostCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); - argList.add("assert " + getInstanceVarName(arg.getInstanceId()) + ".equals(" + argumentValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"); + if (argumentValueAsCode.endsWith("[].class)")) { + argList.add("assertArrayEquals(%s, %s);".formatted(getInstanceVarName(arg.getInstanceId()), argumentValueAsCode)); + } else { + argList.add("assertEquals(%s, %s);".formatted(getInstanceVarName(arg.getInstanceId()), argumentValueAsCode)); + } } return String.join("\n\t\t", argList); @@ -134,7 +139,11 @@ private static String traceToAssert(Trace methodTrace) { } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); - return "assert " + getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()) + ".equals(" + returnValueAsCode + ") : \"Value is not equal to recorded value from Trace!\";"; + if (returnValueAsCode.endsWith("[].class)")) { + return "assertArrayEquals(%s, %s);".formatted(getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()), returnValueAsCode); + } else { + return "assertEquals(%s, %s);".formatted(getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()), returnValueAsCode); + } } return null; @@ -164,15 +173,15 @@ private static void printTraceAsCode(TraceEvent event) { String postCallParameterAssertionLine = traceArgumentsToAssert(trace); if (methodCallLine != null && !methodCallLine.isEmpty()) { - System.out.println("\t\t" + methodCallLine); + System.out.printf("\t\t%s%n", methodCallLine); } if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - System.out.println("\t\t" + returnAssertionLine); + System.out.printf("\t\t%s%n", returnAssertionLine); } if (postCallParameterAssertionLine != null && !postCallParameterAssertionLine.isEmpty()) { - System.out.println("\t\t" + postCallParameterAssertionLine); + System.out.printf("\t\t%s%n", postCallParameterAssertionLine); } } @@ -187,14 +196,20 @@ public static void main(String[] args) throws IOException { String testName = splitTestName[splitTestName.length - 1]; if (!packageName.isEmpty()) { - System.out.println("package " + packageName + ";"); + System.out.printf("package %s;%n", packageName); System.out.println(); } - System.out.println("public class " + className + " {"); - + System.out.println("import com.fasterxml.jackson.core.JsonProcessingException;"); + System.out.println("import com.fasterxml.jackson.databind.ObjectMapper;"); + System.out.println("import org.junit.jupiter.api.Test;"); + System.out.println(); + System.out.println("import static org.junit.jupiter.api.Assertions.assertEquals;"); + System.out.println("import static org.junit.jupiter.api.Assertions.assertArrayEquals;"); + System.out.println(); + System.out.printf("public class %s {%n", className); System.out.println("\t@Test"); - System.out.println("\tpublic static " + testName + "() {"); + System.out.printf("\tpublic void %s() throws JsonProcessingException {%n", testName); Trace[] methodTraces = testTraceResults.Traces; List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); @@ -210,9 +225,7 @@ public static void main(String[] args) throws IOException { } System.out.println("\t}"); - System.out.println("}"); - System.out.println(); // The map of instance ids to variable indexes From 94fc25e485f02a62f651ebe03347ec6dab166171 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 15:58:56 +0100 Subject: [PATCH 051/244] feat: fix order of values for assert Equals --- .../java/com/github/maracas/gilesi/traceview/Main.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 2910f154..4171a2df 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -120,9 +120,9 @@ private static String traceArgumentsToAssert(Trace methodTrace) { for (TraceData arg : methodTrace.getPostCallArguments()) { String argumentValueAsCode = serializableDataToCode(arg); if (argumentValueAsCode.endsWith("[].class)")) { - argList.add("assertArrayEquals(%s, %s);".formatted(getInstanceVarName(arg.getInstanceId()), argumentValueAsCode)); + argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); } else { - argList.add("assertEquals(%s, %s);".formatted(getInstanceVarName(arg.getInstanceId()), argumentValueAsCode)); + argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); } } @@ -140,9 +140,9 @@ private static String traceToAssert(Trace methodTrace) { // We return a value that we managed to serialize String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); if (returnValueAsCode.endsWith("[].class)")) { - return "assertArrayEquals(%s, %s);".formatted(getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()), returnValueAsCode); + return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); } else { - return "assertEquals(%s, %s);".formatted(getInstanceVarName(methodTrace.getReturnedValue().getInstanceId()), returnValueAsCode); + return "assertEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); } } From 1408eb755712282329db742cdc12015445935ee5 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 20 Feb 2024 16:14:27 +0100 Subject: [PATCH 052/244] Code cleanup --- .../github/maracas/gilesi/confgen/Main.java | 7 ++-- .../gilesi/confgen/RoseauDescriptor.java | 32 +++++++------------ .../maracas/gilesi/instrumentation/Agent.java | 8 ++--- .../gilesi/instrumentation/TraceFactory.java | 6 ++-- .../gilesi/samples/sampleclient/Main2.java | 6 ++-- Samples/sampleclient/src/test/java/CTest.java | 4 +-- .../sampleclient/src/test/java/FooTest.java | 14 +++----- .../gilesi/samples/samplelibrary/A.java | 2 +- .../gilesi/samples/samplelibrary/Foo.java | 2 +- .../gilesi/samples/samplelibrary/Foo2.java | 2 +- .../samplelibrary/src/test/java/ATest.java | 2 +- .../github/maracas/gilesi/traceview/Main.java | 6 ++-- 12 files changed, 39 insertions(+), 52 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 5661ecb5..2840736d 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -5,18 +5,21 @@ import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.maracas.roseau.api.SpoonAPIExtractor; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; import com.github.maracas.roseau.api.model.ConstructorDecl; import com.github.maracas.roseau.api.model.MethodDecl; -import com.github.maracas.roseau.api.SpoonAPIExtractor; import spoon.Launcher; import spoon.reflect.CtModel; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.List; public class Main { private static String getClassNameFromFQN(String fullyQualifiedName) { diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java index c2ee31a8..4ed308c7 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java @@ -35,26 +35,18 @@ public static String getDescriptor(ITypeReference iTypeReference) throws Excepti } case PrimitiveTypeReference primitiveTypeReference -> { String name = primitiveTypeReference.getQualifiedName(); - if (name.equals("int")) { - return "I"; - } else if (name.equals("void")) { - return "V"; - } else if (name.equals("boolean")) { - return "Z"; - } else if (name.equals("byte")) { - return "B"; - } else if (name.equals("char")) { - return "C"; - } else if (name.equals("short")) { - return "S"; - } else if (name.equals("double")) { - return "D"; - } else if (name.equals("float")) { - return "F"; - } else if (name.equals("long")) { - return "J"; - } - throw new Exception("Unsupported primitive type: " + name); + return switch (name) { + case "int" -> "I"; + case "void" -> "V"; + case "boolean" -> "Z"; + case "byte" -> "B"; + case "char" -> "C"; + case "short" -> "S"; + case "double" -> "D"; + case "float" -> "F"; + case "long" -> "J"; + default -> throw new Exception("Unsupported primitive type: " + name); + }; } case TypeParameterReference ignored -> { //String name = typeParameterReference.getQualifiedName(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index dcf755bf..86febebc 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -20,8 +20,8 @@ public class Agent { public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; - public static long ProcessEntryTimeStamp = System.currentTimeMillis(); - public static ArrayList LOGGER = new ArrayList<>(); + public static final long ProcessEntryTimeStamp = System.currentTimeMillis(); + public static final ArrayList LOGGER = new ArrayList<>(); public static int LOGGERINSTANCE = 0; public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { @@ -74,7 +74,7 @@ private static void installAgent(String arg, Instrumentation inst) { // Get the parameters File configurationFile = new File(arg); if (!configurationFile.exists()) { - System.err.println("ERROR: the passed in configuration file (" + arg + ") does not exist or could not be found!"); + System.err.printf("ERROR: the passed in configuration file (%s) does not exist or could not be found!%n", arg); return; } @@ -83,7 +83,7 @@ private static void installAgent(String arg, Instrumentation inst) { try { instrumentationParameters = parseInstrumentationparameters(configurationFile); } catch (IOException ioException) { - System.err.println("ERROR: Could not parse instrumentation configuration file (" + arg + ")!"); + System.err.printf("ERROR: Could not parse instrumentation configuration file (%s)!%n", arg); System.err.println(ioException.getMessage()); ioException.printStackTrace(); return; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 3b275856..1db51f8c 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -69,9 +69,8 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); List preCallArguments = getArgumentsAsSerializableData(arguments); - long timeStampEntry = entryMarker; - return new PartialTrace(methodSignature, serializableInstance, preCallArguments, timeStampEntry); + return new PartialTrace(methodSignature, serializableInstance, preCallArguments, entryMarker); } /** @@ -101,7 +100,6 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object List postCallArguments = getArgumentsAsSerializableData(arguments); TraceData returnedValue = TraceDataFactory.valueOf(returned); long timeStampEntry = originatingTrace.getTimeStampEntry(); - long timeStampExit = exitMarker; TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).skip(3).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); @@ -116,6 +114,6 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); } - return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, timeStampExit, exceptionThrown, stackTrace); + return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, exitMarker, exceptionThrown, stackTrace); } } diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java b/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java index 036bb3d0..58da04d6 100644 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java +++ b/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java @@ -69,8 +69,7 @@ public static void main(String[] args) { System.out.println(); - List peopleList = new ArrayList<>(); - peopleList.addAll(Arrays.asList(people)); + List peopleList = new ArrayList<>(Arrays.asList(people)); System.out.println("People List Right now:"); for (String pe : peopleList) { @@ -151,8 +150,7 @@ public static void main(String[] args) { System.out.println(); - peopleList = new ArrayList<>(); - peopleList.addAll(Arrays.asList(people)); + peopleList = new ArrayList<>(Arrays.asList(people)); System.out.println("People List Right now:"); for (String pe : peopleList) { diff --git a/Samples/sampleclient/src/test/java/CTest.java b/Samples/sampleclient/src/test/java/CTest.java index 6cbd048f..9addc7fc 100644 --- a/Samples/sampleclient/src/test/java/CTest.java +++ b/Samples/sampleclient/src/test/java/CTest.java @@ -1,5 +1,5 @@ -import com.github.maracas.gilesi.samples.samplelibrary.A2; import com.github.maracas.gilesi.samples.sampleclient.C1; +import com.github.maracas.gilesi.samples.samplelibrary.A2; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -8,7 +8,7 @@ public class CTest { @Test public void Test() { C1 c1 = new C1(); - int s = c1.Do(3); + int s = C1.Do(3); assertEquals(s, 21); } diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/sampleclient/src/test/java/FooTest.java index 383ac573..a3f52487 100644 --- a/Samples/sampleclient/src/test/java/FooTest.java +++ b/Samples/sampleclient/src/test/java/FooTest.java @@ -57,10 +57,8 @@ public void mainTest() { assertEquals(var14, "Hello [Toto, Tata, Titi, JP, PA, JR]"); assertArrayEquals(var15, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); - java.util.ArrayList var17 = new ArrayList(); - var17.addAll(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); - java.util.ArrayList var171 = new ArrayList(); - var171.addAll(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); + ArrayList var17 = new ArrayList(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); + ArrayList var171 = new ArrayList(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); java.lang.String var16 = Foo.HelloEveryone2(var17); assertEquals(var16, "Hello TotoTataTitiJPPAJR"); assertEquals(var17, var171); @@ -115,10 +113,8 @@ public void mainTest() { assertEquals(var26, "Hello [Toto, Tata, Titi, JP, PA, JR]"); assertArrayEquals(var27, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); - java.util.ArrayList var29 = new ArrayList(); - java.util.ArrayList var291 = new ArrayList(); - var29.addAll(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); - var291.addAll(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); + ArrayList var29 = new ArrayList(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); + ArrayList var291 = new ArrayList(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); java.lang.String var28 = Foo2.njrhbgtujhu(var29); assertEquals(var28, "Hello TotoTataTitiJPPAJR"); assertEquals(var29, var291); @@ -128,7 +124,7 @@ public void mainTest() { assertEquals(var18, "the life the universe and everything"); assertEquals(var19, 42); } - + @Test public void TestFoo() { A a = new A(5); diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java index 4c6726e9..85ea31e6 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.samples.samplelibrary; public class A { - private int j = 0; + private int j; public A(int j) { this.j = j; diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java index 500b94ec..6ebdd838 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java @@ -24,7 +24,7 @@ public static String HelloEveryone(String[] familly) { } public static String HelloEveryone2(Collection familly) { - String fam = familly.stream().collect(Collectors.joining()); + String fam = String.join("", familly); familly.clear(); familly.add("NewPersonA"); familly.add("NewPersonB"); diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java index 9d833c39..32e2b8b3 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java @@ -24,7 +24,7 @@ public static String jhgbjtjbh(String[] familly) { } public static String njrhbgtujhu(Collection familly) { - String fam = familly.stream().collect(Collectors.joining()); + String fam = String.join("", familly); familly.clear(); familly.add("NewPersonA"); familly.add("NewPersonB"); diff --git a/Samples/samplelibrary/src/test/java/ATest.java b/Samples/samplelibrary/src/test/java/ATest.java index f524f813..74ceef94 100644 --- a/Samples/samplelibrary/src/test/java/ATest.java +++ b/Samples/samplelibrary/src/test/java/ATest.java @@ -17,7 +17,7 @@ public void TestFooIsLifeNice() { int result = a.foo(1); a.CallBack(this::TestFoo); - + assertEquals(result, 69); } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 4171a2df..6a82fdf1 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -12,9 +12,9 @@ public class Main { // The map of instance ids to variable indexes - private static final HashMap mapOfInstancesToIndexes = new HashMap(); + private static final HashMap mapOfInstancesToIndexes = new HashMap<>(); // The list of instance ids we already defined - private static final List listOfDefinedInstances = new ArrayList(); + private static final List listOfDefinedInstances = new ArrayList<>(); // The currently free index for variables to define in our java source code private static int varIndex = 0; @@ -180,7 +180,7 @@ private static void printTraceAsCode(TraceEvent event) { System.out.printf("\t\t%s%n", returnAssertionLine); } - if (postCallParameterAssertionLine != null && !postCallParameterAssertionLine.isEmpty()) { + if (!postCallParameterAssertionLine.isEmpty()) { System.out.printf("\t\t%s%n", postCallParameterAssertionLine); } } From a286443b67a32dad83e765f8cc66fb28e3c0b070 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 09:27:15 +0100 Subject: [PATCH 053/244] Create dedicated logging class --- .../maracas/gilesi/instrumentation/Agent.java | 10 ---- .../gilesi/instrumentation/Logger.java | 32 +++++++++++ .../visitors/ConstructorAdvisor.java | 57 ++++++++++--------- .../visitors/MethodAdvisor.java | 57 ++++++++++--------- 4 files changed, 90 insertions(+), 66 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 86febebc..84b47065 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -21,8 +21,6 @@ public class Agent { public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; public static final long ProcessEntryTimeStamp = System.currentTimeMillis(); - public static final ArrayList LOGGER = new ArrayList<>(); - public static int LOGGERINSTANCE = 0; public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); @@ -45,14 +43,6 @@ public static void SaveTraceResults() { System.err.println("ERROR"); e.printStackTrace(); } - - try { - System.out.println("Saving trace results in progress... Done!"); - Files.write(new File("MethodTraces.log").toPath(), LOGGER); - } catch (Exception e) { - System.err.println("ERROR"); - e.printStackTrace(); - } } /* diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java new file mode 100644 index 00000000..52c1e1e8 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java @@ -0,0 +1,32 @@ +package com.github.maracas.gilesi.instrumentation; + +import java.io.File; +import java.nio.file.Files; +import java.util.ArrayList; + +public class Logger { + private static final ArrayList LOGGER = new ArrayList<>(); + private static int LOGGERINSTANCE = 0; + + public static void SaveLogResults() { + try { + Files.write(new File("gilesi.instrumentation.log").toPath(), LOGGER); + } catch (Exception e) { + System.err.println("ERROR while saving logs"); + e.printStackTrace(); + } + } + + static void Logger() { + // Add a shutdown hook to save all logs at exit + Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); + } + + public static int GetInstance() { + return LOGGERINSTANCE++; + } + + public static void Log(int loggerInstance, String log) { + LOGGER.add(String.format("%d: %s", loggerInstance, log)); + } +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 52af80ac..86d2659f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -1,6 +1,7 @@ package com.github.maracas.gilesi.instrumentation.visitors; import com.github.maracas.gilesi.instrumentation.Agent; +import com.github.maracas.gilesi.instrumentation.Logger; import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.TraceFactory; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; @@ -20,15 +21,15 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - int loggerInstance = Agent.LOGGERINSTANCE++; + int loggerInstance = Logger.GetInstance(); StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add(loggerInstance + ":++ConstructorAdvisor::Entry"); - Agent.LOGGER.add(loggerInstance + ": StackTrace:"); + Logger.Log(loggerInstance, ":++ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(loggerInstance + ": " + methodName); + Logger.Log(loggerInstance, ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) @@ -45,8 +46,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); return null; } @@ -77,8 +78,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); return null; } } @@ -89,22 +90,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": Accepted Trace"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); return null; } @@ -115,15 +116,15 @@ public static void exit( @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { - int loggerInstance = Agent.LOGGERINSTANCE++; + int loggerInstance = Logger.GetInstance(); StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add(loggerInstance + ":++ConstructorAdvisor::Exit"); - Agent.LOGGER.add(loggerInstance + ": StackTrace:"); + Logger.Log(loggerInstance, ":++ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(loggerInstance + ": " + methodName); + Logger.Log(loggerInstance, ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) @@ -140,8 +141,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); return; } @@ -172,8 +173,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); return; } } @@ -184,8 +185,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); return; } @@ -193,14 +194,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); TraceCollector.addMethodTrace(trace); - Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": Accepted Trace"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); return; } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); - Agent.LOGGER.add(loggerInstance + ":--ConstructorAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 451dc38e..6bc99137 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,6 +1,7 @@ package com.github.maracas.gilesi.instrumentation.visitors; import com.github.maracas.gilesi.instrumentation.Agent; +import com.github.maracas.gilesi.instrumentation.Logger; import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.TraceFactory; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; @@ -20,15 +21,15 @@ public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - int loggerInstance = Agent.LOGGERINSTANCE++; + int loggerInstance = Logger.GetInstance(); StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add(loggerInstance + ":++MethodAdvisor::Entry"); - Agent.LOGGER.add(loggerInstance + ": StackTrace:"); + Logger.Log(loggerInstance, ":++MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(loggerInstance + ": " + methodName); + Logger.Log(loggerInstance, ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) @@ -45,8 +46,8 @@ public static Object enter( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); return null; } @@ -77,8 +78,8 @@ public static Object enter( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); return null; } } @@ -89,22 +90,22 @@ public static Object enter( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); return null; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": Accepted Trace"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); return TraceFactory.getPartialMethodTrace(origin, arguments, instance); } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Entry"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); return null; } @@ -116,15 +117,15 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { - int loggerInstance = Agent.LOGGERINSTANCE++; + int loggerInstance = Logger.GetInstance(); StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - Agent.LOGGER.add(loggerInstance + ":++MethodAdvisor::Exit"); - Agent.LOGGER.add(loggerInstance + ": StackTrace:"); + Logger.Log(loggerInstance, ":++MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": StackTrace:"); for (StackTraceElement s : stackTraceElements) { String methodName = s.getClassName() + "." + s.getMethodName(); - Agent.LOGGER.add(loggerInstance + ": " + methodName); + Logger.Log(loggerInstance, ": " + methodName); } // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) @@ -141,8 +142,8 @@ public static void exit( // so we want to also check if we are not a caller ourselves as well if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 1)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); return; } @@ -173,8 +174,8 @@ public static void exit( String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 2)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); return; } } @@ -185,8 +186,8 @@ public static void exit( String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 3)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); return; } @@ -194,14 +195,14 @@ public static void exit( if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); TraceCollector.addMethodTrace(trace); - Agent.LOGGER.add(loggerInstance + ": Accepted Trace"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": Accepted Trace"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); return; } } // We never found any trace of the client, something is up... - Agent.LOGGER.add(loggerInstance + ": Rejected Trace (Case 4)"); - Agent.LOGGER.add(loggerInstance + ":--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); } } \ No newline at end of file From 1ccdf7b0b8ac45ce616a8ad441dea0aa6674b79a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 09:45:52 +0100 Subject: [PATCH 054/244] fix: logger saving routine not being executed --- .../java/com/github/maracas/gilesi/instrumentation/Logger.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java index 52c1e1e8..e5bf1211 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java @@ -17,7 +17,7 @@ public static void SaveLogResults() { } } - static void Logger() { + static { // Add a shutdown hook to save all logs at exit Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); } From 9ff7309f77fbcf4d9c38c26ea37b735b4ae373d1 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 09:46:05 +0100 Subject: [PATCH 055/244] fix: refactor test detection --- .../github/maracas/gilesi/confgen/Main.java | 25 ------------ .../models/InstrumentationParameters.java | 1 - .../maracas/gilesi/instrumentation/Agent.java | 8 ---- .../instrumentation/TraceCollector.java | 38 ++++++------------- .../gilesi/instrumentation/TraceFactory.java | 3 +- .../models/InstrumentationParameters.java | 1 - .../visitors/ConstructorAdvisor.java | 16 +++++++- .../visitors/MethodAdvisor.java | 16 +++++++- .../instrumentation/visitors/TestAdvisor.java | 20 ---------- .../visitors/TestInstrumentor.java | 30 --------------- 10 files changed, 40 insertions(+), 118 deletions(-) delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 2840736d..93a0a9a0 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -55,15 +55,6 @@ private static void addToInstrumentationObject(InstrumentationParameters instrum instrumentationParameters.MethodsToInstrument.add(instrumentationParameter); } - private static void addToInstrumentationObjectTest(InstrumentationParameters instrumentationParameters, String className, String methodName) { - InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); - instrumentationParameter.ClassName = className; - instrumentationParameter.MethodName = methodName; - instrumentationParameter.MethodDescriptor = null; - - instrumentationParameters.TestsToInstrument.add(instrumentationParameter); - } - public static void main(String[] args) throws Exception { String apiReportOutputLocation = args[0]; Path apiReportOutputPath = Path.of(apiReportOutputLocation); @@ -79,7 +70,6 @@ public static void main(String[] args) throws Exception { InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.MethodsToInstrument = new ArrayList<>(); - instrumentationParameters.TestsToInstrument = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); @@ -113,25 +103,10 @@ public static void main(String[] args) throws Exception { System.out.println("Processing Test Project..."); - List testMethods = new ArrayList<>(); - Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(args[2]), CodeType.ALL); CtModel clientModel = clientLauncher.buildModel(); - clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() - .forEach(method -> method.getAnnotations().stream() - .filter(annotation -> annotation.getName().contains("Test")) - .map(annotation -> type.getQualifiedName() + "." + method.getSignature()) - .forEach(testMethods::add)))); - - for (String testMethod : testMethods) { - String className = getClassNameFromFQN(testMethod); - String methodName = getMethodNameFromFQN(testMethod); - - addToInstrumentationObjectTest(instrumentationParameters, className, methodName); - } - System.out.println("Processing Client Project..."); clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 57009bd2..7a941780 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -4,7 +4,6 @@ public class InstrumentationParameters { public List MethodsToInstrument; - public List TestsToInstrument; public List LibraryMethods; public List ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 84b47065..ac3b7a48 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -5,14 +5,11 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; -import com.github.maracas.gilesi.instrumentation.visitors.TestInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; import java.io.IOException; import java.lang.instrument.Instrumentation; -import java.nio.file.Files; -import java.util.ArrayList; /* Our main agent class @@ -87,11 +84,6 @@ private static void installAgent(String arg, Instrumentation inst) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } - // Instrument every test - for (InstrumentationParameter instrumentationParameter : instrumentationParameters.TestsToInstrument) { - TestInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); - } - // Then add a shutdown hook to save all method execution traces at exit Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index ee9f13e4..1006c200 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -9,36 +9,20 @@ public class TraceCollector { // Storage for traces collected so far private static final ArrayList TRACES = new ArrayList<>(); - private static TestTraceResults CURRENT_TRACES = null; - public static void addMethodTrace(Trace trace) { - if (CURRENT_TRACES == null) { - return; + public static void addMethodTrace(String currentTestMethod, Trace trace) { + for (TestTraceResults testTraceResults : TRACES) { + if (testTraceResults.Test.equals(currentTestMethod)) { + testTraceResults.Traces.add(trace); + return; + } } - CURRENT_TRACES.Traces.add(trace); - } - - public static String getCurrentKey() { - if (CURRENT_TRACES == null) { - return ""; - } - - return CURRENT_TRACES.Test; - } - - public static void setCurrentKey(String currentKey) { - if (CURRENT_TRACES != null) { - TRACES.add(CURRENT_TRACES); - } - - if (currentKey == null || currentKey.isEmpty()) { - CURRENT_TRACES = null; - } else { - CURRENT_TRACES = new TestTraceResults(); - CURRENT_TRACES.Test = currentKey; - CURRENT_TRACES.Traces = new ArrayList<>(); - } + TestTraceResults testTraceResults = new TestTraceResults(); + testTraceResults.Test = currentTestMethod; + testTraceResults.Traces = new ArrayList<>(); + testTraceResults.Traces.add(trace); + TRACES.add(testTraceResults); } /** diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 1db51f8c..cdbbc86d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -90,7 +90,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg * @param arguments The originating trace argument list on entry * @param returned The data returned by the originating trace */ - public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace) { + public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String currentTestMethod) { // Need to fetch this asap to not be off on the measurements! long exitMarker = System.currentTimeMillis() - Agent.ProcessEntryTimeStamp; @@ -103,7 +103,6 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).skip(3).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); - String currentTestMethod = TraceCollector.getCurrentKey(); if (currentTestMethod != null && !currentTestMethod.isEmpty()) { int index; for (index = 0; index < stackTrace.length; index++) { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index e1eaa112..157abbb5 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -2,7 +2,6 @@ public class InstrumentationParameters { public InstrumentationParameter[] MethodsToInstrument; - public InstrumentationParameter[] TestsToInstrument; public String[] LibraryMethods; public String[] ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 86d2659f..da8c7c5e 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -127,6 +127,18 @@ public static void exit( Logger.Log(loggerInstance, ": " + methodName); } + String testName = "Unknown"; + for (int i = 0; i < stackTraceElements.length; i++) { + StackTraceElement s = stackTraceElements[i]; + + String methodName = s.getClassName() + "." + s.getMethodName(); + if (methodName.equals("org.junit.platform.commons.util.ReflectionUtils.invokeMethod")) { + StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; + testName = testStackTraceElement.getClassName() + "." + testStackTraceElement.getMethodName(); + break; + } + } + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) @@ -192,8 +204,8 @@ public static void exit( // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace); - TraceCollector.addMethodTrace(trace); + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace, testName); + TraceCollector.addMethodTrace(testName, trace); Logger.Log(loggerInstance, ": Accepted Trace"); Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); return; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 6bc99137..5948f1c3 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -128,6 +128,18 @@ public static void exit( Logger.Log(loggerInstance, ": " + methodName); } + String testName = "Unknown"; + for (int i = 0; i < stackTraceElements.length; i++) { + StackTraceElement s = stackTraceElements[i]; + + String methodName = s.getClassName() + "." + s.getMethodName(); + if (methodName.equals("org.junit.platform.commons.util.ReflectionUtils.invokeMethod")) { + StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; + testName = testStackTraceElement.getClassName() + "." + testStackTraceElement.getMethodName(); + break; + } + } + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) @@ -193,8 +205,8 @@ public static void exit( // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace); - TraceCollector.addMethodTrace(trace); + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, testName); + TraceCollector.addMethodTrace(testName, trace); Logger.Log(loggerInstance, ": Accepted Trace"); Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); return; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java deleted file mode 100644 index 94dc2c81..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestAdvisor.java +++ /dev/null @@ -1,20 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.visitors; - -import com.github.maracas.gilesi.instrumentation.TraceCollector; -import net.bytebuddy.asm.Advice; - -import java.lang.reflect.Executable; - -public class TestAdvisor { - @Advice.OnMethodEnter(inline = false) - public static Object enter(@Advice.Origin Executable origin) { - - TraceCollector.setCurrentKey(origin.getDeclaringClass().getName() + "." + origin.getName()); - return null; - } - - @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) - public static void exit() { - TraceCollector.setCurrentKey(""); - } -} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java deleted file mode 100644 index 3e17f98c..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/TestInstrumentor.java +++ /dev/null @@ -1,30 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.visitors; - -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; -import net.bytebuddy.agent.builder.AgentBuilder; -import net.bytebuddy.asm.Advice; -import net.bytebuddy.description.method.MethodDescription; -import net.bytebuddy.matcher.ElementMatcher; -import net.bytebuddy.matcher.ElementMatchers; - -import java.lang.instrument.Instrumentation; - -import static net.bytebuddy.matcher.ElementMatchers.named; - -public class TestInstrumentor { - public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - ElementMatcher.Junction methodMatcher = ElementMatchers.namedOneOf(instrumentationParameter.MethodName); - - new AgentBuilder.Default() - .type(named(instrumentationParameter.ClassName)) - .transform((builder, - typeDescription, - classLoader, - javaModule, - protectionDomain) -> - builder.visit(Advice.to(TestAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(methodMatcher))) - ) - .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) - .with(AgentBuilder.TypeStrategy.Default.REDEFINE).installOn(inst); - } -} From 7ba6aa5b0ee52c8d8aa0ef79464550ea35cf1e01 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 09:48:16 +0100 Subject: [PATCH 056/244] fix: cleanup trace saving code --- .../maracas/gilesi/instrumentation/Agent.java | 21 --------------- .../instrumentation/TraceCollector.java | 26 +++++++++++++++++++ 2 files changed, 26 insertions(+), 21 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index ac3b7a48..713dccbe 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -24,24 +24,6 @@ public static InstrumentationParameters parseInstrumentationparameters(File file return objectMapper.readValue(file, InstrumentationParameters.class); } - /** - * Generates the tracing results text file on disk - */ - public static void SaveTraceResults() { - File outputFile = new File("MethodTraces.json"); - System.out.println("Saving trace results in progress..."); - System.out.println("Output location: " + outputFile.getAbsolutePath()); - - try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); - } catch (Exception e) { - System.err.println("ERROR"); - e.printStackTrace(); - } - } - /* Our primary method to install the agent required to trace methods during execution We take in as parameter a JSON file with the list of methods to instrument and their class @@ -83,9 +65,6 @@ private static void installAgent(String arg, Instrumentation inst) { for (InstrumentationParameter instrumentationParameter : instrumentationParameters.MethodsToInstrument) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } - - // Then add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(Agent::SaveTraceResults)); } /* diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 1006c200..7efc99fc 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,8 +1,11 @@ package com.github.maracas.gilesi.instrumentation; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; +import java.io.File; import java.util.ArrayList; import java.util.Collection; @@ -34,4 +37,27 @@ public static void addMethodTrace(String currentTestMethod, Trace trace) { public static Collection getMethodTraces() { return TRACES; } + + /** + * Generates the tracing results text file on disk + */ + public static void SaveTraceResults() { + File outputFile = new File("MethodTraces.json"); + System.out.println("Saving trace results in progress..."); + System.out.println("Output location: " + outputFile.getAbsolutePath()); + + try { + ObjectMapper objectMapper = new ObjectMapper(); + objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); + } catch (Exception e) { + System.err.println("ERROR"); + e.printStackTrace(); + } + } + + static { + // Add a shutdown hook to save all method execution traces at exit + Runtime.getRuntime().addShutdownHook(new Thread(TraceCollector::SaveTraceResults)); + } } \ No newline at end of file From 03e23a6aa65d3d1962bb969c7e0940a2df3b1f81 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 10:11:38 +0100 Subject: [PATCH 057/244] fix: cleanup/timestamps --- .../maracas/gilesi/instrumentation/Agent.java | 2 +- .../gilesi/instrumentation/TraceFactory.java | 4 +- .../visitors/CommonAdvisor.java | 149 +++++++++++++ .../visitors/ConstructorAdvisor.java | 196 +----------------- .../visitors/MethodAdvisor.java | 196 +----------------- 5 files changed, 156 insertions(+), 391 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 713dccbe..ad0b6000 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -17,7 +17,7 @@ public class Agent { public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; - public static final long ProcessEntryTimeStamp = System.currentTimeMillis(); + public static final long ProcessEntryTimeStamp = System.nanoTime(); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index cdbbc86d..b0f1e805 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -64,7 +64,7 @@ private static List getArgumentsAsSerializableData(Object[] arguments */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.currentTimeMillis() - Agent.ProcessEntryTimeStamp; + long entryMarker = System.nanoTime() - Agent.ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); @@ -92,7 +92,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg */ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String currentTestMethod) { // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.currentTimeMillis() - Agent.ProcessEntryTimeStamp; + long exitMarker = System.nanoTime() - Agent.ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java new file mode 100644 index 00000000..64c95046 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -0,0 +1,149 @@ +package com.github.maracas.gilesi.instrumentation.visitors; + +import com.github.maracas.gilesi.instrumentation.Agent; +import com.github.maracas.gilesi.instrumentation.Logger; +import com.github.maracas.gilesi.instrumentation.TraceCollector; +import com.github.maracas.gilesi.instrumentation.TraceFactory; +import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.maracas.gilesi.instrumentation.models.Trace; + +import java.lang.reflect.Executable; +import java.util.Arrays; + +public class CommonAdvisor { + private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; + private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; + private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; + private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; + + public static Object commonEnter( + Executable origin, + Object[] arguments, + Object instance) { + if (isAcceptedTrace()) { + return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + } else { + return null; + } + } + + public static void commonExit( + Executable origin, + Object[] arguments, + Object returned, + Object instance, + Throwable thrown, + PartialTrace entryTrace) { + if (isAcceptedTrace()) { + String testName = getTestMethodName(); + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, testName); + TraceCollector.addMethodTrace(testName, trace); + } + } + + private static String getTestMethodName() { + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + for (int i = 0; i < stackTraceElements.length; i++) { + StackTraceElement s = stackTraceElements[i]; + + String methodName = String.format("%s.%s", s.getClassName(), s.getMethodName()); + if (methodName.equals(JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN)) { + StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; + return String.format("%s.%s", testStackTraceElement.getClassName(), testStackTraceElement.getMethodName()); + } + } + + return UNKNOWN_TEST_METHOD_NAME; + } + + private static boolean isAcceptedTrace() { + int instrumentedMethodStackTraceIndex = 3; + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + + int loggerInstance = Logger.GetInstance(); + + Logger.Log(loggerInstance, "++MethodAdvisor::Exit"); + Logger.Log(loggerInstance, " StackTrace:"); + for (StackTraceElement s : stackTraceElements) { + String methodName = String.format("%s.%s", s.getClassName(), s.getMethodName()); + Logger.Log(loggerInstance, String.format(" %s", methodName)); + } + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 2: The caller: FooTest.mainTest(FooTest.java:50) + // 3: ... + + StackTraceElement callerStackTraceElement = stackTraceElements[instrumentedMethodStackTraceIndex + 1]; + String methodName = String.format("%s.%s", callerStackTraceElement.getClassName(), callerStackTraceElement.getMethodName()); + + // The caller is a method from the library, which we do not want to collect traces for in our case + // Because we focus on API calls here, so do not do anything. + // Note: it's also possible the tracing, is originating from us, + // so we want to also check if we are not a caller ourselves as well + if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + methodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { + Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return false; + } + + // When we collect traces, we attempt to serialize the data transiting on the API barrier + // Unfortunately for us, some classes may return objects, that are linked to themselves + // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to + // Serialize an object, and while doing so, we go into our entry/exit methods + // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well + + // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) + // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) + // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) + // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) + // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) + // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) + // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) + // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) + // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) + // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 15: The caller: ... + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= instrumentedMethodStackTraceIndex + 10) { + StackTraceElement originatingReflectStackTraceElement = stackTraceElements[instrumentedMethodStackTraceIndex + 10]; + String originatingReflectMethodName = String.format("%s.%s", originatingReflectStackTraceElement.getClassName(), originatingReflectStackTraceElement.getMethodName()); + + if (originatingReflectMethodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { + Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return false; + } + } + + // Start with the caller + for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTraceElements.length; i++) { + StackTraceElement stackTraceElement = stackTraceElements[i]; + String stackTraceMethodName = String.format("%s.%s", stackTraceElement.getClassName(), stackTraceElement.getMethodName()); + + if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return false; + } + + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + Logger.Log(loggerInstance, " Accepted Trace"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return true; + } + } + + // We never found any trace of the client, something is up... + Logger.Log(loggerInstance, " Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + + return false; + } +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java index da8c7c5e..0a254d08 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -1,112 +1,18 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.Agent; -import com.github.maracas.gilesi.instrumentation.Logger; -import com.github.maracas.gilesi.instrumentation.TraceCollector; -import com.github.maracas.gilesi.instrumentation.TraceFactory; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; -import com.github.maracas.gilesi.instrumentation.models.Trace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; -import java.util.Arrays; public class ConstructorAdvisor { - private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; - private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; - @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - int loggerInstance = Logger.GetInstance(); - - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - - Logger.Log(loggerInstance, ":++ConstructorAdvisor::Entry"); - Logger.Log(loggerInstance, ": StackTrace:"); - for (StackTraceElement s : stackTraceElements) { - String methodName = s.getClassName() + "." + s.getMethodName(); - Logger.Log(loggerInstance, ": " + methodName); - } - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) - // 2: The caller: FooTest.mainTest(FooTest.java:50) - // 3: ... - - StackTraceElement callerStackTraceElement = stackTraceElements[2]; - String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); - - // The caller is a method from the library, which we do not want to collect traces for in our case - // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the tracing, is originating from us, - // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); - return null; - } - - // When we collect traces, we attempt to serialize the data transiting on the API barrier - // Unfortunately for us, some classes may return objects, that are linked to themselves - // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to - // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) - // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { - StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; - String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - - if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); - return null; - } - } - - // Start with the caller - for (int i = 2; i < stackTraceElements.length; i++) { - StackTraceElement stackTraceElement = stackTraceElements[i]; - String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); - - if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); - return null; - } - - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Accepted Trace"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); - return TraceFactory.getPartialMethodTrace(origin, arguments, instance); - } - } - - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Entry"); - return null; + return CommonAdvisor.commonEnter(origin, arguments, instance); } @Advice.OnMethodExit(inline = false) @@ -116,104 +22,6 @@ public static void exit( @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { - int loggerInstance = Logger.GetInstance(); - - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - - Logger.Log(loggerInstance, ":++ConstructorAdvisor::Exit"); - Logger.Log(loggerInstance, ": StackTrace:"); - for (StackTraceElement s : stackTraceElements) { - String methodName = s.getClassName() + "." + s.getMethodName(); - Logger.Log(loggerInstance, ": " + methodName); - } - - String testName = "Unknown"; - for (int i = 0; i < stackTraceElements.length; i++) { - StackTraceElement s = stackTraceElements[i]; - - String methodName = s.getClassName() + "." + s.getMethodName(); - if (methodName.equals("org.junit.platform.commons.util.ReflectionUtils.invokeMethod")) { - StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; - testName = testStackTraceElement.getClassName() + "." + testStackTraceElement.getMethodName(); - break; - } - } - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:19) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) - // 2: The caller: FooTest.mainTest(FooTest.java:50) - // 3: ... - - StackTraceElement callerStackTraceElement = stackTraceElements[2]; - String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); - - // The caller is a method from the library, which we do not want to collect traces for in our case - // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the tracing, is originating from us, - // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); - return; - } - - // When we collect traces, we attempt to serialize the data transiting on the API barrier - // Unfortunately for us, some classes may return objects, that are linked to themselves - // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to - // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.ConstructorAdvisor.enter(ConstructorAdvisor.java:40) - // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { - StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; - String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - - if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); - return; - } - } - - // Start with the caller - for (int i = 2; i < stackTraceElements.length; i++) { - StackTraceElement stackTraceElement = stackTraceElements[i]; - String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); - - if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); - return; - } - - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, null, entryTrace, testName); - TraceCollector.addMethodTrace(testName, trace); - Logger.Log(loggerInstance, ": Accepted Trace"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); - return; - } - } - - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); - Logger.Log(loggerInstance, ":--ConstructorAdvisor::Exit"); + CommonAdvisor.commonExit(origin, arguments, returned, instance, null, entryTrace); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java index 5948f1c3..a41fe99f 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,112 +1,18 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.Agent; -import com.github.maracas.gilesi.instrumentation.Logger; -import com.github.maracas.gilesi.instrumentation.TraceCollector; -import com.github.maracas.gilesi.instrumentation.TraceFactory; import com.github.maracas.gilesi.instrumentation.models.PartialTrace; -import com.github.maracas.gilesi.instrumentation.models.Trace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; import java.lang.reflect.Executable; -import java.util.Arrays; public class MethodAdvisor { - private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; - private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; - @Advice.OnMethodEnter(inline = false) public static Object enter( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { - int loggerInstance = Logger.GetInstance(); - - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - - Logger.Log(loggerInstance, ":++MethodAdvisor::Entry"); - Logger.Log(loggerInstance, ": StackTrace:"); - for (StackTraceElement s : stackTraceElements) { - String methodName = s.getClassName() + "." + s.getMethodName(); - Logger.Log(loggerInstance, ": " + methodName); - } - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) - // 2: The caller: FooTest.mainTest(FooTest.java:50) - // 3: ... - - StackTraceElement callerStackTraceElement = stackTraceElements[2]; - String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); - - // The caller is a method from the library, which we do not want to collect traces for in our case - // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the tracing, is originating from us, - // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); - return null; - } - - // When we collect traces, we attempt to serialize the data transiting on the API barrier - // Unfortunately for us, some classes may return objects, that are linked to themselves - // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to - // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { - StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; - String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - - if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); - return null; - } - } - - // Start with the caller - for (int i = 2; i < stackTraceElements.length; i++) { - StackTraceElement stackTraceElement = stackTraceElements[i]; - String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); - - if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); - return null; - } - - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Accepted Trace"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); - return TraceFactory.getPartialMethodTrace(origin, arguments, instance); - } - } - - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Entry"); - return null; + return CommonAdvisor.commonEnter(origin, arguments, instance); } @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) @@ -117,104 +23,6 @@ public static void exit( @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, @Advice.Thrown Throwable thrown, @Advice.Enter(typing = Assigner.Typing.DYNAMIC) PartialTrace entryTrace) { - int loggerInstance = Logger.GetInstance(); - - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - - Logger.Log(loggerInstance, ":++MethodAdvisor::Exit"); - Logger.Log(loggerInstance, ": StackTrace:"); - for (StackTraceElement s : stackTraceElements) { - String methodName = s.getClassName() + "." + s.getMethodName(); - Logger.Log(loggerInstance, ": " + methodName); - } - - String testName = "Unknown"; - for (int i = 0; i < stackTraceElements.length; i++) { - StackTraceElement s = stackTraceElements[i]; - - String methodName = s.getClassName() + "." + s.getMethodName(); - if (methodName.equals("org.junit.platform.commons.util.ReflectionUtils.invokeMethod")) { - StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; - testName = testStackTraceElement.getClassName() + "." + testStackTraceElement.getMethodName(); - break; - } - } - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) - // 2: The caller: FooTest.mainTest(FooTest.java:50) - // 3: ... - - StackTraceElement callerStackTraceElement = stackTraceElements[2]; - String methodName = callerStackTraceElement.getClassName() + "." + callerStackTraceElement.getMethodName(); - - // The caller is a method from the library, which we do not want to collect traces for in our case - // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the tracing, is originating from us, - // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || - methodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); - return; - } - - // When we collect traces, we attempt to serialize the data transiting on the API barrier - // Unfortunately for us, some classes may return objects, that are linked to themselves - // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to - // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= 11) { - StackTraceElement originatingReflectStackTraceElement = stackTraceElements[11]; - String originatingReflectMethodName = originatingReflectStackTraceElement.getClassName() + "." + originatingReflectStackTraceElement.getMethodName(); - - if (originatingReflectMethodName.startsWith(GILESI_INSTRUMENTATION_NAMESPACE + ".")) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); - return; - } - } - - // Start with the caller - for (int i = 2; i < stackTraceElements.length; i++) { - StackTraceElement stackTraceElement = stackTraceElements[i]; - String stackTraceMethodName = stackTraceElement.getClassName() + "." + stackTraceElement.getMethodName(); - - if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, ": Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); - return; - } - - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, testName); - TraceCollector.addMethodTrace(testName, trace); - Logger.Log(loggerInstance, ": Accepted Trace"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); - return; - } - } - - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, ": Rejected Trace (Case 4)"); - Logger.Log(loggerInstance, ":--MethodAdvisor::Exit"); + CommonAdvisor.commonExit(origin, arguments, returned, instance, thrown, entryTrace); } } \ No newline at end of file From e299031b5fe7c74d2b7d3faeee19088313ae88e2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 10:16:23 +0100 Subject: [PATCH 058/244] fix: further cleanup --- .../maracas/gilesi/instrumentation/Agent.java | 11 ++++------- .../maracas/gilesi/instrumentation/Logger.java | 10 +++++----- .../gilesi/instrumentation/TraceCollector.java | 17 +++++++++-------- .../instrumentation/TraceDataFactory.java | 5 +---- .../gilesi/instrumentation/TraceFactory.java | 6 ++++-- .../instrumentation/visitors/CommonAdvisor.java | 9 +++++---- 6 files changed, 28 insertions(+), 30 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index ad0b6000..1849bd35 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -1,9 +1,9 @@ package com.github.maracas.gilesi.instrumentation; import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; @@ -15,12 +15,9 @@ Our main agent class */ public class Agent { - public static String[] LibraryMethods = new String[0]; - public static String[] ClientMethods = new String[0]; - public static final long ProcessEntryTimeStamp = System.nanoTime(); + public static ObjectMapper objectMapper = new ObjectMapper(); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(file, InstrumentationParameters.class); } @@ -58,8 +55,8 @@ private static void installAgent(String arg, Instrumentation inst) { return; } - LibraryMethods = instrumentationParameters.LibraryMethods; - ClientMethods = instrumentationParameters.ClientMethods; + CommonAdvisor.LibraryMethods = instrumentationParameters.LibraryMethods; + CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; // Instrument every class for (InstrumentationParameter instrumentationParameter : instrumentationParameters.MethodsToInstrument) { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java index e5bf1211..bd2ca1da 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java @@ -8,6 +8,11 @@ public class Logger { private static final ArrayList LOGGER = new ArrayList<>(); private static int LOGGERINSTANCE = 0; + static { + // Add a shutdown hook to save all logs at exit + Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); + } + public static void SaveLogResults() { try { Files.write(new File("gilesi.instrumentation.log").toPath(), LOGGER); @@ -17,11 +22,6 @@ public static void SaveLogResults() { } } - static { - // Add a shutdown hook to save all logs at exit - Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); - } - public static int GetInstance() { return LOGGERINSTANCE++; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 7efc99fc..ec58e30a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,6 +1,5 @@ package com.github.maracas.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; @@ -13,6 +12,11 @@ public class TraceCollector { // Storage for traces collected so far private static final ArrayList TRACES = new ArrayList<>(); + static { + // Add a shutdown hook to save all method execution traces at exit + Runtime.getRuntime().addShutdownHook(new Thread(TraceCollector::SaveTraceResults)); + } + public static void addMethodTrace(String currentTestMethod, Trace trace) { for (TestTraceResults testTraceResults : TRACES) { if (testTraceResults.Test.equals(currentTestMethod)) { @@ -46,18 +50,15 @@ public static void SaveTraceResults() { System.out.println("Saving trace results in progress..."); System.out.println("Output location: " + outputFile.getAbsolutePath()); + Agent.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + try { - ObjectMapper objectMapper = new ObjectMapper(); - objectMapper.enable(SerializationFeature.INDENT_OUTPUT); - objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); + Agent.objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); } catch (Exception e) { System.err.println("ERROR"); e.printStackTrace(); } - } - static { - // Add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(TraceCollector::SaveTraceResults)); + Agent.objectMapper.disable(SerializationFeature.INDENT_OUTPUT); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 3463f0ef..88a91520 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -1,12 +1,9 @@ package com.github.maracas.gilesi.instrumentation; import com.fasterxml.jackson.core.JsonProcessingException; -import com.fasterxml.jackson.databind.ObjectMapper; import com.github.maracas.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - private static final ObjectMapper objectMapper = new ObjectMapper(); - public static TraceData valueOf(Object object) { if (object == null) { return null; @@ -29,7 +26,7 @@ public static TraceData valueOf(Object object) { String serializedString = null; try { - serializedString = objectMapper.writeValueAsString(object); + serializedString = Agent.objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { System.err.println("ERROR: Cannot serialize specific argument: " + e); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index b0f1e805..3bc21ccd 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -13,6 +13,8 @@ import java.util.stream.Collectors; public class TraceFactory { + public static final long ProcessEntryTimeStamp = System.nanoTime(); + /** * Gets the origin name from an Exectuable object with the signature if possible. *

@@ -64,7 +66,7 @@ private static List getArgumentsAsSerializableData(Object[] arguments */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.nanoTime() - Agent.ProcessEntryTimeStamp; + long entryMarker = System.nanoTime() - ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); @@ -92,7 +94,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg */ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String currentTestMethod) { // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.nanoTime() - Agent.ProcessEntryTimeStamp; + long exitMarker = System.nanoTime() - ProcessEntryTimeStamp; String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java index 64c95046..892cdf8d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -1,6 +1,5 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.Agent; import com.github.maracas.gilesi.instrumentation.Logger; import com.github.maracas.gilesi.instrumentation.TraceCollector; import com.github.maracas.gilesi.instrumentation.TraceFactory; @@ -15,6 +14,8 @@ public class CommonAdvisor { private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; + public static String[] LibraryMethods = new String[0]; + public static String[] ClientMethods = new String[0]; public static Object commonEnter( Executable origin, @@ -81,7 +82,7 @@ private static boolean isAcceptedTrace() { // Because we focus on API calls here, so do not do anything. // Note: it's also possible the tracing, is originating from us, // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(Agent.LibraryMethods).contains(methodName) || + if (Arrays.asList(LibraryMethods).contains(methodName) || methodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); @@ -126,14 +127,14 @@ private static boolean isAcceptedTrace() { StackTraceElement stackTraceElement = stackTraceElements[i]; String stackTraceMethodName = String.format("%s.%s", stackTraceElement.getClassName(), stackTraceElement.getMethodName()); - if (Arrays.asList(Agent.LibraryMethods).contains(stackTraceMethodName)) { + if (Arrays.asList(LibraryMethods).contains(stackTraceMethodName)) { Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); return false; } // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(Agent.ClientMethods).contains(stackTraceMethodName)) { + if (Arrays.asList(ClientMethods).contains(stackTraceMethodName)) { Logger.Log(loggerInstance, " Accepted Trace"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); return true; From d1dfa3ddcda871cf05414a9671af7dfa6dc6641c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 10:37:22 +0100 Subject: [PATCH 059/244] Improve stack trace collection & timestamps --- .../gilesi/instrumentation/TraceFactory.java | 22 +----- .../visitors/CommonAdvisor.java | 70 ++++++++++++------- 2 files changed, 47 insertions(+), 45 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 3bc21ccd..c88a1687 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -65,14 +65,11 @@ private static List getArgumentsAsSerializableData(Object[] arguments * @param arguments The originating trace argument list on entry */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { - // Need to fetch this asap to not be off on the measurements! - long entryMarker = System.nanoTime() - ProcessEntryTimeStamp; - String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); List preCallArguments = getArgumentsAsSerializableData(arguments); - return new PartialTrace(methodSignature, serializableInstance, preCallArguments, entryMarker); + return new PartialTrace(methodSignature, serializableInstance, preCallArguments, 0); } /** @@ -92,9 +89,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg * @param arguments The originating trace argument list on entry * @param returned The data returned by the originating trace */ - public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String currentTestMethod) { - // Need to fetch this asap to not be off on the measurements! - long exitMarker = System.nanoTime() - ProcessEntryTimeStamp; + public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String[] stackTrace) { String methodSignature = getOriginName(origin); TraceData serializableInstance = TraceDataFactory.valueOf(instance); @@ -103,18 +98,7 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object TraceData returnedValue = TraceDataFactory.valueOf(returned); long timeStampEntry = originatingTrace.getTimeStampEntry(); TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); - String[] stackTrace = Arrays.stream(Thread.currentThread().getStackTrace()).skip(3).map(t -> t.getClassName() + "." + t.getMethodName()).toArray(String[]::new); - - if (currentTestMethod != null && !currentTestMethod.isEmpty()) { - int index; - for (index = 0; index < stackTrace.length; index++) { - if (stackTrace[index].equals(currentTestMethod)) { - break; - } - } - stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); - } - return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, exitMarker, exceptionThrown, stackTrace); + return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, 0, exceptionThrown, stackTrace); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java index 892cdf8d..0fdbea37 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -21,8 +21,17 @@ public static Object commonEnter( Executable origin, Object[] arguments, Object instance) { - if (isAcceptedTrace()) { - return TraceFactory.getPartialMethodTrace(origin, arguments, instance); + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + + if (isAcceptedTrace(stackTrace)) { + PartialTrace partialTrace = TraceFactory.getPartialMethodTrace(origin, arguments, instance); + + // Need to fetch this asap to not be off on the measurements! + long entryMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; + partialTrace.setTimeStampEntry(entryMarker); + + return partialTrace; } else { return null; } @@ -35,38 +44,50 @@ public static void commonExit( Object instance, Throwable thrown, PartialTrace entryTrace) { - if (isAcceptedTrace()) { - String testName = getTestMethodName(); - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, testName); + // Need to fetch this asap to not be off on the measurements! + long exitMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; + + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + + if (isAcceptedTrace(stackTrace)) { + String testName = getTestMethodName(stackTrace); + + if (testName != null && !testName.isEmpty()) { + int index; + for (index = 0; index < stackTrace.length; index++) { + if (stackTrace[index].equals(testName)) { + break; + } + } + stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); + } + + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, stackTrace); + trace.setTimeStampExit(exitMarker); TraceCollector.addMethodTrace(testName, trace); } } - private static String getTestMethodName() { - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - for (int i = 0; i < stackTraceElements.length; i++) { - StackTraceElement s = stackTraceElements[i]; - - String methodName = String.format("%s.%s", s.getClassName(), s.getMethodName()); + private static String getTestMethodName(String[] stackTrace) { + for (int i = 0; i < stackTrace.length; i++) { + String methodName = stackTrace[i]; if (methodName.equals(JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN)) { - StackTraceElement testStackTraceElement = stackTraceElements[i - 3]; - return String.format("%s.%s", testStackTraceElement.getClassName(), testStackTraceElement.getMethodName()); + return stackTrace[i - 3]; } } return UNKNOWN_TEST_METHOD_NAME; } - private static boolean isAcceptedTrace() { - int instrumentedMethodStackTraceIndex = 3; - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + private static boolean isAcceptedTrace(String[] stackTrace) { + int instrumentedMethodStackTraceIndex = 0; int loggerInstance = Logger.GetInstance(); Logger.Log(loggerInstance, "++MethodAdvisor::Exit"); Logger.Log(loggerInstance, " StackTrace:"); - for (StackTraceElement s : stackTraceElements) { - String methodName = String.format("%s.%s", s.getClassName(), s.getMethodName()); + for (String methodName : stackTrace) { Logger.Log(loggerInstance, String.format(" %s", methodName)); } @@ -75,8 +96,7 @@ private static boolean isAcceptedTrace() { // 2: The caller: FooTest.mainTest(FooTest.java:50) // 3: ... - StackTraceElement callerStackTraceElement = stackTraceElements[instrumentedMethodStackTraceIndex + 1]; - String methodName = String.format("%s.%s", callerStackTraceElement.getClassName(), callerStackTraceElement.getMethodName()); + String methodName = stackTrace[instrumentedMethodStackTraceIndex + 1]; // The caller is a method from the library, which we do not want to collect traces for in our case // Because we focus on API calls here, so do not do anything. @@ -111,9 +131,8 @@ private static boolean isAcceptedTrace() { // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTraceElements.length >= instrumentedMethodStackTraceIndex + 10) { - StackTraceElement originatingReflectStackTraceElement = stackTraceElements[instrumentedMethodStackTraceIndex + 10]; - String originatingReflectMethodName = String.format("%s.%s", originatingReflectStackTraceElement.getClassName(), originatingReflectStackTraceElement.getMethodName()); + if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTrace.length >= instrumentedMethodStackTraceIndex + 10) { + String originatingReflectMethodName = stackTrace[instrumentedMethodStackTraceIndex + 10]; if (originatingReflectMethodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); @@ -123,9 +142,8 @@ private static boolean isAcceptedTrace() { } // Start with the caller - for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTraceElements.length; i++) { - StackTraceElement stackTraceElement = stackTraceElements[i]; - String stackTraceMethodName = String.format("%s.%s", stackTraceElement.getClassName(), stackTraceElement.getMethodName()); + for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTrace.length; i++) { + String stackTraceMethodName = stackTrace[i]; if (Arrays.asList(LibraryMethods).contains(stackTraceMethodName)) { Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); From edb6d0a3e7d7d137b7dd4a7c06f55ed7ecc05a0f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 11:04:16 +0100 Subject: [PATCH 060/244] more refactoring --- .../github/maracas/gilesi/confgen/Main.java | 49 +++++++++++--- .../models/ClassParameter.java | 8 +++ .../models/InstrumentationParameter.java | 7 -- .../models/InstrumentationParameters.java | 2 +- .../models/MethodParameter.java | 8 +++ .../maracas/gilesi/instrumentation/Agent.java | 4 +- .../models/ClassParameter.java | 6 ++ .../models/InstrumentationParameter.java | 7 -- .../models/InstrumentationParameters.java | 2 +- .../models/MethodParameter.java | 6 ++ .../visitors/MethodInstrumentor.java | 65 +++++++++++++++++-- 11 files changed, 133 insertions(+), 31 deletions(-) create mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java create mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 93a0a9a0..2cf463fd 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -3,8 +3,9 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.ClassParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.maracas.gilesi.instrumentation.models.MethodParameter; import com.github.maracas.roseau.api.SpoonAPIExtractor; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; @@ -19,7 +20,6 @@ import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; -import java.util.List; public class Main { private static String getClassNameFromFQN(String fullyQualifiedName) { @@ -47,12 +47,45 @@ private static String getMethodNameFromFQN(String fullyQualifiedName) { } private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName, String methodDescriptor) { - InstrumentationParameter instrumentationParameter = new InstrumentationParameter(); - instrumentationParameter.ClassName = className; - instrumentationParameter.MethodName = methodName; - instrumentationParameter.MethodDescriptor = methodDescriptor; + for (ClassParameter classToInstrument : instrumentationParameters.ClassesToInstrument) { + if (classToInstrument.ClassName.equals(className)) { + for (MethodParameter methodParameter : classToInstrument.MethodsOrConstructorsToInstrument) { + if (methodParameter.MethodName.equals(methodName)) { + for (String descriptorToInstrument : methodParameter.DescriptorsToInstrument) { + if (descriptorToInstrument.equals(methodDescriptor)) { + // Element is already in the config, return now + return; + } + } + + // Element doesn't have a descriptor in the config, add now + methodParameter.DescriptorsToInstrument.add(methodDescriptor); + return; + } + } + + // Element doesn't have a method in the config, add now + MethodParameter methodParameter = new MethodParameter(); + methodParameter.MethodName = methodName; + methodParameter.DescriptorsToInstrument = new ArrayList<>(); + methodParameter.DescriptorsToInstrument.add(methodDescriptor); + + classToInstrument.MethodsOrConstructorsToInstrument.add(methodParameter); + return; + } + } - instrumentationParameters.MethodsToInstrument.add(instrumentationParameter); + // Element doesn't have a class in the config, add now + ClassParameter classParameter = new ClassParameter(); + classParameter.ClassName = className; + classParameter.MethodsOrConstructorsToInstrument = new ArrayList<>(); + MethodParameter methodParameter = new MethodParameter(); + methodParameter.MethodName = methodName; + methodParameter.DescriptorsToInstrument = new ArrayList<>(); + methodParameter.DescriptorsToInstrument.add(methodDescriptor); + classParameter.MethodsOrConstructorsToInstrument.add(methodParameter); + + instrumentationParameters.ClassesToInstrument.add(classParameter); } public static void main(String[] args) throws Exception { @@ -69,7 +102,7 @@ public static void main(String[] args) throws Exception { API libraryApiModel = new SpoonAPIExtractor(libraryModel).extractAPI(); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); - instrumentationParameters.MethodsToInstrument = new ArrayList<>(); + instrumentationParameters.ClassesToInstrument = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java new file mode 100644 index 00000000..cedc581b --- /dev/null +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class ClassParameter { + public String ClassName; + public List MethodsOrConstructorsToInstrument; +} diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java deleted file mode 100644 index 339789b1..00000000 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -public class InstrumentationParameter { - public String ClassName; - public String MethodName; - public String MethodDescriptor; -} diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 7a941780..54f4ef1b 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -3,7 +3,7 @@ import java.util.List; public class InstrumentationParameters { - public List MethodsToInstrument; + public List ClassesToInstrument; public List LibraryMethods; public List ClientMethods; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java new file mode 100644 index 00000000..50b37159 --- /dev/null +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class MethodParameter { + public String MethodName; + public List DescriptorsToInstrument; +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 1849bd35..f44b66fd 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.ClassParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; @@ -59,7 +59,7 @@ private static void installAgent(String arg, Instrumentation inst) { CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; // Instrument every class - for (InstrumentationParameter instrumentationParameter : instrumentationParameters.MethodsToInstrument) { + for (ClassParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java new file mode 100644 index 00000000..63f0d5df --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java @@ -0,0 +1,6 @@ +package com.github.maracas.gilesi.instrumentation.models; + +public class ClassParameter { + public String ClassName; + public MethodParameter[] MethodsOrConstructorsToInstrument; +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java deleted file mode 100644 index 339789b1..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameter.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -public class InstrumentationParameter { - public String ClassName; - public String MethodName; - public String MethodDescriptor; -} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 157abbb5..104f291d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; public class InstrumentationParameters { - public InstrumentationParameter[] MethodsToInstrument; + public ClassParameter[] ClassesToInstrument; public String[] LibraryMethods; public String[] ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java new file mode 100644 index 00000000..69b91793 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java @@ -0,0 +1,6 @@ +package com.github.maracas.gilesi.instrumentation.models; + +public class MethodParameter { + public String MethodName; + public String[] DescriptorsToInstrument; +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index 72442784..684e0cc0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -1,6 +1,7 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameter; +import com.github.maracas.gilesi.instrumentation.models.ClassParameter; +import com.github.maracas.gilesi.instrumentation.models.MethodParameter; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -9,14 +10,68 @@ import java.lang.instrument.Instrumentation; +import static net.bytebuddy.matcher.ElementMatchers.hasDescriptor; import static net.bytebuddy.matcher.ElementMatchers.named; public class MethodInstrumentor { - public static void instrumentClassForTracingAgent(Instrumentation inst, InstrumentationParameter instrumentationParameter) { - ElementMatcher.Junction methodMatcher = named(instrumentationParameter.MethodName).and(ElementMatchers.hasDescriptor(instrumentationParameter.MethodDescriptor)); + private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(ClassParameter classParameter) { + ElementMatcher.Junction classMatcher = null; + for (MethodParameter methodParameter : classParameter.MethodsOrConstructorsToInstrument) { + if (!methodParameter.MethodName.equals("")) { + continue; + } + + ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : methodParameter.DescriptorsToInstrument) { + if (descriptorMatcher == null) { + descriptorMatcher = hasDescriptor(descriptorParameter); + } else { + descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); + } + } + + if (classMatcher == null) { + classMatcher = descriptorMatcher; + } else { + classMatcher = classMatcher.or(descriptorMatcher); + } + } + return classMatcher; + } + + private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(ClassParameter classParameter) { + ElementMatcher.Junction classMatcher = null; + for (MethodParameter methodParameter : classParameter.MethodsOrConstructorsToInstrument) { + if (methodParameter.MethodName.equals("")) { + continue; + } + + ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); + ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : methodParameter.DescriptorsToInstrument) { + if (descriptorMatcher == null) { + descriptorMatcher = hasDescriptor(descriptorParameter); + } else { + descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); + } + } + methodMatcher = methodMatcher.and(descriptorMatcher); + + if (classMatcher == null) { + classMatcher = methodMatcher; + } else { + classMatcher = classMatcher.or(methodMatcher); + } + } + return classMatcher; + } + + public static void instrumentClassForTracingAgent(Instrumentation inst, ClassParameter classParameter) { + ElementMatcher.Junction methodMatcher = getMethodElementMatcherFromClassParameter(classParameter); + ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); new AgentBuilder.Default() - .type(named(instrumentationParameter.ClassName)) + .type(named(classParameter.ClassName)) .transform((builder, typeDescription, classLoader, @@ -27,7 +82,7 @@ public static void instrumentClassForTracingAgent(Instrumentation inst, Instrume Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(methodMatcher)) ) .visit( - Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(methodMatcher)) + Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(constructorMatcher)) ) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) From 4102460715b9f0af6d8ab8e3ab189a3e2943a808 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 11:13:00 +0100 Subject: [PATCH 061/244] Even more refactoring --- .../github/maracas/gilesi/confgen/Main.java | 66 +++++++++++++------ .../models/ClassParameter.java | 5 +- .../models/InstrumentationParameters.java | 2 +- .../models/MethodParameter.java | 4 +- .../maracas/gilesi/instrumentation/Agent.java | 2 +- .../models/ClassParameter.java | 5 +- .../models/InstrumentationParameters.java | 2 +- .../models/MethodParameter.java | 4 +- .../visitors/MethodInstrumentor.java | 37 +++-------- 9 files changed, 69 insertions(+), 58 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 2cf463fd..a41c136e 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -47,11 +47,11 @@ private static String getMethodNameFromFQN(String fullyQualifiedName) { } private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName, String methodDescriptor) { - for (ClassParameter classToInstrument : instrumentationParameters.ClassesToInstrument) { - if (classToInstrument.ClassName.equals(className)) { - for (MethodParameter methodParameter : classToInstrument.MethodsOrConstructorsToInstrument) { - if (methodParameter.MethodName.equals(methodName)) { - for (String descriptorToInstrument : methodParameter.DescriptorsToInstrument) { + for (ClassParameter classToInstrument : instrumentationParameters.Classes) { + if (classToInstrument.Name.equals(className)) { + for (MethodParameter methodParameter : classToInstrument.Methods) { + if (methodParameter.Name.equals(methodName)) { + for (String descriptorToInstrument : methodParameter.Descriptors) { if (descriptorToInstrument.equals(methodDescriptor)) { // Element is already in the config, return now return; @@ -59,33 +59,60 @@ private static void addToInstrumentationObject(InstrumentationParameters instrum } // Element doesn't have a descriptor in the config, add now - methodParameter.DescriptorsToInstrument.add(methodDescriptor); + methodParameter.Descriptors.add(methodDescriptor); return; } } // Element doesn't have a method in the config, add now MethodParameter methodParameter = new MethodParameter(); - methodParameter.MethodName = methodName; - methodParameter.DescriptorsToInstrument = new ArrayList<>(); - methodParameter.DescriptorsToInstrument.add(methodDescriptor); + methodParameter.Name = methodName; + methodParameter.Descriptors = new ArrayList<>(); + methodParameter.Descriptors.add(methodDescriptor); - classToInstrument.MethodsOrConstructorsToInstrument.add(methodParameter); + classToInstrument.Methods.add(methodParameter); return; } } // Element doesn't have a class in the config, add now ClassParameter classParameter = new ClassParameter(); - classParameter.ClassName = className; - classParameter.MethodsOrConstructorsToInstrument = new ArrayList<>(); + classParameter.Name = className; + classParameter.Methods = new ArrayList<>(); + classParameter.Descriptors = new ArrayList<>(); MethodParameter methodParameter = new MethodParameter(); - methodParameter.MethodName = methodName; - methodParameter.DescriptorsToInstrument = new ArrayList<>(); - methodParameter.DescriptorsToInstrument.add(methodDescriptor); - classParameter.MethodsOrConstructorsToInstrument.add(methodParameter); + methodParameter.Name = methodName; + methodParameter.Descriptors = new ArrayList<>(); + methodParameter.Descriptors.add(methodDescriptor); + classParameter.Methods.add(methodParameter); - instrumentationParameters.ClassesToInstrument.add(classParameter); + instrumentationParameters.Classes.add(classParameter); + } + + private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String constructorDescriptor) { + for (ClassParameter classToInstrument : instrumentationParameters.Classes) { + if (classToInstrument.Name.equals(className)) { + for (String descriptorToInstrument : classToInstrument.Descriptors) { + if (descriptorToInstrument.equals(constructorDescriptor)) { + // Element is already in the config, return now + return; + } + + // Element doesn't have a descriptor in the config, add now + classToInstrument.Descriptors.add(constructorDescriptor); + return; + } + } + } + + // Element doesn't have a class in the config, add now + ClassParameter classParameter = new ClassParameter(); + classParameter.Name = className; + classParameter.Methods = new ArrayList<>(); + classParameter.Descriptors = new ArrayList<>(); + classParameter.Descriptors.add(constructorDescriptor); + + instrumentationParameters.Classes.add(classParameter); } public static void main(String[] args) throws Exception { @@ -102,7 +129,7 @@ public static void main(String[] args) throws Exception { API libraryApiModel = new SpoonAPIExtractor(libraryModel).extractAPI(); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); - instrumentationParameters.ClassesToInstrument = new ArrayList<>(); + instrumentationParameters.Classes = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); @@ -112,10 +139,9 @@ public static void main(String[] args) throws Exception { for (ConstructorDecl constructor : classDecl.getConstructors()) { String className = getClassNameFromFQN(constructor.getQualifiedName()); - String methodName = ""; String methodDescriptor = RoseauDescriptor.getDescriptor(constructor); - addToInstrumentationObject(instrumentationParameters, className, methodName, methodDescriptor); + addToInstrumentationObject(instrumentationParameters, className, methodDescriptor); } for (MethodDecl method : classDecl.getMethods()) { diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java index cedc581b..d7e78db4 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java @@ -3,6 +3,7 @@ import java.util.List; public class ClassParameter { - public String ClassName; - public List MethodsOrConstructorsToInstrument; + public String Name; + public List Methods; + public List Descriptors; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 54f4ef1b..511b8a4e 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -3,7 +3,7 @@ import java.util.List; public class InstrumentationParameters { - public List ClassesToInstrument; + public List Classes; public List LibraryMethods; public List ClientMethods; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java index 50b37159..2646931a 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java @@ -3,6 +3,6 @@ import java.util.List; public class MethodParameter { - public String MethodName; - public List DescriptorsToInstrument; + public String Name; + public List Descriptors; } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index f44b66fd..6a99535a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -59,7 +59,7 @@ private static void installAgent(String arg, Instrumentation inst) { CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; // Instrument every class - for (ClassParameter instrumentationParameter : instrumentationParameters.ClassesToInstrument) { + for (ClassParameter instrumentationParameter : instrumentationParameters.Classes) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java index 63f0d5df..a7bed2d5 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java @@ -1,6 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; public class ClassParameter { - public String ClassName; - public MethodParameter[] MethodsOrConstructorsToInstrument; + public String Name; + public MethodParameter[] Methods; + public String[] Descriptors; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 104f291d..76ec2e09 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; public class InstrumentationParameters { - public ClassParameter[] ClassesToInstrument; + public ClassParameter[] Classes; public String[] LibraryMethods; public String[] ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java index 69b91793..3549d846 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java @@ -1,6 +1,6 @@ package com.github.maracas.gilesi.instrumentation.models; public class MethodParameter { - public String MethodName; - public String[] DescriptorsToInstrument; + public String Name; + public String[] Descriptors; } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index 684e0cc0..9c06ecf7 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -15,40 +15,23 @@ public class MethodInstrumentor { private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(ClassParameter classParameter) { - ElementMatcher.Junction classMatcher = null; - for (MethodParameter methodParameter : classParameter.MethodsOrConstructorsToInstrument) { - if (!methodParameter.MethodName.equals("")) { - continue; - } - - ElementMatcher.Junction descriptorMatcher = null; - for (String descriptorParameter : methodParameter.DescriptorsToInstrument) { - if (descriptorMatcher == null) { - descriptorMatcher = hasDescriptor(descriptorParameter); - } else { - descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); - } - } - - if (classMatcher == null) { - classMatcher = descriptorMatcher; + ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : classParameter.Descriptors) { + if (descriptorMatcher == null) { + descriptorMatcher = hasDescriptor(descriptorParameter); } else { - classMatcher = classMatcher.or(descriptorMatcher); + descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); } } - return classMatcher; + return descriptorMatcher; } private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(ClassParameter classParameter) { ElementMatcher.Junction classMatcher = null; - for (MethodParameter methodParameter : classParameter.MethodsOrConstructorsToInstrument) { - if (methodParameter.MethodName.equals("")) { - continue; - } - - ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); + for (MethodParameter methodParameter : classParameter.Methods) { + ElementMatcher.Junction methodMatcher = named(methodParameter.Name); ElementMatcher.Junction descriptorMatcher = null; - for (String descriptorParameter : methodParameter.DescriptorsToInstrument) { + for (String descriptorParameter : methodParameter.Descriptors) { if (descriptorMatcher == null) { descriptorMatcher = hasDescriptor(descriptorParameter); } else { @@ -71,7 +54,7 @@ public static void instrumentClassForTracingAgent(Instrumentation inst, ClassPar ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); new AgentBuilder.Default() - .type(named(classParameter.ClassName)) + .type(named(classParameter.Name)) .transform((builder, typeDescription, classLoader, From 09141fcdb2fc4d48e4590fcc45b061f7ec624cf8 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 11:51:43 +0100 Subject: [PATCH 062/244] fix: cleanup unused code in confgen --- .../github/maracas/gilesi/confgen/Main.java | 4 +- .../gilesi/confgen/RoseauDescriptor.java | 42 ++++++------ .../gilesi/confgen/models/UsagePosition.java | 36 ---------- .../confgen/spoon/SpoonLauncherUtilities.java | 6 -- .../SpoonFullyQualifiedNameExtractor.java | 65 ------------------- 5 files changed, 24 insertions(+), 129 deletions(-) delete mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/confgen/models/UsagePosition.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index a41c136e..868fef78 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -139,7 +139,7 @@ public static void main(String[] args) throws Exception { for (ConstructorDecl constructor : classDecl.getConstructors()) { String className = getClassNameFromFQN(constructor.getQualifiedName()); - String methodDescriptor = RoseauDescriptor.getDescriptor(constructor); + String methodDescriptor = RoseauDescriptor.getDescriptor(constructor, false); addToInstrumentationObject(instrumentationParameters, className, methodDescriptor); } @@ -148,7 +148,7 @@ public static void main(String[] args) throws Exception { String FQN = method.getQualifiedName(); String className = getClassNameFromFQN(FQN); String methodName = getMethodNameFromFQN(FQN); - String methodDescriptor = RoseauDescriptor.getDescriptor(method); + String methodDescriptor = RoseauDescriptor.getDescriptor(method, false); addToInstrumentationObject(instrumentationParameters, className, methodName, methodDescriptor); } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java index 4ed308c7..e2c8c538 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java @@ -8,30 +8,30 @@ import java.util.List; public class RoseauDescriptor { - public static String getDescriptor(ConstructorDecl constructorDecl) throws Exception { + public static String getDescriptor(ConstructorDecl constructorDecl, boolean handleTypeArgs) throws Exception { StringBuilder descriptor = new StringBuilder().append('('); for (ParameterDecl parameterType : constructorDecl.getParameters()) { - descriptor.append(getDescriptor(parameterType)); + descriptor.append(getDescriptor(parameterType, handleTypeArgs)); } return descriptor.append(")V").toString(); } - public static String getDescriptor(MethodDecl methodDecl) throws Exception { + public static String getDescriptor(MethodDecl methodDecl, boolean handleTypeArgs) throws Exception { StringBuilder descriptor = new StringBuilder().append('('); for (ParameterDecl parameterType : methodDecl.getParameters()) { - descriptor.append(getDescriptor(parameterType)); + descriptor.append(getDescriptor(parameterType, handleTypeArgs)); } - return descriptor.append(')').append(getDescriptor(methodDecl.getType())).toString(); + return descriptor.append(')').append(getDescriptor(methodDecl.getType(), handleTypeArgs)).toString(); } - public static String getDescriptor(ParameterDecl parameterDecl) throws Exception { - return getDescriptor(parameterDecl.type()); + public static String getDescriptor(ParameterDecl parameterDecl, boolean handleTypeArgs) throws Exception { + return getDescriptor(parameterDecl.type(), handleTypeArgs); } - public static String getDescriptor(ITypeReference iTypeReference) throws Exception { + public static String getDescriptor(ITypeReference iTypeReference, boolean handleTypeArgs) throws Exception { switch (iTypeReference) { case ArrayTypeReference arrayTypeReference -> { - return "[" + getDescriptor(arrayTypeReference.componentType()); + return "[" + getDescriptor(arrayTypeReference.componentType(), handleTypeArgs); } case PrimitiveTypeReference primitiveTypeReference -> { String name = primitiveTypeReference.getQualifiedName(); @@ -62,17 +62,19 @@ public static String getDescriptor(ITypeReference iTypeReference) throws Excepti } case TypeReference typeReference -> { String typeArgumentString = ""; - List typeArgs = typeReference.getTypeArguments(); - /*if (!typeArgs.isEmpty()) { - // Check join string here to be very sure against spec and test it - typeArgumentString = "<" + String.join("", typeArgs.stream().map(t -> { - try { - return getDescriptor(t); - } catch (Exception e) { - throw new RuntimeException(e); - } - }).toList()) + ">"; - }*/ + if (handleTypeArgs) { + List typeArgs = typeReference.getTypeArguments(); + if (!typeArgs.isEmpty()) { + // Check join string here to be very sure against spec and test it + typeArgumentString = "<" + String.join("", typeArgs.stream().map(t -> { + try { + return getDescriptor(t, true); + } catch (Exception e) { + throw new RuntimeException(e); + } + }).toList()) + ">"; + } + } String name = typeReference.getQualifiedName(); return "L" + name.replace('.', '/') + typeArgumentString + ";"; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/models/UsagePosition.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/models/UsagePosition.java deleted file mode 100644 index 6874114b..00000000 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/models/UsagePosition.java +++ /dev/null @@ -1,36 +0,0 @@ -package com.github.maracas.gilesi.confgen.models; - -import spoon.reflect.cu.SourcePosition; - -import java.nio.file.Path; - -public record UsagePosition(String path, int line, int column, int endLine, int endColumn) { - public static UsagePosition getFromSourcePosition(SourcePosition position) { - String path = ""; - int line = -1; - int column = -1; - int endLine = -1; - int endColumn = -1; - - if (position != null && position.isValidPosition()) { - if (position.getFile() != null) { - path = position.getFile().getAbsolutePath(); - } - - line = position.getLine(); - column = position.getColumn(); - endLine = position.getEndLine(); - endColumn = position.getEndColumn(); - } - - return new UsagePosition(path, line, column, endLine, endColumn); - } - - public String getPositionAsString(Path projectLocation) { - return path().toLowerCase().replace(projectLocation.toAbsolutePath().toString().toLowerCase(), "").replace('\\', '/') + "(" + line() + ":" + column() + ")"; - } - - public String getEndPositionAsString(Path projectLocation) { - return path().toLowerCase().replace(projectLocation.toAbsolutePath().toString().toLowerCase(), "").replace('\\', '/') + "(" + endLine() + ":" + endColumn() + ")"; - } -} diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java index bb8a2478..172ed1cb 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -162,12 +162,6 @@ private static MavenLauncher.SOURCE_TYPE getSourceTypeValue(EnumSet co } } - public static Launcher getLauncherForProject(Path projectLocation, EnumSet codeTypes) { - Launcher launcher = getCommonLauncherInstance(); - applyProjectToLauncher(launcher, projectLocation, codeTypes); - return launcher; - } - public static void applyProjectToLauncher(Launcher launcher, Path projectLocation, EnumSet codeTypes) { launcher.getEnvironment().setComplianceLevel(getProjectSourceComplianceLevel(projectLocation)); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java deleted file mode 100644 index 33642b5f..00000000 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/visitors/SpoonFullyQualifiedNameExtractor.java +++ /dev/null @@ -1,65 +0,0 @@ -package com.github.maracas.gilesi.confgen.spoon.visitors; - -import spoon.reflect.code.CtConstructorCall; -import spoon.reflect.code.CtFieldRead; -import spoon.reflect.code.CtFieldWrite; -import spoon.reflect.code.CtInvocation; -import spoon.reflect.declaration.CtConstructor; -import spoon.reflect.declaration.CtField; -import spoon.reflect.declaration.CtMethod; -import spoon.reflect.declaration.CtType; -import spoon.reflect.reference.CtExecutableReference; -import spoon.reflect.reference.CtFieldReference; -import spoon.reflect.reference.CtTypeReference; - -public class SpoonFullyQualifiedNameExtractor { - public static String getFullyQualifiedName(CtField ctField) { - return getFullyQualifiedName(ctField.getDeclaringType()) + "." + ctField.getSimpleName(); - } - - public static String getFullyQualifiedName(CtInvocation ctInvocation) { - return getFullyQualifiedName(ctInvocation.getExecutable()); - } - - public static String getFullyQualifiedName(CtConstructorCall ctConstructorCall) { - return getFullyQualifiedName(ctConstructorCall.getExecutable()); - } - - public static String getFullyQualifiedName(CtExecutableReference ctExecutableReference) { - if (ctExecutableReference.isConstructor()) { - return ctExecutableReference.getSignature(); - } else { - CtTypeReference typeReference = ctExecutableReference.getDeclaringType(); - return typeReference.getQualifiedName() + "." + ctExecutableReference.getSignature(); - } - } - - public static String getFullyQualifiedName(CtFieldRead ctFieldRead) { - return getFullyQualifiedName(ctFieldRead.getVariable()); - } - - public static String getFullyQualifiedName(CtFieldWrite ctFieldWrite) { - return getFullyQualifiedName(ctFieldWrite.getVariable()); - } - - public static String getFullyQualifiedName(CtFieldReference ctFieldReference) { - return ctFieldReference.getQualifiedName(); - } - - public static String getFullyQualifiedName(CtTypeReference ctTypeReference) { - return ctTypeReference.getQualifiedName(); - } - - public static String getFullyQualifiedName(CtMethod ctMethod) { - CtType declaringType = ctMethod.getDeclaringType(); - return declaringType.getQualifiedName() + "." + ctMethod.getSignature(); - } - - public static String getFullyQualifiedName(CtConstructor ctConstructor) { - return ctConstructor.getSignature(); - } - - public static String getFullyQualifiedName(CtType ctType) { - return ctType.getQualifiedName(); - } -} \ No newline at end of file From 52fc450954204ceef7920066cf4c45b031ce623c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 11:54:12 +0100 Subject: [PATCH 063/244] fix: refactoring/cleanup --- .../github/maracas/gilesi/confgen/Main.java | 4 ++-- .../gilesi/confgen/RoseauDescriptor.java | 10 +++++----- .../confgen/spoon/SpoonLauncherUtilities.java | 18 +++++++++--------- 3 files changed, 16 insertions(+), 16 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 868fef78..d6099f6e 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -158,7 +158,7 @@ public static void main(String[] args) throws Exception { libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() .forEach(method -> instrumentationParameters.LibraryMethods - .add(type.getQualifiedName() + "." + method.getSimpleName())))); + .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); System.out.println("Processing Test Project..."); @@ -170,7 +170,7 @@ public static void main(String[] args) throws Exception { clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() .forEach(method -> instrumentationParameters.ClientMethods - .add(type.getQualifiedName() + "." + method.getSimpleName())))); + .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); String apiJson = objectMapper.writeValueAsString(instrumentationParameters); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java index e2c8c538..a954d7e0 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java @@ -31,7 +31,7 @@ public static String getDescriptor(ParameterDecl parameterDecl, boolean handleTy public static String getDescriptor(ITypeReference iTypeReference, boolean handleTypeArgs) throws Exception { switch (iTypeReference) { case ArrayTypeReference arrayTypeReference -> { - return "[" + getDescriptor(arrayTypeReference.componentType(), handleTypeArgs); + return "[%s".formatted(getDescriptor(arrayTypeReference.componentType(), handleTypeArgs)); } case PrimitiveTypeReference primitiveTypeReference -> { String name = primitiveTypeReference.getQualifiedName(); @@ -45,7 +45,7 @@ public static String getDescriptor(ITypeReference iTypeReference, boolean handle case "double" -> "D"; case "float" -> "F"; case "long" -> "J"; - default -> throw new Exception("Unsupported primitive type: " + name); + default -> throw new Exception("Unsupported primitive type: %s".formatted(name)); }; } case TypeParameterReference ignored -> { @@ -66,17 +66,17 @@ public static String getDescriptor(ITypeReference iTypeReference, boolean handle List typeArgs = typeReference.getTypeArguments(); if (!typeArgs.isEmpty()) { // Check join string here to be very sure against spec and test it - typeArgumentString = "<" + String.join("", typeArgs.stream().map(t -> { + typeArgumentString = "<%s>".formatted(String.join("", typeArgs.stream().map(t -> { try { return getDescriptor(t, true); } catch (Exception e) { throw new RuntimeException(e); } - }).toList()) + ">"; + }).toList())); } } String name = typeReference.getQualifiedName(); - return "L" + name.replace('.', '/') + typeArgumentString + ";"; + return "L%s%s;".formatted(name.replace('.', '/'), typeArgumentString); } } } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java index 172ed1cb..cd703281 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -39,7 +39,7 @@ private static Collection getPomProjectPaths(String mavenProject, spoon.Ma File mavenProjectFile = new File(mavenProject); if (!mavenProjectFile.exists()) { - throw new SpoonException(mavenProject + " does not exist."); + throw new SpoonException("%s does not exist.".formatted(mavenProject)); } Pattern profileFilter = Pattern.compile("^$"); @@ -54,7 +54,7 @@ private static Collection getPomProjectPaths(String mavenProject, spoon.Ma if (spoon.MavenLauncher.SOURCE_TYPE.APP_SOURCE == sourceType || spoon.MavenLauncher.SOURCE_TYPE.ALL_SOURCE == sourceType) { List sourceDirectories = model.getSourceDirectories(); for (File sourceDirectory : sourceDirectories) { - System.out.println("Detected Project MAIN Source Directory at: " + sourceDirectory); + System.out.printf("Detected Project MAIN Source Directory at: %s%n", sourceDirectory); paths.add(sourceDirectory.toPath()); } } @@ -63,7 +63,7 @@ private static Collection getPomProjectPaths(String mavenProject, spoon.Ma if (spoon.MavenLauncher.SOURCE_TYPE.TEST_SOURCE == sourceType || spoon.MavenLauncher.SOURCE_TYPE.ALL_SOURCE == sourceType) { List testSourceDirectories = model.getTestDirectories(); for (File sourceDirectory : testSourceDirectories) { - System.out.println("Detected Project TEST Source Directory at: " + sourceDirectory); + System.out.printf("Detected Project TEST Source Directory at: %s%n", sourceDirectory); paths.add(sourceDirectory.toPath()); } } @@ -76,7 +76,7 @@ private static int getPomProjectSourceComplianceLevel(String mavenProject) throw File mavenProjectFile = new File(mavenProject); if (!mavenProjectFile.exists()) { - throw new SpoonException(mavenProject + " does not exist."); + throw new SpoonException("%s does not exist.".formatted(mavenProject)); } Pattern profileFilter = Pattern.compile("^$"); @@ -174,7 +174,7 @@ public static void applyProjectToLauncher(Launcher launcher, Path projectLocatio public static Collection getProjectPaths(Path projectLocation, EnumSet codeTypes) { Collection paths = new HashSet<>(); - System.out.println("Trying to detect source directories for project: " + projectLocation + " with types: " + codeTypes); + System.out.printf("Trying to detect source directories for project: %s with types: %s%n", projectLocation, codeTypes); if (codeTypes.contains(CodeType.MAIN) || codeTypes.contains(CodeType.TEST)) { try { @@ -185,7 +185,7 @@ public static Collection getProjectPaths(Path projectLocation, EnumSet getProjectPaths(Path projectLocation, EnumSet getProjectPaths(Path projectLocation, EnumSet getProjectPaths(Path projectLocation, EnumSet Date: Wed, 21 Feb 2024 12:42:07 +0100 Subject: [PATCH 064/244] Start cleaning up code gen --- .../github/maracas/gilesi/traceview/Main.java | 170 +----------------- .../gilesi/traceview/TestMethodGenerator.java | 169 +++++++++++++++++ 2 files changed, 171 insertions(+), 168 deletions(-) create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 6a82fdf1..1ece26d0 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -3,152 +3,12 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; -import com.github.maracas.gilesi.instrumentation.models.TraceData; -import org.apache.commons.text.StringEscapeUtils; import java.io.File; import java.io.IOException; import java.util.*; public class Main { - // The map of instance ids to variable indexes - private static final HashMap mapOfInstancesToIndexes = new HashMap<>(); - // The list of instance ids we already defined - private static final List listOfDefinedInstances = new ArrayList<>(); - // The currently free index for variables to define in our java source code - private static int varIndex = 0; - - private static String getInstanceVarName(int instanceId) { - int i; - - if (mapOfInstancesToIndexes.containsKey(instanceId)) { - i = mapOfInstancesToIndexes.get(instanceId); - } else { - i = varIndex++; - mapOfInstancesToIndexes.put(instanceId, i); - } - - return "var%d".formatted(i); - } - - private static String serializableDataToCode(TraceData arg) { - if (arg == null) { - return "null"; - } else if (arg.getDataAsJson() != null) { - return serializableDataToJava(arg); - } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { - return getInstanceVarName(arg.getInstanceId()); - } else { - return "InstanceId{%d}".formatted(arg.getInstanceId()); - } - } - - private static String getCleanedType(String FQN) { - if (FQN.startsWith("[L") && FQN.endsWith(";")) { - FQN = "%s[]".formatted(FQN.substring(2, FQN.length() - 1)); - } - return FQN; - } - - private static String serializableDataToJava(TraceData serializableData) { - String valueToBeEqualTo = serializableData.getDataAsJson(); - String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); - - if (!FQN.equals("java.lang.String") && - !FQN.equals("java.lang.Integer") && - !FQN.equals("java.lang.Double") && - !FQN.equals("java.lang.Float") && - !FQN.equals("java.lang.Long")) { - valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); - } - return valueToBeEqualTo; - } - - private static String getReturnStatementAsCode(TraceData serializableData) { - if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { - return getInstanceVarName(serializableData.getInstanceId()); - } else { - String returnType = getCleanedType(serializableData.getFullyQualifiedTypeName()); - listOfDefinedInstances.add(serializableData.getInstanceId()); - return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); - } - } - - private static String traceToCode(Trace methodTrace) { - String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; - cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - - boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); - boolean isInstanceCall = methodTrace.getInstance() != null && !methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); - - if (isConstructor) { - cleanedMethodName = "new %s".formatted(cleanedMethodName); - } else if (isInstanceCall) { - String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; - cleanedMethodName = getInstanceVarName(methodTrace.getInstance().getInstanceId()) + "." + methodNameOnly; - } - - if (isConstructor) { - // TODO: we need to fix the tracer so for constructors we get to return an instance, and instead leave instance field empty, to make more sense and simplify this part too!! - // TODO: also we may want seen indexes to keep the order in the json in general for traces, like which index we added something at for sanity, can be useful when ordering things properly! - // TODO: last but not least, we can return instances that either previously existed or never did. - // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? - - // Value returned is of course, the instance! - - cleanedMethodName = getReturnStatementAsCode(methodTrace.getInstance()) + " = " + cleanedMethodName; - } else if (methodTrace.getReturnedValue() != null) { - // We return a value that we managed to serialize - cleanedMethodName = getReturnStatementAsCode(methodTrace.getReturnedValue()) + " = " + cleanedMethodName; - } - - List argList = new ArrayList<>(); - for (TraceData arg : methodTrace.getPreCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg); - String argumentDeclaration = "%s = %s".formatted(getReturnStatementAsCode(arg), argumentValueAsCode); - - argList.add(getInstanceVarName(arg.getInstanceId())); - cleanedMethodName = ("%s;\n" + - "\t\t%s").formatted(argumentDeclaration, cleanedMethodName); - } - - return "%s(%s);".formatted(cleanedMethodName, String.join(",", argList)); - } - - private static String traceArgumentsToAssert(Trace methodTrace) { - List argList = new ArrayList<>(); - for (TraceData arg : methodTrace.getPostCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg); - if (argumentValueAsCode.endsWith("[].class)")) { - argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); - } else { - argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); - } - } - - return String.join("\n\t\t", argList); - } - - private static String traceToAssert(Trace methodTrace) { - String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; - cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); - - if (isConstructor) { - // Nothing to do! - } else if (methodTrace.getReturnedValue() != null) { - // We return a value that we managed to serialize - String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); - if (returnValueAsCode.endsWith("[].class)")) { - return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); - } else { - return "assertEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); - } - } - - return null; - } - private static TestTraceResults[] readTraces(String filePathStr) throws IOException { ObjectMapper objectMapper = new ObjectMapper(); return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); @@ -165,29 +25,10 @@ private static List getTraceEventsFromTraces(Trace[] methodTraces) { return events.stream().sorted(Comparator.comparing(TraceEvent::At)).toList(); } - private static void printTraceAsCode(TraceEvent event) { - Trace trace = event.About(); - - String methodCallLine = traceToCode(trace); - String returnAssertionLine = traceToAssert(trace); - String postCallParameterAssertionLine = traceArgumentsToAssert(trace); - - if (methodCallLine != null && !methodCallLine.isEmpty()) { - System.out.printf("\t\t%s%n", methodCallLine); - } - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - System.out.printf("\t\t%s%n", returnAssertionLine); - } - - if (!postCallParameterAssertionLine.isEmpty()) { - System.out.printf("\t\t%s%n", postCallParameterAssertionLine); - } - } - public static void main(String[] args) throws IOException { TestTraceResults[] testTraceResultsList = readTraces(args[0]); for (TestTraceResults testTraceResults : testTraceResultsList) { + TestMethodGenerator testMethodGenerator = new TestMethodGenerator(); var splitTestName = testTraceResults.Test.split("\\."); @@ -217,7 +58,7 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < entryTraceEvents.length; i++) { TraceEvent event = entryTraceEvents[i]; - printTraceAsCode(event); + testMethodGenerator.printTraceAsCode(event); if (i != entryTraceEvents.length - 1) { System.out.println(); @@ -227,13 +68,6 @@ public static void main(String[] args) throws IOException { System.out.println("\t}"); System.out.println("}"); System.out.println(); - - // The map of instance ids to variable indexes - mapOfInstancesToIndexes.clear(); - // The list of instance ids we already defined - listOfDefinedInstances.clear(); - // The currently free index for variables to define in our java source code - varIndex = 0; } } } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java new file mode 100644 index 00000000..70f1bc8b --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -0,0 +1,169 @@ +package com.github.maracas.gilesi.traceview; + +import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.maracas.gilesi.instrumentation.models.TraceData; +import org.apache.commons.text.StringEscapeUtils; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class TestMethodGenerator { + // The map of instance ids to variable indexes + private final HashMap mapOfInstancesToIndexes = new HashMap<>(); + // The list of instance ids we already defined + private final List listOfDefinedInstances = new ArrayList<>(); + // The currently free index for variables to define in our java source code + private int varIndex = 0; + + private String getInstanceVarName(int instanceId) { + int i; + + if (mapOfInstancesToIndexes.containsKey(instanceId)) { + i = mapOfInstancesToIndexes.get(instanceId); + } else { + i = varIndex++; + mapOfInstancesToIndexes.put(instanceId, i); + } + + return "var%d".formatted(i); + } + + private String serializableDataToCode(TraceData arg) { + if (arg == null) { + return "null"; + } else if (arg.getDataAsJson() != null) { + return serializableDataToJava(arg); + } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { + return getInstanceVarName(arg.getInstanceId()); + } else { + return "InstanceId{%d}".formatted(arg.getInstanceId()); + } + } + + private String getCleanedType(String FQN) { + if (FQN.startsWith("[L") && FQN.endsWith(";")) { + FQN = "%s[]".formatted(FQN.substring(2, FQN.length() - 1)); + } + return FQN; + } + + private String serializableDataToJava(TraceData serializableData) { + String valueToBeEqualTo = serializableData.getDataAsJson(); + String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); + + if (!FQN.equals("java.lang.String") && + !FQN.equals("java.lang.Integer") && + !FQN.equals("java.lang.Double") && + !FQN.equals("java.lang.Float") && + !FQN.equals("java.lang.Long")) { + valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); + } + return valueToBeEqualTo; + } + + private String getReturnStatementAsCode(TraceData serializableData) { + if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { + return getInstanceVarName(serializableData.getInstanceId()); + } else { + String returnType = getCleanedType(serializableData.getFullyQualifiedTypeName()); + listOfDefinedInstances.add(serializableData.getInstanceId()); + return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); + } + } + + private String traceToCode(Trace methodTrace) { + String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; + cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; + + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + boolean isInstanceCall = methodTrace.getInstance() != null && !methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + + if (isConstructor) { + cleanedMethodName = "new %s".formatted(cleanedMethodName); + } else if (isInstanceCall) { + String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; + cleanedMethodName = "%s.%s".formatted(getInstanceVarName(methodTrace.getInstance().getInstanceId()), methodNameOnly); + } + + if (isConstructor) { + // TODO: we need to fix the tracer so for constructors we get to return an instance, and instead leave instance field empty, to make more sense and simplify this part too!! + // TODO: also we may want seen indexes to keep the order in the json in general for traces, like which index we added something at for sanity, can be useful when ordering things properly! + // TODO: last but not least, we can return instances that either previously existed or never did. + // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? + + // Value returned is of course, the instance! + + cleanedMethodName = "%s = %s".formatted(getReturnStatementAsCode(methodTrace.getInstance()), cleanedMethodName); + } else if (methodTrace.getReturnedValue() != null) { + // We return a value that we managed to serialize + cleanedMethodName = "%s = %s".formatted(getReturnStatementAsCode(methodTrace.getReturnedValue()), cleanedMethodName); + } + + List argList = new ArrayList<>(); + for (TraceData arg : methodTrace.getPreCallArguments()) { + String argumentValueAsCode = serializableDataToCode(arg); + String argumentDeclaration = "%s = %s".formatted(getReturnStatementAsCode(arg), argumentValueAsCode); + + argList.add(getInstanceVarName(arg.getInstanceId())); + cleanedMethodName = ("%s;\n" + + "\t\t%s").formatted(argumentDeclaration, cleanedMethodName); + } + + return "%s(%s);".formatted(cleanedMethodName, String.join(",", argList)); + } + + private String traceArgumentsToAssert(Trace methodTrace) { + List argList = new ArrayList<>(); + for (TraceData arg : methodTrace.getPostCallArguments()) { + String argumentValueAsCode = serializableDataToCode(arg); + if (argumentValueAsCode.endsWith("[].class)")) { + argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); + } else { + argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); + } + } + + return String.join("\n\t\t", argList); + } + + private String traceToAssert(Trace methodTrace) { + String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; + cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + + if (isConstructor) { + // Nothing to do! + } else if (methodTrace.getReturnedValue() != null) { + // We return a value that we managed to serialize + String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); + if (returnValueAsCode.endsWith("[].class)")) { + return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + } else { + return "assertEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + } + } + + return null; + } + + public void printTraceAsCode(TraceEvent event) { + Trace trace = event.About(); + + String methodCallLine = traceToCode(trace); + String returnAssertionLine = traceToAssert(trace); + String postCallParameterAssertionLine = traceArgumentsToAssert(trace); + + if (methodCallLine != null && !methodCallLine.isEmpty()) { + System.out.printf("\t\t%s%n", methodCallLine); + } + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + System.out.printf("\t\t%s%n", returnAssertionLine); + } + + if (!postCallParameterAssertionLine.isEmpty()) { + System.out.printf("\t\t%s%n", postCallParameterAssertionLine); + } + } +} \ No newline at end of file From d2517a53fced836e91f7e21b9dd97dde033ea77f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 12:46:28 +0100 Subject: [PATCH 065/244] Add missing primitive types --- .../maracas/gilesi/traceview/TestMethodGenerator.java | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 70f1bc8b..9e51f066 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -52,11 +52,16 @@ private String serializableDataToJava(TraceData serializableData) { String valueToBeEqualTo = serializableData.getDataAsJson(); String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); - if (!FQN.equals("java.lang.String") && - !FQN.equals("java.lang.Integer") && + if (!FQN.equals("java.lang.Integer") && + !FQN.equals("java.lang.Void") && + !FQN.equals("java.lang.Boolean") && + !FQN.equals("java.lang.Byte") && + !FQN.equals("java.lang.Character") && + !FQN.equals("java.lang.Short") && !FQN.equals("java.lang.Double") && !FQN.equals("java.lang.Float") && - !FQN.equals("java.lang.Long")) { + !FQN.equals("java.lang.Long") && + !FQN.equals("java.lang.String")) { valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); } return valueToBeEqualTo; From a6759a32800755f709de1fee8813b0344f36ed77 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 13:03:25 +0100 Subject: [PATCH 066/244] fix: implement parsing of jvm type descriptors --- .../gilesi/traceview/TestMethodGenerator.java | 31 +++++++++++++++++-- 1 file changed, 29 insertions(+), 2 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 9e51f066..1052d78e 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -41,9 +41,36 @@ private String serializableDataToCode(TraceData arg) { } } + private String JvmTypeToLangType(String name) throws Exception { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new Exception("Unsupported primitive type: %s".formatted(name)); + }; + } + private String getCleanedType(String FQN) { - if (FQN.startsWith("[L") && FQN.endsWith(";")) { - FQN = "%s[]".formatted(FQN.substring(2, FQN.length() - 1)); + if ((FQN.contains("/") || FQN.startsWith("[") || FQN.endsWith(";")) && + (FQN.startsWith("I") || FQN.startsWith("V") || + FQN.startsWith("Z") || FQN.startsWith("B") || + FQN.startsWith("C") || FQN.startsWith("S") || + FQN.startsWith("D") || FQN.startsWith("F") || + FQN.startsWith("J") || FQN.startsWith("L") || + FQN.startsWith("["))) { + try { + return JvmTypeToLangType(FQN); + } catch (Exception ignored) { + + } } return FQN; } From 87eab9f527ac6c0a5d551ffcdba5b39054b35938 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 13:10:00 +0100 Subject: [PATCH 067/244] codegen: further changes --- .../github/maracas/gilesi/traceview/Main.java | 5 +- .../gilesi/traceview/SerializationUtils.java | 59 +++++++++ .../gilesi/traceview/TestMethodGenerator.java | 121 ++---------------- .../traceview/VariableStackHandler.java | 51 ++++++++ 4 files changed, 127 insertions(+), 109 deletions(-) create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java create mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 1ece26d0..a44749d7 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -6,7 +6,10 @@ import java.io.File; import java.io.IOException; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Comparator; +import java.util.List; public class Main { private static TestTraceResults[] readTraces(String filePathStr) throws IOException { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java new file mode 100644 index 00000000..eda403d6 --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java @@ -0,0 +1,59 @@ +package com.github.maracas.gilesi.traceview; + +import com.github.maracas.gilesi.instrumentation.models.TraceData; +import org.apache.commons.text.StringEscapeUtils; + +public class SerializationUtils { + private static String JvmTypeToLangType(String name) throws Exception { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new Exception("Unsupported primitive type: %s".formatted(name)); + }; + } + + public static String getCleanedType(String FQN) { + if ((FQN.contains("/") || FQN.startsWith("[") || FQN.endsWith(";")) && + (FQN.startsWith("I") || FQN.startsWith("V") || + FQN.startsWith("Z") || FQN.startsWith("B") || + FQN.startsWith("C") || FQN.startsWith("S") || + FQN.startsWith("D") || FQN.startsWith("F") || + FQN.startsWith("J") || FQN.startsWith("L") || + FQN.startsWith("["))) { + try { + return JvmTypeToLangType(FQN); + } catch (Exception ignored) { + + } + } + return FQN; + } + + public static String serializableDataToJava(TraceData serializableData) { + String valueToBeEqualTo = serializableData.getDataAsJson(); + String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); + + if (!FQN.equals("java.lang.Integer") && + !FQN.equals("java.lang.Void") && + !FQN.equals("java.lang.Boolean") && + !FQN.equals("java.lang.Byte") && + !FQN.equals("java.lang.Character") && + !FQN.equals("java.lang.Short") && + !FQN.equals("java.lang.Double") && + !FQN.equals("java.lang.Float") && + !FQN.equals("java.lang.Long") && + !FQN.equals("java.lang.String")) { + valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); + } + return valueToBeEqualTo; + } +} diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 1052d78e..305402eb 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -2,107 +2,12 @@ import com.github.maracas.gilesi.instrumentation.models.Trace; import com.github.maracas.gilesi.instrumentation.models.TraceData; -import org.apache.commons.text.StringEscapeUtils; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; public class TestMethodGenerator { - // The map of instance ids to variable indexes - private final HashMap mapOfInstancesToIndexes = new HashMap<>(); - // The list of instance ids we already defined - private final List listOfDefinedInstances = new ArrayList<>(); - // The currently free index for variables to define in our java source code - private int varIndex = 0; - - private String getInstanceVarName(int instanceId) { - int i; - - if (mapOfInstancesToIndexes.containsKey(instanceId)) { - i = mapOfInstancesToIndexes.get(instanceId); - } else { - i = varIndex++; - mapOfInstancesToIndexes.put(instanceId, i); - } - - return "var%d".formatted(i); - } - - private String serializableDataToCode(TraceData arg) { - if (arg == null) { - return "null"; - } else if (arg.getDataAsJson() != null) { - return serializableDataToJava(arg); - } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { - return getInstanceVarName(arg.getInstanceId()); - } else { - return "InstanceId{%d}".formatted(arg.getInstanceId()); - } - } - - private String JvmTypeToLangType(String name) throws Exception { - return switch (name.charAt(0)) { - case 'I' -> "java.lang.Integer"; - case 'V' -> "java.lang.Void"; - case 'Z' -> "java.lang.Boolean"; - case 'B' -> "java.lang.Byte"; - case 'C' -> "java.lang.Character"; - case 'S' -> "java.lang.Short"; - case 'D' -> "java.lang.Double"; - case 'F' -> "java.lang.Float"; - case 'J' -> "java.lang.Long"; - case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); - case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new Exception("Unsupported primitive type: %s".formatted(name)); - }; - } - - private String getCleanedType(String FQN) { - if ((FQN.contains("/") || FQN.startsWith("[") || FQN.endsWith(";")) && - (FQN.startsWith("I") || FQN.startsWith("V") || - FQN.startsWith("Z") || FQN.startsWith("B") || - FQN.startsWith("C") || FQN.startsWith("S") || - FQN.startsWith("D") || FQN.startsWith("F") || - FQN.startsWith("J") || FQN.startsWith("L") || - FQN.startsWith("["))) { - try { - return JvmTypeToLangType(FQN); - } catch (Exception ignored) { - - } - } - return FQN; - } - - private String serializableDataToJava(TraceData serializableData) { - String valueToBeEqualTo = serializableData.getDataAsJson(); - String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); - - if (!FQN.equals("java.lang.Integer") && - !FQN.equals("java.lang.Void") && - !FQN.equals("java.lang.Boolean") && - !FQN.equals("java.lang.Byte") && - !FQN.equals("java.lang.Character") && - !FQN.equals("java.lang.Short") && - !FQN.equals("java.lang.Double") && - !FQN.equals("java.lang.Float") && - !FQN.equals("java.lang.Long") && - !FQN.equals("java.lang.String")) { - valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); - } - return valueToBeEqualTo; - } - - private String getReturnStatementAsCode(TraceData serializableData) { - if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { - return getInstanceVarName(serializableData.getInstanceId()); - } else { - String returnType = getCleanedType(serializableData.getFullyQualifiedTypeName()); - listOfDefinedInstances.add(serializableData.getInstanceId()); - return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); - } - } + private final VariableStackHandler variableStackHandler = new VariableStackHandler(); private String traceToCode(Trace methodTrace) { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; @@ -115,7 +20,7 @@ private String traceToCode(Trace methodTrace) { cleanedMethodName = "new %s".formatted(cleanedMethodName); } else if (isInstanceCall) { String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; - cleanedMethodName = "%s.%s".formatted(getInstanceVarName(methodTrace.getInstance().getInstanceId()), methodNameOnly); + cleanedMethodName = "%s.%s".formatted(variableStackHandler.getInstanceVarName(methodTrace.getInstance().getInstanceId()), methodNameOnly); } if (isConstructor) { @@ -126,18 +31,18 @@ private String traceToCode(Trace methodTrace) { // Value returned is of course, the instance! - cleanedMethodName = "%s = %s".formatted(getReturnStatementAsCode(methodTrace.getInstance()), cleanedMethodName); + cleanedMethodName = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(methodTrace.getInstance()), cleanedMethodName); } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - cleanedMethodName = "%s = %s".formatted(getReturnStatementAsCode(methodTrace.getReturnedValue()), cleanedMethodName); + cleanedMethodName = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(methodTrace.getReturnedValue()), cleanedMethodName); } List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg); - String argumentDeclaration = "%s = %s".formatted(getReturnStatementAsCode(arg), argumentValueAsCode); + String argumentValueAsCode = variableStackHandler.serializableDataToCode(arg); + String argumentDeclaration = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(arg), argumentValueAsCode); - argList.add(getInstanceVarName(arg.getInstanceId())); + argList.add(variableStackHandler.getInstanceVarName(arg.getInstanceId())); cleanedMethodName = ("%s;\n" + "\t\t%s").formatted(argumentDeclaration, cleanedMethodName); } @@ -148,11 +53,11 @@ private String traceToCode(Trace methodTrace) { private String traceArgumentsToAssert(Trace methodTrace) { List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPostCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg); + String argumentValueAsCode = variableStackHandler.serializableDataToCode(arg); if (argumentValueAsCode.endsWith("[].class)")) { - argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); + argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVarName(arg.getInstanceId()))); } else { - argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, getInstanceVarName(arg.getInstanceId()))); + argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVarName(arg.getInstanceId()))); } } @@ -168,11 +73,11 @@ private String traceToAssert(Trace methodTrace) { // Nothing to do! } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); + String returnValueAsCode = variableStackHandler.serializableDataToCode(methodTrace.getReturnedValue()); if (returnValueAsCode.endsWith("[].class)")) { - return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); } else { - return "assertEquals(%s, %s);".formatted(returnValueAsCode, getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + return "assertEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java new file mode 100644 index 00000000..107a9f1d --- /dev/null +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java @@ -0,0 +1,51 @@ +package com.github.maracas.gilesi.traceview; + +import com.github.maracas.gilesi.instrumentation.models.TraceData; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +public class VariableStackHandler { + // The map of instance ids to variable indexes + private final HashMap mapOfInstancesToIndexes = new HashMap<>(); + // The list of instance ids we already defined + private final List listOfDefinedInstances = new ArrayList<>(); + // The currently free index for variables to define in our java source code + private int varIndex = 0; + + public String getInstanceVarName(int instanceId) { + int i; + + if (mapOfInstancesToIndexes.containsKey(instanceId)) { + i = mapOfInstancesToIndexes.get(instanceId); + } else { + i = varIndex++; + mapOfInstancesToIndexes.put(instanceId, i); + } + + return "var%d".formatted(i); + } + + public String serializableDataToCode(TraceData arg) { + if (arg == null) { + return "null"; + } else if (arg.getDataAsJson() != null) { + return SerializationUtils.serializableDataToJava(arg); + } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { + return getInstanceVarName(arg.getInstanceId()); + } else { + return "/* Unserializable Instance with Id: %d */".formatted(arg.getInstanceId()); + } + } + + public String getReturnStatementAsCode(TraceData serializableData) { + if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { + return getInstanceVarName(serializableData.getInstanceId()); + } else { + String returnType = SerializationUtils.getCleanedType(serializableData.getFullyQualifiedTypeName()); + listOfDefinedInstances.add(serializableData.getInstanceId()); + return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); + } + } +} From 7a802da22b11aa505134ae33e7b5226f4f0cbd95 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 13:11:06 +0100 Subject: [PATCH 068/244] fix: use formatted when possible --- .../github/maracas/gilesi/traceview/VariableStackHandler.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java index 107a9f1d..6fec891d 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java @@ -45,7 +45,7 @@ public String getReturnStatementAsCode(TraceData serializableData) { } else { String returnType = SerializationUtils.getCleanedType(serializableData.getFullyQualifiedTypeName()); listOfDefinedInstances.add(serializableData.getInstanceId()); - return returnType + " " + getInstanceVarName(serializableData.getInstanceId()); + return "%s %s".formatted(returnType, getInstanceVarName(serializableData.getInstanceId())); } } } From deb89a2860f3f4208a46ad92c50ce007bd4306d2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 14:02:21 +0100 Subject: [PATCH 069/244] fix: rewrite parts of the code generator --- .../instrumentation/TraceCollector.java | 2 +- .../instrumentation/TraceDataFactory.java | 2 +- .../github/maracas/gilesi/traceview/Main.java | 2 +- .../gilesi/traceview/SerializationUtils.java | 19 ++-- .../gilesi/traceview/TestMethodGenerator.java | 90 ++++++++++++------- .../traceview/VariableStackHandler.java | 45 +++------- 6 files changed, 88 insertions(+), 72 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index ec58e30a..9a6752f4 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -48,7 +48,7 @@ public static Collection getMethodTraces() { public static void SaveTraceResults() { File outputFile = new File("MethodTraces.json"); System.out.println("Saving trace results in progress..."); - System.out.println("Output location: " + outputFile.getAbsolutePath()); + System.out.printf("Output location: %s%n", outputFile.getAbsolutePath()); Agent.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 88a91520..6b80abfa 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -28,7 +28,7 @@ public static TraceData valueOf(Object object) { try { serializedString = Agent.objectMapper.writeValueAsString(object); } catch (JsonProcessingException e) { - System.err.println("ERROR: Cannot serialize specific argument: " + e); + System.err.printf("ERROR: Cannot serialize specific argument: %s%n", e); } return new TraceData(objectClassName, serializedString, instanceId); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index a44749d7..89b03a4c 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -28,7 +28,7 @@ private static List getTraceEventsFromTraces(Trace[] methodTraces) { return events.stream().sorted(Comparator.comparing(TraceEvent::At)).toList(); } - public static void main(String[] args) throws IOException { + public static void main(String[] args) throws Exception { TestTraceResults[] testTraceResultsList = readTraces(args[0]); for (TestTraceResults testTraceResults : testTraceResultsList) { TestMethodGenerator testMethodGenerator = new TestMethodGenerator(); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java index eda403d6..e9b05484 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java @@ -22,13 +22,18 @@ private static String JvmTypeToLangType(String name) throws Exception { } public static String getCleanedType(String FQN) { - if ((FQN.contains("/") || FQN.startsWith("[") || FQN.endsWith(";")) && - (FQN.startsWith("I") || FQN.startsWith("V") || - FQN.startsWith("Z") || FQN.startsWith("B") || - FQN.startsWith("C") || FQN.startsWith("S") || - FQN.startsWith("D") || FQN.startsWith("F") || - FQN.startsWith("J") || FQN.startsWith("L") || - FQN.startsWith("["))) { + int currentCharacterIndex = 0; + char currentCharacter = FQN.charAt(currentCharacterIndex); + while (currentCharacter == '[') { + currentCharacter = FQN.charAt(++currentCharacterIndex); + } + + if (((currentCharacter == 'I' || currentCharacter == 'V' || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN); } catch (Exception ignored) { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 305402eb..3d029928 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -9,62 +9,92 @@ public class TestMethodGenerator { private final VariableStackHandler variableStackHandler = new VariableStackHandler(); - private String traceToCode(Trace methodTrace) { - String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; - cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - - boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); - boolean isInstanceCall = methodTrace.getInstance() != null && !methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + public String serializableDataToCode(TraceData arg) throws Exception { + if (arg == null) { + return "null"; + } else if (arg.getDataAsJson() != null) { + return SerializationUtils.serializableDataToJava(arg); + } else if (variableStackHandler.isInstanceVariableNameDefined(arg.getInstanceId())) { + return variableStackHandler.getInstanceVariableName(arg.getInstanceId()); + } else { + return "/* Unserializable Instance with Id: %d */".formatted(arg.getInstanceId()); + } + } - if (isConstructor) { - cleanedMethodName = "new %s".formatted(cleanedMethodName); - } else if (isInstanceCall) { - String methodNameOnly = cleanedMethodName.split("\\.")[cleanedMethodName.split("\\.").length - 1]; - cleanedMethodName = "%s.%s".formatted(variableStackHandler.getInstanceVarName(methodTrace.getInstance().getInstanceId()), methodNameOnly); + public String getDataVariableDeclaration(TraceData serializableData) throws Exception { + if (variableStackHandler.isInstanceVariableNameDefined(serializableData.getInstanceId())) { + return variableStackHandler.getInstanceVariableName(serializableData.getInstanceId()); + } else { + String returnType = SerializationUtils.getCleanedType(serializableData.getFullyQualifiedTypeName()); + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.getInstanceId()); + return "%s %s".formatted(returnType, instanceVariableName); } + } + + private String traceToCode(Trace methodTrace) throws Exception { + String methodName = methodTrace.getMethodSignature().split("\\(")[0]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1]; + + TraceData traceData = methodTrace.getInstance(); + + boolean isConstructor = traceData != null && traceData.getFullyQualifiedTypeName().equals(methodName); + boolean isInstanceCall = traceData != null && !traceData.getFullyQualifiedTypeName().equals(methodName); + + String methodCall = methodName; if (isConstructor) { + methodCall = "new %s".formatted(methodCall); + // TODO: we need to fix the tracer so for constructors we get to return an instance, and instead leave instance field empty, to make more sense and simplify this part too!! // TODO: also we may want seen indexes to keep the order in the json in general for traces, like which index we added something at for sanity, can be useful when ordering things properly! // TODO: last but not least, we can return instances that either previously existed or never did. // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? // Value returned is of course, the instance! + String argumentVariable = getDataVariableDeclaration(traceData); + methodCall = "%s = %s".formatted(argumentVariable, methodCall); + } else if (isInstanceCall) { + String instanceMethodCallName = methodCall.split("\\.")[methodCall.split("\\.").length - 1]; + String instanceVariableName = variableStackHandler.getInstanceVariableName(traceData.getInstanceId()); + methodCall = "%s.%s".formatted(instanceVariableName, instanceMethodCallName); + } - cleanedMethodName = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(methodTrace.getInstance()), cleanedMethodName); - } else if (methodTrace.getReturnedValue() != null) { + if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - cleanedMethodName = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(methodTrace.getReturnedValue()), cleanedMethodName); + String argumentVariable = getDataVariableDeclaration(methodTrace.getReturnedValue()); + methodCall = "%s = %s".formatted(argumentVariable, methodCall); } List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { - String argumentValueAsCode = variableStackHandler.serializableDataToCode(arg); - String argumentDeclaration = "%s = %s".formatted(variableStackHandler.getReturnStatementAsCode(arg), argumentValueAsCode); - - argList.add(variableStackHandler.getInstanceVarName(arg.getInstanceId())); - cleanedMethodName = ("%s;\n" + - "\t\t%s").formatted(argumentDeclaration, cleanedMethodName); + String argumentValue = serializableDataToCode(arg); + String argumentVariable = getDataVariableDeclaration(arg); + String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); + + argList.add(variableStackHandler.getInstanceVariableName(arg.getInstanceId())); + // Define the variable before the method + methodCall = ("%s;\n" + + "\t\t%s").formatted(argumentDeclaration, methodCall); } - return "%s(%s);".formatted(cleanedMethodName, String.join(",", argList)); + return "%s(%s);".formatted(methodCall, String.join(",", argList)); } - private String traceArgumentsToAssert(Trace methodTrace) { + private String traceArgumentsToAssert(Trace methodTrace) throws Exception { List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPostCallArguments()) { - String argumentValueAsCode = variableStackHandler.serializableDataToCode(arg); + String argumentValueAsCode = serializableDataToCode(arg); if (argumentValueAsCode.endsWith("[].class)")) { - argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVarName(arg.getInstanceId()))); + argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVariableName(arg.getInstanceId()))); } else { - argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVarName(arg.getInstanceId()))); + argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVariableName(arg.getInstanceId()))); } } return String.join("\n\t\t", argList); } - private String traceToAssert(Trace methodTrace) { + private String traceToAssert(Trace methodTrace) throws Exception { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); @@ -73,18 +103,18 @@ private String traceToAssert(Trace methodTrace) { // Nothing to do! } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - String returnValueAsCode = variableStackHandler.serializableDataToCode(methodTrace.getReturnedValue()); + String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); if (returnValueAsCode.endsWith("[].class)")) { - return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVariableName(methodTrace.getReturnedValue().getInstanceId())); } else { - return "assertEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVarName(methodTrace.getReturnedValue().getInstanceId())); + return "assertEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVariableName(methodTrace.getReturnedValue().getInstanceId())); } } return null; } - public void printTraceAsCode(TraceEvent event) { + public void printTraceAsCode(TraceEvent event) throws Exception { Trace trace = event.About(); String methodCallLine = traceToCode(trace); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java index 6fec891d..ea0d0813 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java @@ -1,51 +1,32 @@ package com.github.maracas.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.models.TraceData; - -import java.util.ArrayList; import java.util.HashMap; -import java.util.List; public class VariableStackHandler { // The map of instance ids to variable indexes private final HashMap mapOfInstancesToIndexes = new HashMap<>(); - // The list of instance ids we already defined - private final List listOfDefinedInstances = new ArrayList<>(); // The currently free index for variables to define in our java source code private int varIndex = 0; - public String getInstanceVarName(int instanceId) { - int i; - - if (mapOfInstancesToIndexes.containsKey(instanceId)) { - i = mapOfInstancesToIndexes.get(instanceId); - } else { - i = varIndex++; - mapOfInstancesToIndexes.put(instanceId, i); + public String getInstanceVariableName(int instanceId) throws Exception { + if (isInstanceVariableNameDefined(instanceId)) { + return "var%d".formatted(mapOfInstancesToIndexes.get(instanceId)); } - return "var%d".formatted(i); + throw new Exception("Instance Id is not already defined"); } - public String serializableDataToCode(TraceData arg) { - if (arg == null) { - return "null"; - } else if (arg.getDataAsJson() != null) { - return SerializationUtils.serializableDataToJava(arg); - } else if (mapOfInstancesToIndexes.containsKey(arg.getInstanceId())) { - return getInstanceVarName(arg.getInstanceId()); - } else { - return "/* Unserializable Instance with Id: %d */".formatted(arg.getInstanceId()); + public String newInstanceVariableName(int instanceId) throws Exception { + if (!isInstanceVariableNameDefined(instanceId)) { + int i = ++varIndex; + mapOfInstancesToIndexes.put(instanceId, i); + return "var%d".formatted(i); } + + throw new Exception("Instance Id is already defined"); } - public String getReturnStatementAsCode(TraceData serializableData) { - if (listOfDefinedInstances.contains(serializableData.getInstanceId())) { - return getInstanceVarName(serializableData.getInstanceId()); - } else { - String returnType = SerializationUtils.getCleanedType(serializableData.getFullyQualifiedTypeName()); - listOfDefinedInstances.add(serializableData.getInstanceId()); - return "%s %s".formatted(returnType, getInstanceVarName(serializableData.getInstanceId())); - } + public boolean isInstanceVariableNameDefined(int instanceId) { + return mapOfInstancesToIndexes.containsKey(instanceId); } } From 3e37fa6239ed70181733e2070d584b15545781d4 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 14:10:56 +0100 Subject: [PATCH 070/244] cleanup unused code --- .../gilesi/samples/samplelibrary/Foo.java | 1 - .../gilesi/samples/samplelibrary/Foo2.java | 1 - .../github/maracas/gilesi/traceview/Main.java | 28 ++++----------- .../gilesi/traceview/TestMethodGenerator.java | 34 ++++++++----------- .../maracas/gilesi/traceview/TraceEvent.java | 7 ---- 5 files changed, 21 insertions(+), 50 deletions(-) delete mode 100644 TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java index 6ebdd838..004ca3af 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java @@ -2,7 +2,6 @@ import java.util.Arrays; import java.util.Collection; -import java.util.stream.Collectors; public class Foo { public static String SomeValueStoredHere = "ha"; diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java index 32e2b8b3..80cc7930 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java @@ -2,7 +2,6 @@ import java.util.Arrays; import java.util.Collection; -import java.util.stream.Collectors; public class Foo2 { public static String SomeValueStoredHere = "ha"; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 89b03a4c..f8e5f747 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -6,10 +6,7 @@ import java.io.File; import java.io.IOException; -import java.util.ArrayList; import java.util.Arrays; -import java.util.Comparator; -import java.util.List; public class Main { private static TestTraceResults[] readTraces(String filePathStr) throws IOException { @@ -17,23 +14,12 @@ private static TestTraceResults[] readTraces(String filePathStr) throws IOExcept return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); } - private static List getTraceEventsFromTraces(Trace[] methodTraces) { - List events = new ArrayList<>(); - - for (Trace methodTrace : methodTraces) { - events.add(new TraceEvent("Entry", methodTrace.getTimeStampEntry(), methodTrace)); - events.add(new TraceEvent("Exit", methodTrace.getTimeStampExit(), methodTrace)); - } - - return events.stream().sorted(Comparator.comparing(TraceEvent::At)).toList(); - } - public static void main(String[] args) throws Exception { TestTraceResults[] testTraceResultsList = readTraces(args[0]); for (TestTraceResults testTraceResults : testTraceResultsList) { - TestMethodGenerator testMethodGenerator = new TestMethodGenerator(); + VariableStackHandler variableStackHandler = new VariableStackHandler(); - var splitTestName = testTraceResults.Test.split("\\."); + String[] splitTestName = testTraceResults.Test.split("\\."); String packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); String className = splitTestName[splitTestName.length - 2]; @@ -56,14 +42,12 @@ public static void main(String[] args) throws Exception { System.out.printf("\tpublic void %s() throws JsonProcessingException {%n", testName); Trace[] methodTraces = testTraceResults.Traces; - List eventsSortedByTimeStamp = getTraceEventsFromTraces(methodTraces); - TraceEvent[] entryTraceEvents = eventsSortedByTimeStamp.stream().filter(event -> event.What().equals("Entry")).toArray(TraceEvent[]::new); - for (int i = 0; i < entryTraceEvents.length; i++) { - TraceEvent event = entryTraceEvents[i]; - testMethodGenerator.printTraceAsCode(event); + for (int i = 0; i < methodTraces.length; i++) { + Trace trace = methodTraces[i]; + TestMethodGenerator.printTraceAsCode(trace, variableStackHandler); - if (i != entryTraceEvents.length - 1) { + if (i != methodTraces.length - 1) { System.out.println(); } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 3d029928..0d116254 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -7,9 +7,7 @@ import java.util.List; public class TestMethodGenerator { - private final VariableStackHandler variableStackHandler = new VariableStackHandler(); - - public String serializableDataToCode(TraceData arg) throws Exception { + private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler) throws Exception { if (arg == null) { return "null"; } else if (arg.getDataAsJson() != null) { @@ -21,7 +19,7 @@ public String serializableDataToCode(TraceData arg) throws Exception { } } - public String getDataVariableDeclaration(TraceData serializableData) throws Exception { + private static String getDataVariableDeclaration(TraceData serializableData, VariableStackHandler variableStackHandler) throws Exception { if (variableStackHandler.isInstanceVariableNameDefined(serializableData.getInstanceId())) { return variableStackHandler.getInstanceVariableName(serializableData.getInstanceId()); } else { @@ -31,7 +29,7 @@ public String getDataVariableDeclaration(TraceData serializableData) throws Exce } } - private String traceToCode(Trace methodTrace) throws Exception { + private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { String methodName = methodTrace.getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1]; @@ -51,7 +49,7 @@ private String traceToCode(Trace methodTrace) throws Exception { // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? // Value returned is of course, the instance! - String argumentVariable = getDataVariableDeclaration(traceData); + String argumentVariable = getDataVariableDeclaration(traceData, variableStackHandler); methodCall = "%s = %s".formatted(argumentVariable, methodCall); } else if (isInstanceCall) { String instanceMethodCallName = methodCall.split("\\.")[methodCall.split("\\.").length - 1]; @@ -61,14 +59,14 @@ private String traceToCode(Trace methodTrace) throws Exception { if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - String argumentVariable = getDataVariableDeclaration(methodTrace.getReturnedValue()); + String argumentVariable = getDataVariableDeclaration(methodTrace.getReturnedValue(), variableStackHandler); methodCall = "%s = %s".formatted(argumentVariable, methodCall); } List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { - String argumentValue = serializableDataToCode(arg); - String argumentVariable = getDataVariableDeclaration(arg); + String argumentValue = serializableDataToCode(arg, variableStackHandler); + String argumentVariable = getDataVariableDeclaration(arg, variableStackHandler); String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); argList.add(variableStackHandler.getInstanceVariableName(arg.getInstanceId())); @@ -80,10 +78,10 @@ private String traceToCode(Trace methodTrace) throws Exception { return "%s(%s);".formatted(methodCall, String.join(",", argList)); } - private String traceArgumentsToAssert(Trace methodTrace) throws Exception { + private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { List argList = new ArrayList<>(); for (TraceData arg : methodTrace.getPostCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg); + String argumentValueAsCode = serializableDataToCode(arg, variableStackHandler); if (argumentValueAsCode.endsWith("[].class)")) { argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVariableName(arg.getInstanceId()))); } else { @@ -94,7 +92,7 @@ private String traceArgumentsToAssert(Trace methodTrace) throws Exception { return String.join("\n\t\t", argList); } - private String traceToAssert(Trace methodTrace) throws Exception { + private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); @@ -103,7 +101,7 @@ private String traceToAssert(Trace methodTrace) throws Exception { // Nothing to do! } else if (methodTrace.getReturnedValue() != null) { // We return a value that we managed to serialize - String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue()); + String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue(), variableStackHandler); if (returnValueAsCode.endsWith("[].class)")) { return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVariableName(methodTrace.getReturnedValue().getInstanceId())); } else { @@ -114,12 +112,10 @@ private String traceToAssert(Trace methodTrace) throws Exception { return null; } - public void printTraceAsCode(TraceEvent event) throws Exception { - Trace trace = event.About(); - - String methodCallLine = traceToCode(trace); - String returnAssertionLine = traceToAssert(trace); - String postCallParameterAssertionLine = traceArgumentsToAssert(trace); + public static void printTraceAsCode(Trace trace, VariableStackHandler variableStackHandler) throws Exception { + String methodCallLine = traceToCode(trace, variableStackHandler); + String returnAssertionLine = traceToAssert(trace, variableStackHandler); + String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler); if (methodCallLine != null && !methodCallLine.isEmpty()) { System.out.printf("\t\t%s%n", methodCallLine); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java deleted file mode 100644 index 083a5418..00000000 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TraceEvent.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.maracas.gilesi.traceview; - -import com.github.maracas.gilesi.instrumentation.models.Trace; - -public record TraceEvent(String What, long At, Trace About) { - -} From 609643bd5482e451d752d33c52a27df98c974d52 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 14:14:50 +0100 Subject: [PATCH 071/244] Cleanup more duplicated code --- .../gilesi/traceview/TestMethodGenerator.java | 33 ++++++++++--------- 1 file changed, 18 insertions(+), 15 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 0d116254..4be83c7a 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -78,15 +78,22 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab return "%s(%s);".formatted(methodCall, String.join(",", argList)); } + private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler) throws Exception { + String valueAsCode = serializableDataToCode(traceData, variableStackHandler); + int instanceId = traceData.getInstanceId(); + if (valueAsCode.endsWith("[].class)")) { + return "assertArrayEquals(%s, %s);".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); + } else { + return "assertEquals(%s, %s);".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); + } + } + private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { List argList = new ArrayList<>(); - for (TraceData arg : methodTrace.getPostCallArguments()) { - String argumentValueAsCode = serializableDataToCode(arg, variableStackHandler); - if (argumentValueAsCode.endsWith("[].class)")) { - argList.add("assertArrayEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVariableName(arg.getInstanceId()))); - } else { - argList.add("assertEquals(%s, %s);".formatted(argumentValueAsCode, variableStackHandler.getInstanceVariableName(arg.getInstanceId()))); - } + + for (TraceData traceData : methodTrace.getPostCallArguments()) { + // We return a value that we managed to serialize + argList.add(getAssertionCodeLine(traceData, variableStackHandler)); } return String.join("\n\t\t", argList); @@ -97,16 +104,12 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + TraceData traceData = methodTrace.getReturnedValue(); + if (isConstructor) { // Nothing to do! - } else if (methodTrace.getReturnedValue() != null) { - // We return a value that we managed to serialize - String returnValueAsCode = serializableDataToCode(methodTrace.getReturnedValue(), variableStackHandler); - if (returnValueAsCode.endsWith("[].class)")) { - return "assertArrayEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVariableName(methodTrace.getReturnedValue().getInstanceId())); - } else { - return "assertEquals(%s, %s);".formatted(returnValueAsCode, variableStackHandler.getInstanceVariableName(methodTrace.getReturnedValue().getInstanceId())); - } + } else if (traceData != null) { + return getAssertionCodeLine(traceData, variableStackHandler); } return null; From 933a99156e688c87b6805966c0c1e7227cd194ec Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 14:22:37 +0100 Subject: [PATCH 072/244] fix: rewrite trace generation to not print in the console --- .../github/maracas/gilesi/traceview/Main.java | 3 ++- .../gilesi/traceview/TestMethodGenerator.java | 16 ++++++++++++---- 2 files changed, 14 insertions(+), 5 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index f8e5f747..566ebc81 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -45,7 +45,8 @@ public static void main(String[] args) throws Exception { for (int i = 0; i < methodTraces.length; i++) { Trace trace = methodTraces[i]; - TestMethodGenerator.printTraceAsCode(trace, variableStackHandler); + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler); + System.out.println(traceCode); if (i != methodTraces.length - 1) { System.out.println(); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 4be83c7a..cb8f486f 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -115,21 +115,29 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari return null; } - public static void printTraceAsCode(Trace trace, VariableStackHandler variableStackHandler) throws Exception { + public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler) throws Exception { String methodCallLine = traceToCode(trace, variableStackHandler); String returnAssertionLine = traceToAssert(trace, variableStackHandler); String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler); + String traceCode = ""; + if (methodCallLine != null && !methodCallLine.isEmpty()) { - System.out.printf("\t\t%s%n", methodCallLine); + traceCode += String.format("\t\t%s\n", methodCallLine); } if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - System.out.printf("\t\t%s%n", returnAssertionLine); + traceCode += String.format("\t\t%s\n", returnAssertionLine); } if (!postCallParameterAssertionLine.isEmpty()) { - System.out.printf("\t\t%s%n", postCallParameterAssertionLine); + traceCode += String.format("\t\t%s\n", postCallParameterAssertionLine); + } + + while (traceCode.endsWith("\n")) { + traceCode = traceCode.substring(0, traceCode.length() - 1); } + + return traceCode; } } \ No newline at end of file From 8b5d83ebe42e9767e83f320f4c4da30a025450bf Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 14:37:17 +0100 Subject: [PATCH 073/244] codegen: allow specifying custom indentation --- .../github/maracas/gilesi/traceview/Main.java | 2 +- .../gilesi/traceview/TestMethodGenerator.java | 36 ++++++++++++------- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 566ebc81..ac715bcf 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -45,7 +45,7 @@ public static void main(String[] args) throws Exception { for (int i = 0; i < methodTraces.length; i++) { Trace trace = methodTraces[i]; - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler); + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t"); System.out.println(traceCode); if (i != methodTraces.length - 1) { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index cb8f486f..319143ca 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -29,7 +29,7 @@ private static String getDataVariableDeclaration(TraceData serializableData, Var } } - private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { + private static String traceToMethodCall(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { String methodName = methodTrace.getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1]; @@ -63,19 +63,31 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab methodCall = "%s = %s".formatted(argumentVariable, methodCall); } + return methodCall; + } + + private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws Exception { + String methodCall = traceToMethodCall(methodTrace, variableStackHandler); + List argList = new ArrayList<>(); + List variableList = new ArrayList<>(); + for (TraceData arg : methodTrace.getPreCallArguments()) { String argumentValue = serializableDataToCode(arg, variableStackHandler); String argumentVariable = getDataVariableDeclaration(arg, variableStackHandler); String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); argList.add(variableStackHandler.getInstanceVariableName(arg.getInstanceId())); + // Define the variable before the method - methodCall = ("%s;\n" + - "\t\t%s").formatted(argumentDeclaration, methodCall); + variableList.add("%s;".formatted(argumentDeclaration)); } - return "%s(%s);".formatted(methodCall, String.join(",", argList)); + String argumentParameters = String.join(",", argList); + String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); + variableList.add(methodCallCode); + + return String.join("\n%s".formatted(indentationPrefix), variableList); } private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler) throws Exception { @@ -88,7 +100,7 @@ private static String getAssertionCodeLine(TraceData traceData, VariableStackHan } } - private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { + private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws Exception { List argList = new ArrayList<>(); for (TraceData traceData : methodTrace.getPostCallArguments()) { @@ -96,7 +108,7 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan argList.add(getAssertionCodeLine(traceData, variableStackHandler)); } - return String.join("\n\t\t", argList); + return String.join("\n%s".formatted(indentationPrefix), argList); } private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { @@ -115,23 +127,23 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari return null; } - public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler) throws Exception { - String methodCallLine = traceToCode(trace, variableStackHandler); + public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix) throws Exception { + String methodCallLine = traceToCode(trace, variableStackHandler, indentationPrefix); String returnAssertionLine = traceToAssert(trace, variableStackHandler); - String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler); + String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler, indentationPrefix); String traceCode = ""; if (methodCallLine != null && !methodCallLine.isEmpty()) { - traceCode += String.format("\t\t%s\n", methodCallLine); + traceCode += String.format("%s%s\n", indentationPrefix, methodCallLine); } if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - traceCode += String.format("\t\t%s\n", returnAssertionLine); + traceCode += String.format("%s%s\n", indentationPrefix, returnAssertionLine); } if (!postCallParameterAssertionLine.isEmpty()) { - traceCode += String.format("\t\t%s\n", postCallParameterAssertionLine); + traceCode += String.format("%s%s\n", indentationPrefix, postCallParameterAssertionLine); } while (traceCode.endsWith("\n")) { From afb538e4e481c69c8c3912224617702c8b689539 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 21 Feb 2024 15:37:17 +0100 Subject: [PATCH 074/244] Update maracas test --- MaracasConfiguration.json | 1706 +++++++++-------- .../gilesi/traceview/TestMethodGenerator.java | 12 +- maracas-test.cmd | 23 + 3 files changed, 903 insertions(+), 838 deletions(-) diff --git a/MaracasConfiguration.json b/MaracasConfiguration.json index 156cf699..9b807c1c 100644 --- a/MaracasConfiguration.json +++ b/MaracasConfiguration.json @@ -1,839 +1,871 @@ { - "ClassesToInstrument": [ - { - "ClassName": "com.github.maracas.visitors.FieldNowFinalVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldNowFinalVisitor", - "ClassMethodsOrConstructors": [ - "visitCtFieldWrite" - ] - }, - { - "ClassName": "com.github.maracas.visitors.CombinedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.CombinedVisitor", - "ClassMethodsOrConstructors": [ - "getBrokenUses", - "visitCtAnnotation", - "visitCtAnnotationFieldAccess", - "visitCtAnnotationMethod", - "visitCtAnnotationType", - "visitCtAnonymousExecutable", - "visitCtArrayRead", - "visitCtArrayTypeReference", - "visitCtArrayWrite", - "visitCtAssert", - "visitCtAssignment", - "visitCtBinaryOperator", - "visitCtBlock", - "visitCtBreak", - "visitCtCase", - "visitCtCatch", - "visitCtCatchVariable", - "visitCtCatchVariableReference", - "visitCtClass", - "visitCtCodeSnippetExpression", - "visitCtCodeSnippetStatement", - "visitCtComment", - "visitCtCompilationUnit", - "visitCtConditional", - "visitCtConstructor", - "visitCtConstructorCall", - "visitCtContinue", - "visitCtDo", - "visitCtEnum", - "visitCtEnumValue", - "visitCtExecutableReference", - "visitCtExecutableReferenceExpression", - "visitCtField", - "visitCtFieldRead", - "visitCtFieldReference", - "visitCtFieldWrite", - "visitCtFor", - "visitCtForEach", - "visitCtIf", - "visitCtImport", - "visitCtInterface", - "visitCtIntersectionTypeReference", - "visitCtInvocation", - "visitCtJavaDoc", - "visitCtJavaDocTag", - "visitCtLambda", - "visitCtLiteral", - "visitCtLocalVariable", - "visitCtLocalVariableReference", - "visitCtMethod", - "visitCtModule", - "visitCtModuleReference", - "visitCtModuleRequirement", - "visitCtNewArray", - "visitCtNewClass", - "visitCtOperatorAssignment", - "visitCtPackage", - "visitCtPackageDeclaration", - "visitCtPackageExport", - "visitCtPackageReference", - "visitCtParameter", - "visitCtParameterReference", - "visitCtProvidedService", - "visitCtReturn", - "visitCtStatementList", - "visitCtSuperAccess", - "visitCtSwitch", - "visitCtSwitchExpression", - "visitCtSynchronized", - "visitCtTextBlock", - "visitCtThisAccess", - "visitCtThrow", - "visitCtTry", - "visitCtTryWithResource", - "visitCtTypeAccess", - "visitCtTypeMemberWildcardImportReference", - "visitCtTypeParameter", - "visitCtTypeParameterReference", - "visitCtTypeReference", - "visitCtUnaryOperator", - "visitCtUnboundVariableReference", - "visitCtUsedService", - "visitCtVariableRead", - "visitCtVariableWrite", - "visitCtWhile", - "visitCtWildcardReference", - "visitCtYieldStatement" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.LibraryJar", - "ClassMethodsOrConstructors": [ - "buildModel", - "equals", - "getClasspath", - "getJar", - "getLabel", - "getSources", - "hasSources", - "hashCode", - "setNoClasspath", - "setSources", - "toString", - "withSources", - "withoutSources" - ] - }, - { - "ClassName": "com.github.maracas.delta.AbstractBreakingChange.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.AbstractBreakingChange", - "ClassMethodsOrConstructors": [ - "getChange", - "getSourceElement", - "setSourceElement" - ] - }, - { - "ClassName": "com.github.maracas.util.SpoonHelpers", - "ClassMethodsOrConstructors": [ - "buildSpoonSignature", - "firstLocatableParent", - "fullyQualifiedName", - "getEnclosingPkgName", - "isImplicit", - "matchingSignatures" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldLessAccessibleVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldLessAccessibleVisitor", - "ClassMethodsOrConstructors": [ - "visitCtFieldRead", - "visitCtFieldWrite" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldReferenceVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldReferenceVisitor", - "ClassMethodsOrConstructors": [ - "visitCtFieldReference" - ] - }, - { - "ClassName": "com.github.maracas.util.PathHelpers", - "ClassMethodsOrConstructors": [ - "isValidDirectory", - "isValidJar" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldTypeChangedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldTypeChangedVisitor", - "ClassMethodsOrConstructors": [ - "visitCtFieldRead", - "visitCtFieldWrite" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodAddedToInterfaceVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodAddedToInterfaceVisitor", - "ClassMethodsOrConstructors": [ - "visitCtClass" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SupertypeRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SupertypeRemovedVisitor", - "ClassMethodsOrConstructors": [ - "visitCtAssignment", - "visitCtFieldReference", - "visitCtInvocation", - "visitCtLocalVariable", - "visitCtMethod" - ] - }, - { - "ClassName": "com.github.maracas.brokenuse.APIUse.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldNowStaticVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.BinaryToSourceMapper.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.BinaryToSourceMapper", - "ClassMethodsOrConstructors": [ - "resolve" - ] - }, - { - "ClassName": "com.github.maracas.visitors.InterfaceAddedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.InterfaceRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.CtElementSerializer.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.CtElementSerializer", - "ClassMethodsOrConstructors": [ - "serialize" - ] - }, - { - "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToFieldVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowAbstractVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowAbstractVisitor", - "ClassMethodsOrConstructors": [ - "visitCtConstructorCall" - ] - }, - { - "ClassName": "com.github.maracas.MaracasOptions.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.MaracasOptions", - "ClassMethodsOrConstructors": [ - "defaultJApiOptions", - "excludeBreakingChange", - "getBuildTimeout", - "getClientsPerModule", - "getCloneTimeout", - "getExcludedBreakingChanges", - "getJApiOptions", - "getMaxClassLines", - "getMinStarsPerClient", - "newDefault", - "setBuildTimeout", - "setClientsPerModule", - "setCloneTimeout", - "setMaxClassLines", - "setMinStarsPerClient" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor", - "ClassMethodsOrConstructors": [ - "visitCtThrow" - ] - }, - { - "ClassName": "com.github.maracas.util.ParentLastURLClassLoader.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.ParentLastURLClassLoader", - "ClassMethodsOrConstructors": [ - "loadClass" - ] - }, - { - "ClassName": "com.github.maracas.delta.Delta.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.Delta", - "ClassMethodsOrConstructors": [ - "fromJApiCmpDelta", - "getBreakingChanges", - "getNewVersion", - "getOldVersion", - "getVisitors", - "isEmpty", - "populateLocations", - "toJson", - "toString" - ] - }, - { - "ClassName": "com.github.maracas.Maracas.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.Maracas", - "ClassMethodsOrConstructors": [ - "analyze", - "computeDelta", - "computeDeltaImpact" - ] - }, - { - "ClassName": "com.github.maracas.AnalysisQuery", - "ClassMethodsOrConstructors": [ - "builder", - "getClients", - "getMaracasOptions", - "getNewVersion", - "getOldVersion" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodNowFinalVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodNowFinalVisitor", - "ClassMethodsOrConstructors": [ - "visitCtMethod" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SuperclassRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodReturnTypeChangedVisitor", - "ClassMethodsOrConstructors": [ - "visitCtInvocation", - "visitCtMethod" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ConstructorRemovedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ConstructorRemovedVisitor", - "ClassMethodsOrConstructors": [ - "visitCtConstructorCall", - "visitCtInvocation", - "visitCtNewClass" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowFinalVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassNowFinalVisitor", - "ClassMethodsOrConstructors": [ - "visitCtClass", - "visitCtNewClass" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SupertypeAddedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SupertypeAddedVisitor", - "ClassMethodsOrConstructors": [ - "visitCtClass" - ] - }, - { - "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToClassVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.SpoonTypeHelpers", - "ClassMethodsOrConstructors": [ - "haveUnimplAbstractMethods", - "inferExpectedType", - "isAssignableFrom", - "isAssignableFromOverride", - "isBoxedType", - "isNarrowedPrimitiveType", - "isNarrowedType", - "isSubtype", - "isUnboxedType", - "isWidenedPrimitiveType", - "isWidenedType" - ] - }, - { - "ClassName": "com.github.maracas.delta.JApiCmpToSpoonVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.JApiCmpToSpoonVisitor", - "ClassMethodsOrConstructors": [ - "getBreakingChanges", - "visit" - ] - }, - { - "ClassName": "com.github.maracas.util.GradleLauncher.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.util.GradleLauncher", - "ClassMethodsOrConstructors": [ - "init" - ] - }, - { - "ClassName": "com.github.maracas.SourcesDirectory", - "ClassMethodsOrConstructors": [ - "buildModel", - "equals", - "getLocation", - "hashCode", - "of", - "setClasspath", - "toString" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldNoLongerStaticVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.FieldNoLongerStaticVisitor", - "ClassMethodsOrConstructors": [ - "visitCtFieldRead", - "visitCtFieldWrite" - ] - }, - { - "ClassName": "com.github.maracas.visitors.SuperclassAddedVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.TypeReferenceVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.TypeReferenceVisitor", - "ClassMethodsOrConstructors": [ - "visitCtTypeReference" - ] - }, - { - "ClassName": "com.github.maracas.delta.FieldBreakingChange.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.FieldBreakingChange", - "ClassMethodsOrConstructors": [ - "getReference", - "getVisitor" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassLessAccessibleVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.ClassLessAccessibleVisitor", - "ClassMethodsOrConstructors": [ - "visitCtTypeReference" - ] - }, - { - "ClassName": "com.github.maracas.AnalysisQuery$Builder", - "ClassMethodsOrConstructors": [ - "build", - "client", - "clients", - "exclude", - "newVersion", - "of", - "oldVersion", - "options" - ] - }, - { - "ClassName": "com.github.maracas.MaracasCLI.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.MaracasCLI", - "ClassMethodsOrConstructors": [ - "main", - "run" - ] - }, - { - "ClassName": "com.github.maracas.delta.TypeBreakingChange.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.TypeBreakingChange", - "ClassMethodsOrConstructors": [ - "getReference", - "getVisitor" - ] - }, - { - "ClassName": "com.github.maracas.visitors.BreakingChangeVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.BreakingChangeVisitor", - "ClassMethodsOrConstructors": [ - "brokenUse", - "getAPIUseByRole", - "getBrokenUses" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodNowAbstractVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodNowAbstractVisitor", - "ClassMethodsOrConstructors": [ - "visitCtClass", - "visitCtInvocation" - ] - }, - { - "ClassName": "com.github.maracas.delta.JApiCmpDeltaFilter.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.JApiCmpDeltaFilter", - "ClassMethodsOrConstructors": [ - "filter" - ] - }, - { - "ClassName": "com.github.maracas.delta.MethodBreakingChange.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.delta.MethodBreakingChange", - "ClassMethodsOrConstructors": [ - "getReference", - "getVisitor" - ] - }, - { - "ClassName": "com.github.maracas.visitors.AnnotationDeprecatedAddedToMethodVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodReferenceVisitor.", - "ClassMethodsOrConstructors": [ - "" - ] - }, - { - "ClassName": "com.github.maracas.visitors.MethodReferenceVisitor", - "ClassMethodsOrConstructors": [ - "visitCtInvocation", - "visitCtMethod" - ] - }, - { - "ClassName": "com.github.maracas.forges.analysis.CommitAnalyzerIT", - "ClassMethodsOrConstructors": [ - "analyzeCommits_GumTree", - "analyzeCommits_fixture_moduleA", - "analyzeCommits_fixture_nestedB", - "computeDelta_maracas_withBuildTimeout", - "computeDelta_maracas_withCloneTimeout", - "computeImpact_fixture_withCloneTimeout" - ] - }, - { - "ClassName": "com.github.maracas.forges.analysis.CommitAnalyzerTest", - "ClassMethodsOrConstructors": [ - "analyzeCommits_success", - "computeDelta_buildException", - "computeDelta_cloneException", - "computeDelta_no_JAR_created", - "computeDelta_success", - "computeImpact_no_BC_in_delta", - "computeImpact_no_client", - "computeImpact_two_clients_one_analysis_fails", - "computeImpact_two_clients_one_clone_timeout", - "computeImpact_two_clients_success" - ] - }, - { - "ClassName": "com.github.maracas.forges.analysis.PullRequestAnalyzerTest", - "ClassMethodsOrConstructors": [ - "analyzePullRequest_fixture_two_broken_modules", - "inferImpactedModules_fixture_no_impacted_module", - "inferImpactedModules_fixture_one_impacted_module", - "inferImpactedModules_fixture_two_impacted_modules" - ] - }, - { - "ClassName": "com.github.maracas.forges.build.BuilderTest", - "ClassMethodsOrConstructors": [ - "build_From_GradleProject", - "build_From_MavenProject", - "build_From_UnknownProject" - ] - }, - { - "ClassName": "com.github.maracas.forges.build.gradle.GradleBuilderTest", - "ClassMethodsOrConstructors": [ - "build_compileError", - "build_multi_core_default_with_version", - "build_multi_extra_default", - "build_multi_invalid", - "build_validGradle_default", - "build_validGradle_invalidGoal", - "build_validGradle_withGoal", - "build_validGradle_with_invalidProperty", - "build_validGradle_with_validProperty" - ] - }, - { - "ClassName": "com.github.maracas.forges.build.maven.MavenBuilderTest", - "ClassMethodsOrConstructors": [ - "build_compileError", - "build_invalidGoal", - "build_maracas_timeout", - "build_multi_core_default", - "build_multi_extra_default", - "build_multi_invalid", - "build_no_pom", - "build_validPom_default", - "build_validPom_withGoal", - "build_validPom_withProperty", - "locate_modules_multi", - "locate_modules_valid" - ] - }, - { - "ClassName": "com.github.maracas.forges.clone.ClonerTest", - "ClassMethodsOrConstructors": [ - "cloner_From_GitHub", - "cloner_From_Unknown" - ] - }, - { - "ClassName": "com.github.maracas.forges.clone.git.GitClonerTest", - "ClassMethodsOrConstructors": [ - "clone_commit_HEAD", - "clone_commit_invalid_repository", - "clone_commit_invalid_sha", - "clone_commit_sha_branch", - "clone_commit_sha_main", - "clone_commit_timeout", - "clone_commit_timeout_invalid", - "clone_repository", - "clone_repository_branch", - "clone_repository_branch_invalid", - "clone_repository_invalid", - "clone_repository_invalid_location", - "clone_repository_timeout", - "clone_repository_timeout_invalid" - ] - }, - { - "ClassName": "com.github.maracas.forges.github.GitHubClientsScraperTest", - "ClassMethodsOrConstructors": [ - "fetch_clients_ews", - "fetch_clients_guava_limit", - "fetch_clients_spoon", - "fetch_modules_ews", - "fetch_modules_spoon", - "fetch_modules_unknown", - "fetch_one_module_spoon", - "fetch_unknown_module_spoon" - ] - }, - { - "ClassName": "com.github.maracas.forges.github.GitHubForgeIT", - "ClassMethodsOrConstructors": [ - "fetchAllClients_fixture", - "fetchAllClients_from_fork", - "fetchAllClients_no_module", - "fetchClients_unknown_module", - "fetchCommit_HEAD", - "fetchCommit_short_sha", - "fetchCommit_unknown", - "fetchCommit_valid", - "fetchPullRequest_closed", - "fetchPullRequest_opened", - "fetchPullRequest_that_was_synchronized", - "fetchPullRequest_unknown", - "fetchRepository_branch_unknown", - "fetchRepository_branch_valid", - "fetchRepository_unknown", - "fetchRepository_valid", - "fetchStarredClients_spoon", - "fetchTopClients_spoon" - ] - } - ] + "Classes" : [ { + "Name" : "com.github.maracas.visitors.FieldNowFinalVisitor", + "Methods" : [ { + "Name" : "visitCtFieldWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.CombinedVisitor", + "Methods" : [ { + "Name" : "getBrokenUses", + "Descriptors" : [ "()Ljava/util/Set;" ] + }, { + "Name" : "visitCtAnnotation", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotation;)V" ] + }, { + "Name" : "visitCtAnnotationFieldAccess", + "Descriptors" : [ "(Lspoon/reflect/code/CtAnnotationFieldAccess;)V" ] + }, { + "Name" : "visitCtAnnotationMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotationMethod;)V" ] + }, { + "Name" : "visitCtAnnotationType", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotationType;)V" ] + }, { + "Name" : "visitCtAnonymousExecutable", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnonymousExecutable;)V" ] + }, { + "Name" : "visitCtArrayRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtArrayRead;)V" ] + }, { + "Name" : "visitCtArrayTypeReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtArrayTypeReference;)V" ] + }, { + "Name" : "visitCtArrayWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtArrayWrite;)V" ] + }, { + "Name" : "visitCtAssert", + "Descriptors" : [ "(Lspoon/reflect/code/CtAssert;)V" ] + }, { + "Name" : "visitCtAssignment", + "Descriptors" : [ "(Lspoon/reflect/code/CtAssignment;)V" ] + }, { + "Name" : "visitCtBinaryOperator", + "Descriptors" : [ "(Lspoon/reflect/code/CtBinaryOperator;)V" ] + }, { + "Name" : "visitCtBlock", + "Descriptors" : [ "(Lspoon/reflect/code/CtBlock;)V" ] + }, { + "Name" : "visitCtBreak", + "Descriptors" : [ "(Lspoon/reflect/code/CtBreak;)V" ] + }, { + "Name" : "visitCtCase", + "Descriptors" : [ "(Lspoon/reflect/code/CtCase;)V" ] + }, { + "Name" : "visitCtCatch", + "Descriptors" : [ "(Lspoon/reflect/code/CtCatch;)V" ] + }, { + "Name" : "visitCtCatchVariable", + "Descriptors" : [ "(Lspoon/reflect/code/CtCatchVariable;)V" ] + }, { + "Name" : "visitCtCatchVariableReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtCatchVariableReference;)V" ] + }, { + "Name" : "visitCtClass", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] + }, { + "Name" : "visitCtCodeSnippetExpression", + "Descriptors" : [ "(Lspoon/reflect/code/CtCodeSnippetExpression;)V" ] + }, { + "Name" : "visitCtCodeSnippetStatement", + "Descriptors" : [ "(Lspoon/reflect/code/CtCodeSnippetStatement;)V" ] + }, { + "Name" : "visitCtComment", + "Descriptors" : [ "(Lspoon/reflect/code/CtComment;)V" ] + }, { + "Name" : "visitCtCompilationUnit", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtCompilationUnit;)V" ] + }, { + "Name" : "visitCtConditional", + "Descriptors" : [ "(Lspoon/reflect/code/CtConditional;)V" ] + }, { + "Name" : "visitCtConstructor", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtConstructor;)V" ] + }, { + "Name" : "visitCtConstructorCall", + "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] + }, { + "Name" : "visitCtContinue", + "Descriptors" : [ "(Lspoon/reflect/code/CtContinue;)V" ] + }, { + "Name" : "visitCtDo", + "Descriptors" : [ "(Lspoon/reflect/code/CtDo;)V" ] + }, { + "Name" : "visitCtEnum", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtEnum;)V" ] + }, { + "Name" : "visitCtEnumValue", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtEnumValue;)V" ] + }, { + "Name" : "visitCtExecutableReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "visitCtExecutableReferenceExpression", + "Descriptors" : [ "(Lspoon/reflect/code/CtExecutableReferenceExpression;)V" ] + }, { + "Name" : "visitCtField", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtField;)V" ] + }, { + "Name" : "visitCtFieldRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] + }, { + "Name" : "visitCtFieldReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "visitCtFieldWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] + }, { + "Name" : "visitCtFor", + "Descriptors" : [ "(Lspoon/reflect/code/CtFor;)V" ] + }, { + "Name" : "visitCtForEach", + "Descriptors" : [ "(Lspoon/reflect/code/CtForEach;)V" ] + }, { + "Name" : "visitCtIf", + "Descriptors" : [ "(Lspoon/reflect/code/CtIf;)V" ] + }, { + "Name" : "visitCtImport", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtImport;)V" ] + }, { + "Name" : "visitCtInterface", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtInterface;)V" ] + }, { + "Name" : "visitCtIntersectionTypeReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtIntersectionTypeReference;)V" ] + }, { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + }, { + "Name" : "visitCtJavaDoc", + "Descriptors" : [ "(Lspoon/reflect/code/CtJavaDoc;)V" ] + }, { + "Name" : "visitCtJavaDocTag", + "Descriptors" : [ "(Lspoon/reflect/code/CtJavaDocTag;)V" ] + }, { + "Name" : "visitCtLambda", + "Descriptors" : [ "(Lspoon/reflect/code/CtLambda;)V" ] + }, { + "Name" : "visitCtLiteral", + "Descriptors" : [ "(Lspoon/reflect/code/CtLiteral;)V" ] + }, { + "Name" : "visitCtLocalVariable", + "Descriptors" : [ "(Lspoon/reflect/code/CtLocalVariable;)V" ] + }, { + "Name" : "visitCtLocalVariableReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtLocalVariableReference;)V" ] + }, { + "Name" : "visitCtMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] + }, { + "Name" : "visitCtModule", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtModule;)V" ] + }, { + "Name" : "visitCtModuleReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtModuleReference;)V" ] + }, { + "Name" : "visitCtModuleRequirement", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtModuleRequirement;)V" ] + }, { + "Name" : "visitCtNewArray", + "Descriptors" : [ "(Lspoon/reflect/code/CtNewArray;)V" ] + }, { + "Name" : "visitCtNewClass", + "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] + }, { + "Name" : "visitCtOperatorAssignment", + "Descriptors" : [ "(Lspoon/reflect/code/CtOperatorAssignment;)V" ] + }, { + "Name" : "visitCtPackage", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] + }, { + "Name" : "visitCtPackageDeclaration", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackageDeclaration;)V" ] + }, { + "Name" : "visitCtPackageExport", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackageExport;)V" ] + }, { + "Name" : "visitCtPackageReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtPackageReference;)V" ] + }, { + "Name" : "visitCtParameter", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtParameter;)V" ] + }, { + "Name" : "visitCtParameterReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtParameterReference;)V" ] + }, { + "Name" : "visitCtProvidedService", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtProvidedService;)V" ] + }, { + "Name" : "visitCtReturn", + "Descriptors" : [ "(Lspoon/reflect/code/CtReturn;)V" ] + }, { + "Name" : "visitCtStatementList", + "Descriptors" : [ "(Lspoon/reflect/code/CtStatementList;)V" ] + }, { + "Name" : "visitCtSuperAccess", + "Descriptors" : [ "(Lspoon/reflect/code/CtSuperAccess;)V" ] + }, { + "Name" : "visitCtSwitch", + "Descriptors" : [ "(Lspoon/reflect/code/CtSwitch;)V" ] + }, { + "Name" : "visitCtSwitchExpression", + "Descriptors" : [ "(Lspoon/reflect/code/CtSwitchExpression;)V" ] + }, { + "Name" : "visitCtSynchronized", + "Descriptors" : [ "(Lspoon/reflect/code/CtSynchronized;)V" ] + }, { + "Name" : "visitCtTextBlock", + "Descriptors" : [ "(Lspoon/reflect/code/CtTextBlock;)V" ] + }, { + "Name" : "visitCtThisAccess", + "Descriptors" : [ "(Lspoon/reflect/code/CtThisAccess;)V" ] + }, { + "Name" : "visitCtThrow", + "Descriptors" : [ "(Lspoon/reflect/code/CtThrow;)V" ] + }, { + "Name" : "visitCtTry", + "Descriptors" : [ "(Lspoon/reflect/code/CtTry;)V" ] + }, { + "Name" : "visitCtTryWithResource", + "Descriptors" : [ "(Lspoon/reflect/code/CtTryWithResource;)V" ] + }, { + "Name" : "visitCtTypeAccess", + "Descriptors" : [ "(Lspoon/reflect/code/CtTypeAccess;)V" ] + }, { + "Name" : "visitCtTypeMemberWildcardImportReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeMemberWildcardImportReference;)V" ] + }, { + "Name" : "visitCtTypeParameter", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtTypeParameter;)V" ] + }, { + "Name" : "visitCtTypeParameterReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeParameterReference;)V" ] + }, { + "Name" : "visitCtTypeReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "visitCtUnaryOperator", + "Descriptors" : [ "(Lspoon/reflect/code/CtUnaryOperator;)V" ] + }, { + "Name" : "visitCtUnboundVariableReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtUnboundVariableReference;)V" ] + }, { + "Name" : "visitCtUsedService", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtUsedService;)V" ] + }, { + "Name" : "visitCtVariableRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtVariableRead;)V" ] + }, { + "Name" : "visitCtVariableWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtVariableWrite;)V" ] + }, { + "Name" : "visitCtWhile", + "Descriptors" : [ "(Lspoon/reflect/code/CtWhile;)V" ] + }, { + "Name" : "visitCtWildcardReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtWildcardReference;)V" ] + }, { + "Name" : "visitCtYieldStatement", + "Descriptors" : [ "(Lspoon/reflect/code/CtYieldStatement;)V" ] + } ], + "Descriptors" : [ "(Ljava/util/Collection;Lcom/github/maracas/MaracasOptions;)V" ] + }, { + "Name" : "com.github.maracas.visitors.FieldRemovedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "com.github.maracas.LibraryJar", + "Methods" : [ { + "Name" : "buildModel", + "Descriptors" : [ "()Lspoon/reflect/CtModel;" ] + }, { + "Name" : "equals", + "Descriptors" : [ "(Ljava/lang/Object;)Z" ] + }, { + "Name" : "getClasspath", + "Descriptors" : [ "()Ljava/util/List;" ] + }, { + "Name" : "getJar", + "Descriptors" : [ "()Ljava/nio/file/Path;" ] + }, { + "Name" : "getLabel", + "Descriptors" : [ "()Ljava/lang/String;" ] + }, { + "Name" : "getSources", + "Descriptors" : [ "()Lcom/github/maracas/SourcesDirectory;" ] + }, { + "Name" : "hasSources", + "Descriptors" : [ "()Z" ] + }, { + "Name" : "hashCode", + "Descriptors" : [ "()I" ] + }, { + "Name" : "setNoClasspath", + "Descriptors" : [ "(Z)V" ] + }, { + "Name" : "setSources", + "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;)V" ] + }, { + "Name" : "toString", + "Descriptors" : [ "()Ljava/lang/String;" ] + }, { + "Name" : "withSources", + "Descriptors" : [ "(Ljava/nio/file/Path;Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/LibraryJar;", "(Ljava/nio/file/Path;Ljava/nio/file/Path;)Lcom/github/maracas/LibraryJar;" ] + }, { + "Name" : "withoutSources", + "Descriptors" : [ "(Ljava/nio/file/Path;)Lcom/github/maracas/LibraryJar;" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.delta.AbstractBreakingChange", + "Methods" : [ { + "Name" : "getChange", + "Descriptors" : [ "()Ljapicmp/model/JApiCompatibilityChange;" ] + }, { + "Name" : "getSourceElement", + "Descriptors" : [ "()Lspoon/reflect/declaration/CtElement;" ] + }, { + "Name" : "setSourceElement", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)V" ] + } ], + "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.util.SpoonHelpers", + "Methods" : [ { + "Name" : "buildSpoonSignature", + "Descriptors" : [ "(Ljapicmp/model/JApiConstructor;)Ljava/lang/String;", "(Ljapicmp/model/JApiMethod;)Ljava/lang/String;" ] + }, { + "Name" : "firstLocatableParent", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lspoon/reflect/declaration/CtElement;" ] + }, { + "Name" : "fullyQualifiedName", + "Descriptors" : [ "(Lspoon/reflect/reference/CtReference;)Ljava/lang/String;" ] + }, { + "Name" : "getEnclosingPkgName", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Ljava/lang/String;" ] + }, { + "Name" : "isImplicit", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Z" ] + }, { + "Name" : "matchingSignatures", + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Ljavassist/CtBehavior;)Z" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.visitors.FieldLessAccessibleVisitor", + "Methods" : [ { + "Name" : "visitCtFieldRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] + }, { + "Name" : "visitCtFieldWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/AccessModifier;)V" ] + }, { + "Name" : "com.github.maracas.visitors.FieldReferenceVisitor", + "Methods" : [ { + "Name" : "visitCtFieldReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.util.PathHelpers", + "Methods" : [ { + "Name" : "isValidDirectory", + "Descriptors" : [ "(Ljava/nio/file/Path;)Z" ] + }, { + "Name" : "isValidJar", + "Descriptors" : [ "(Ljava/nio/file/Path;)Z" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.visitors.FieldTypeChangedVisitor", + "Methods" : [ { + "Name" : "visitCtFieldRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] + }, { + "Name" : "visitCtFieldWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.MethodAddedToInterfaceVisitor", + "Methods" : [ { + "Name" : "visitCtClass", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.SupertypeRemovedVisitor", + "Methods" : [ { + "Name" : "visitCtAssignment", + "Descriptors" : [ "(Lspoon/reflect/code/CtAssignment;)V" ] + }, { + "Name" : "visitCtFieldReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + }, { + "Name" : "visitCtLocalVariable", + "Descriptors" : [ "(Lspoon/reflect/code/CtLocalVariable;)V" ] + }, { + "Name" : "visitCtMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.brokenuse.APIUse", + "Methods" : [ ], + "Descriptors" : [ "()V" ] + }, { + "Name" : "com.github.maracas.visitors.FieldNowStaticVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ClassRemovedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.util.BinaryToSourceMapper", + "Methods" : [ { + "Name" : "resolve", + "Descriptors" : [ "(Lspoon/reflect/reference/CtReference;)Lspoon/reflect/declaration/CtElement;" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] + }, { + "Name" : "com.github.maracas.visitors.InterfaceAddedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;)V" ] + }, { + "Name" : "com.github.maracas.visitors.InterfaceRemovedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;)V" ] + }, { + "Name" : "com.github.maracas.util.CtElementSerializer", + "Methods" : [ { + "Name" : "serialize", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V" ] + } ], + "Descriptors" : [ "()V", "(Ljava/lang/Class;)V" ] + }, { + "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToFieldVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ClassNowAbstractVisitor", + "Methods" : [ { + "Name" : "visitCtConstructorCall", + "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.MaracasOptions", + "Methods" : [ { + "Name" : "defaultJApiOptions", + "Descriptors" : [ "()Ljapicmp/config/Options;" ] + }, { + "Name" : "excludeBreakingChange", + "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "getBuildTimeout", + "Descriptors" : [ "()Ljava/time/Duration;" ] + }, { + "Name" : "getClientsPerModule", + "Descriptors" : [ "()I" ] + }, { + "Name" : "getCloneTimeout", + "Descriptors" : [ "()Ljava/time/Duration;" ] + }, { + "Name" : "getExcludedBreakingChanges", + "Descriptors" : [ "()Ljava/util/Set;" ] + }, { + "Name" : "getJApiOptions", + "Descriptors" : [ "()Ljapicmp/config/Options;" ] + }, { + "Name" : "getMaxClassLines", + "Descriptors" : [ "()I" ] + }, { + "Name" : "getMinStarsPerClient", + "Descriptors" : [ "()I" ] + }, { + "Name" : "newDefault", + "Descriptors" : [ "()Lcom/github/maracas/MaracasOptions;" ] + }, { + "Name" : "setBuildTimeout", + "Descriptors" : [ "(Ljava/time/Duration;)V" ] + }, { + "Name" : "setClientsPerModule", + "Descriptors" : [ "(I)V" ] + }, { + "Name" : "setCloneTimeout", + "Descriptors" : [ "(Ljava/time/Duration;)V" ] + }, { + "Name" : "setMaxClassLines", + "Descriptors" : [ "(I)V" ] + }, { + "Name" : "setMinStarsPerClient", + "Descriptors" : [ "(I)V" ] + } ], + "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor", + "Methods" : [ { + "Name" : "visitCtThrow", + "Descriptors" : [ "(Lspoon/reflect/code/CtThrow;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.util.ParentLastURLClassLoader", + "Methods" : [ { + "Name" : "loadClass", + "Descriptors" : [ "(Ljava/lang/String;Z)Ljava/lang/Class;" ] + } ], + "Descriptors" : [ "([Ljava/net/URL;)V", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V" ] + }, { + "Name" : "com.github.maracas.delta.Delta", + "Methods" : [ { + "Name" : "fromJApiCmpDelta", + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Ljava/util/List;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/delta/Delta;" ] + }, { + "Name" : "getBreakingChanges", + "Descriptors" : [ "()Ljava/util/List;" ] + }, { + "Name" : "getNewVersion", + "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] + }, { + "Name" : "getOldVersion", + "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] + }, { + "Name" : "getVisitors", + "Descriptors" : [ "()Ljava/util/List;" ] + }, { + "Name" : "isEmpty", + "Descriptors" : [ "()Z" ] + }, { + "Name" : "populateLocations", + "Descriptors" : [ "()V" ] + }, { + "Name" : "toJson", + "Descriptors" : [ "()Ljava/lang/String;" ] + }, { + "Name" : "toString", + "Descriptors" : [ "()Ljava/lang/String;" ] + } ], + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Ljava/util/List;)V" ] + }, { + "Name" : "com.github.maracas.Maracas", + "Methods" : [ { + "Name" : "analyze", + "Descriptors" : [ "(Lcom/github/maracas/AnalysisQuery;)Lcom/github/maracas/AnalysisResult;" ] + }, { + "Name" : "computeDelta", + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/delta/Delta;", "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/delta/Delta;" ] + }, { + "Name" : "computeDeltaImpact", + "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;Lcom/github/maracas/delta/Delta;)Lcom/github/maracas/brokenuse/DeltaImpact;", "(Lcom/github/maracas/SourcesDirectory;Lcom/github/maracas/delta/Delta;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/brokenuse/DeltaImpact;" ] + } ], + "Descriptors" : [ "()V" ] + }, { + "Name" : "com.github.maracas.AnalysisQuery", + "Methods" : [ { + "Name" : "builder", + "Descriptors" : [ "()Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "getClients", + "Descriptors" : [ "()Ljava/util/Collection;" ] + }, { + "Name" : "getMaracasOptions", + "Descriptors" : [ "()Lcom/github/maracas/MaracasOptions;" ] + }, { + "Name" : "getNewVersion", + "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] + }, { + "Name" : "getOldVersion", + "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.visitors.MethodNowFinalVisitor", + "Methods" : [ { + "Name" : "visitCtMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.SuperclassRemovedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.MethodRemovedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.MethodReturnTypeChangedVisitor", + "Methods" : [ { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + }, { + "Name" : "visitCtMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ConstructorRemovedVisitor", + "Methods" : [ { + "Name" : "visitCtConstructorCall", + "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] + }, { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + }, { + "Name" : "visitCtNewClass", + "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ClassNowFinalVisitor", + "Methods" : [ { + "Name" : "visitCtClass", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] + }, { + "Name" : "visitCtNewClass", + "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.SupertypeAddedVisitor", + "Methods" : [ { + "Name" : "visitCtClass", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToClassVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.util.SpoonTypeHelpers", + "Methods" : [ { + "Name" : "haveUnimplAbstractMethods", + "Descriptors" : [ "(Ljava/util/Set;)Z" ] + }, { + "Name" : "inferExpectedType", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lspoon/reflect/reference/CtTypeReference;" ] + }, { + "Name" : "isAssignableFrom", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isAssignableFromOverride", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isBoxedType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isNarrowedPrimitiveType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isNarrowedType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isSubtype", + "Descriptors" : [ "(Ljava/util/Set;Lspoon/reflect/reference/CtTypeReference;)Z", "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isUnboxedType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isWidenedPrimitiveType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + }, { + "Name" : "isWidenedType", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.delta.JApiCmpToSpoonVisitor", + "Methods" : [ { + "Name" : "getBreakingChanges", + "Descriptors" : [ "()Ljava/util/List;" ] + }, { + "Name" : "visit", + "Descriptors" : [ "(Ljapicmp/model/JApiAnnotation;)V", "(Ljapicmp/model/JApiClass;)V", "(Ljapicmp/model/JApiClass;Ljapicmp/model/JApiImplementedInterface;)V", "(Ljapicmp/model/JApiConstructor;)V", "(Ljapicmp/model/JApiField;)V", "(Ljapicmp/model/JApiImplementedInterface;)V", "(Ljapicmp/model/JApiMethod;)V", "(Ljapicmp/model/JApiSuperclass;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] + }, { + "Name" : "com.github.maracas.util.GradleLauncher", + "Methods" : [ { + "Name" : "init", + "Descriptors" : [ "(Ljava/nio/file/Path;)V" ] + } ], + "Descriptors" : [ "(Ljava/nio/file/Path;)V" ] + }, { + "Name" : "com.github.maracas.SourcesDirectory", + "Methods" : [ { + "Name" : "buildModel", + "Descriptors" : [ "()Lspoon/reflect/CtModel;" ] + }, { + "Name" : "equals", + "Descriptors" : [ "(Ljava/lang/Object;)Z" ] + }, { + "Name" : "getLocation", + "Descriptors" : [ "()Ljava/nio/file/Path;" ] + }, { + "Name" : "hashCode", + "Descriptors" : [ "()I" ] + }, { + "Name" : "of", + "Descriptors" : [ "(Ljava/nio/file/Path;)Lcom/github/maracas/SourcesDirectory;" ] + }, { + "Name" : "setClasspath", + "Descriptors" : [ "(Ljava/util/List;)V" ] + }, { + "Name" : "toString", + "Descriptors" : [ "()Ljava/lang/String;" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.visitors.FieldNoLongerStaticVisitor", + "Methods" : [ { + "Name" : "visitCtFieldRead", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] + }, { + "Name" : "visitCtFieldWrite", + "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.SuperclassAddedVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.TypeReferenceVisitor", + "Methods" : [ { + "Name" : "visitCtTypeReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.delta.FieldBreakingChange", + "Methods" : [ { + "Name" : "getReference", + "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] + }, { + "Name" : "getVisitor", + "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] + } ], + "Descriptors" : [ "(Ljapicmp/model/JApiField;Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.visitors.ClassLessAccessibleVisitor", + "Methods" : [ { + "Name" : "visitCtTypeReference", + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/AccessModifier;)V" ] + }, { + "Name" : "com.github.maracas.AnalysisQuery$Builder", + "Methods" : [ { + "Name" : "build", + "Descriptors" : [ "()Lcom/github/maracas/AnalysisQuery;" ] + }, { + "Name" : "client", + "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "clients", + "Descriptors" : [ "([Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/AnalysisQuery$Builder;", "(Ljava/util/Collection;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "exclude", + "Descriptors" : [ "(Ljava/lang/String;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "newVersion", + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "of", + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "oldVersion", + "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + }, { + "Name" : "options", + "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/AnalysisQuery$Builder;" ] + } ], + "Descriptors" : [ ] + }, { + "Name" : "com.github.maracas.MaracasCLI", + "Methods" : [ { + "Name" : "main", + "Descriptors" : [ "([Ljava/lang/String;)V" ] + }, { + "Name" : "run", + "Descriptors" : [ "()V" ] + } ], + "Descriptors" : [ "()V" ] + }, { + "Name" : "com.github.maracas.delta.TypeBreakingChange", + "Methods" : [ { + "Name" : "getReference", + "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] + }, { + "Name" : "getVisitor", + "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] + } ], + "Descriptors" : [ "(Ljapicmp/model/JApiClass;Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.visitors.BreakingChangeVisitor", + "Methods" : [ { + "Name" : "brokenUse", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;Lspoon/reflect/declaration/CtElement;Lspoon/reflect/reference/CtReference;Lcom/github/maracas/brokenuse/APIUse;)V" ] + }, { + "Name" : "getAPIUseByRole", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lcom/github/maracas/brokenuse/APIUse;" ] + }, { + "Name" : "getBrokenUses", + "Descriptors" : [ "()Ljava/util/Set;" ] + } ], + "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.visitors.MethodNowAbstractVisitor", + "Methods" : [ { + "Name" : "visitCtClass", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] + }, { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "com.github.maracas.delta.JApiCmpDeltaFilter", + "Methods" : [ { + "Name" : "filter", + "Descriptors" : [ "(Ljava/util/List;)V" ] + } ], + "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)V" ] + }, { + "Name" : "com.github.maracas.delta.MethodBreakingChange", + "Methods" : [ { + "Name" : "getReference", + "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] + }, { + "Name" : "getVisitor", + "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] + } ], + "Descriptors" : [ "(Ljapicmp/model/JApiBehavior;Lspoon/reflect/reference/CtExecutableReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + }, { + "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToMethodVisitor", + "Methods" : [ ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] + }, { + "Name" : "com.github.maracas.visitors.MethodReferenceVisitor", + "Methods" : [ { + "Name" : "visitCtInvocation", + "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] + }, { + "Name" : "visitCtMethod", + "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] + } ], + "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] + } ], + "LibraryMethods" : [ "com.github.maracas.AnalysisQuery.builder", "com.github.maracas.AnalysisQuery.getClients", "com.github.maracas.AnalysisQuery.getMaracasOptions", "com.github.maracas.AnalysisQuery.getNewVersion", "com.github.maracas.AnalysisQuery.getOldVersion", "com.github.maracas.LibraryJar.buildClasspath", "com.github.maracas.LibraryJar.buildClasspathFromPom", "com.github.maracas.LibraryJar.buildModel", "com.github.maracas.LibraryJar.equals", "com.github.maracas.LibraryJar.extractPomFromJar", "com.github.maracas.LibraryJar.getClasspath", "com.github.maracas.LibraryJar.getJar", "com.github.maracas.LibraryJar.getLabel", "com.github.maracas.LibraryJar.getSources", "com.github.maracas.LibraryJar.hasSources", "com.github.maracas.LibraryJar.hashCode", "com.github.maracas.LibraryJar.setNoClasspath", "com.github.maracas.LibraryJar.setSources", "com.github.maracas.LibraryJar.toString", "com.github.maracas.LibraryJar.withSources", "com.github.maracas.LibraryJar.withSources", "com.github.maracas.LibraryJar.withoutSources", "com.github.maracas.Maracas.analyze", "com.github.maracas.Maracas.computeDelta", "com.github.maracas.Maracas.computeDelta", "com.github.maracas.Maracas.computeDeltaImpact", "com.github.maracas.Maracas.computeDeltaImpact", "com.github.maracas.MaracasCLI.main", "com.github.maracas.MaracasCLI.run", "com.github.maracas.MaracasOptions.defaultJApiOptions", "com.github.maracas.MaracasOptions.excludeBreakingChange", "com.github.maracas.MaracasOptions.getBuildTimeout", "com.github.maracas.MaracasOptions.getClientsPerModule", "com.github.maracas.MaracasOptions.getCloneTimeout", "com.github.maracas.MaracasOptions.getExcludedBreakingChanges", "com.github.maracas.MaracasOptions.getJApiOptions", "com.github.maracas.MaracasOptions.getMaxClassLines", "com.github.maracas.MaracasOptions.getMinStarsPerClient", "com.github.maracas.MaracasOptions.newDefault", "com.github.maracas.MaracasOptions.setBuildTimeout", "com.github.maracas.MaracasOptions.setClientsPerModule", "com.github.maracas.MaracasOptions.setCloneTimeout", "com.github.maracas.MaracasOptions.setMaxClassLines", "com.github.maracas.MaracasOptions.setMinStarsPerClient", "com.github.maracas.SourcesDirectory.buildModel", "com.github.maracas.SourcesDirectory.equals", "com.github.maracas.SourcesDirectory.getLocation", "com.github.maracas.SourcesDirectory.hashCode", "com.github.maracas.SourcesDirectory.of", "com.github.maracas.SourcesDirectory.setClasspath", "com.github.maracas.SourcesDirectory.toString", "com.github.maracas.Usage.main", "com.github.maracas.Usage.readmeUsage1", "com.github.maracas.Usage.readmeUsage2", "com.github.maracas.delta.AbstractBreakingChange.getChange", "com.github.maracas.delta.AbstractBreakingChange.getSourceElement", "com.github.maracas.delta.AbstractBreakingChange.setSourceElement", "com.github.maracas.delta.BreakingChange.getChange", "com.github.maracas.delta.BreakingChange.getReference", "com.github.maracas.delta.BreakingChange.getSourceElement", "com.github.maracas.delta.BreakingChange.getVisitor", "com.github.maracas.delta.BreakingChange.setSourceElement", "com.github.maracas.delta.Delta.fromJApiCmpDelta", "com.github.maracas.delta.Delta.getBreakingChanges", "com.github.maracas.delta.Delta.getNewVersion", "com.github.maracas.delta.Delta.getOldVersion", "com.github.maracas.delta.Delta.getVisitors", "com.github.maracas.delta.Delta.isEmpty", "com.github.maracas.delta.Delta.populateLocations", "com.github.maracas.delta.Delta.toJson", "com.github.maracas.delta.Delta.toString", "com.github.maracas.delta.FieldBreakingChange.getReference", "com.github.maracas.delta.FieldBreakingChange.getVisitor", "com.github.maracas.delta.JApiCmpDeltaFilter.filter", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.getBreakingChanges", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.MethodBreakingChange.getReference", "com.github.maracas.delta.MethodBreakingChange.getVisitor", "com.github.maracas.delta.TypeBreakingChange.getReference", "com.github.maracas.delta.TypeBreakingChange.getVisitor", "com.github.maracas.util.BinaryToSourceMapper.cache", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.CtElementSerializer.serialize", "com.github.maracas.util.GradleLauncher.init", "com.github.maracas.util.ParentLastURLClassLoader.loadClass", "com.github.maracas.util.PathHelpers.isValidDirectory", "com.github.maracas.util.PathHelpers.isValidJar", "com.github.maracas.util.SpoonHelpers.buildSpoonSignature", "com.github.maracas.util.SpoonHelpers.buildSpoonSignature", "com.github.maracas.util.SpoonHelpers.firstLocatableParent", "com.github.maracas.util.SpoonHelpers.fullyQualifiedName", "com.github.maracas.util.SpoonHelpers.getEnclosingPkgName", "com.github.maracas.util.SpoonHelpers.isImplicit", "com.github.maracas.util.SpoonHelpers.matchingSignatures", "com.github.maracas.util.SpoonTypeHelpers.haveUnimplAbstractMethods", "com.github.maracas.util.SpoonTypeHelpers.inferExpectedType", "com.github.maracas.util.SpoonTypeHelpers.isAssignableFrom", "com.github.maracas.util.SpoonTypeHelpers.isAssignableFromOverride", "com.github.maracas.util.SpoonTypeHelpers.isBoxedType", "com.github.maracas.util.SpoonTypeHelpers.isNarrowedPrimitiveType", "com.github.maracas.util.SpoonTypeHelpers.isNarrowedType", "com.github.maracas.util.SpoonTypeHelpers.isSubtype", "com.github.maracas.util.SpoonTypeHelpers.isSubtype", "com.github.maracas.util.SpoonTypeHelpers.isUnboxedType", "com.github.maracas.util.SpoonTypeHelpers.isWidenedPrimitiveType", "com.github.maracas.util.SpoonTypeHelpers.isWidenedType", "com.github.maracas.util.SpoonTypeHelpers.primitivesAreCompatible", "com.github.maracas.visitors.BreakingChangeVisitor.brokenUse", "com.github.maracas.visitors.BreakingChangeVisitor.getAPIUseByRole", "com.github.maracas.visitors.BreakingChangeVisitor.getBrokenUses", "com.github.maracas.visitors.ClassLessAccessibleVisitor.visitCtTypeReference", "com.github.maracas.visitors.ClassNowAbstractVisitor.visitCtConstructorCall", "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor.visitCtThrow", "com.github.maracas.visitors.ClassNowFinalVisitor.visitCtClass", "com.github.maracas.visitors.ClassNowFinalVisitor.visitCtNewClass", "com.github.maracas.visitors.CombinedVisitor.getBrokenUses", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotation", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationFieldAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationMethod", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationType", "com.github.maracas.visitors.CombinedVisitor.visitCtAnonymousExecutable", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayRead", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtAssert", "com.github.maracas.visitors.CombinedVisitor.visitCtAssignment", "com.github.maracas.visitors.CombinedVisitor.visitCtBinaryOperator", "com.github.maracas.visitors.CombinedVisitor.visitCtBlock", "com.github.maracas.visitors.CombinedVisitor.visitCtBreak", "com.github.maracas.visitors.CombinedVisitor.visitCtCase", "com.github.maracas.visitors.CombinedVisitor.visitCtCatch", "com.github.maracas.visitors.CombinedVisitor.visitCtCatchVariable", "com.github.maracas.visitors.CombinedVisitor.visitCtCatchVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtClass", "com.github.maracas.visitors.CombinedVisitor.visitCtCodeSnippetExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtCodeSnippetStatement", "com.github.maracas.visitors.CombinedVisitor.visitCtComment", "com.github.maracas.visitors.CombinedVisitor.visitCtCompilationUnit", "com.github.maracas.visitors.CombinedVisitor.visitCtConditional", "com.github.maracas.visitors.CombinedVisitor.visitCtConstructor", "com.github.maracas.visitors.CombinedVisitor.visitCtConstructorCall", "com.github.maracas.visitors.CombinedVisitor.visitCtContinue", "com.github.maracas.visitors.CombinedVisitor.visitCtDo", "com.github.maracas.visitors.CombinedVisitor.visitCtEnum", "com.github.maracas.visitors.CombinedVisitor.visitCtEnumValue", "com.github.maracas.visitors.CombinedVisitor.visitCtExecutableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtExecutableReferenceExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtField", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldRead", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldReference", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtFor", "com.github.maracas.visitors.CombinedVisitor.visitCtForEach", "com.github.maracas.visitors.CombinedVisitor.visitCtIf", "com.github.maracas.visitors.CombinedVisitor.visitCtImport", "com.github.maracas.visitors.CombinedVisitor.visitCtInterface", "com.github.maracas.visitors.CombinedVisitor.visitCtIntersectionTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtInvocation", "com.github.maracas.visitors.CombinedVisitor.visitCtJavaDoc", "com.github.maracas.visitors.CombinedVisitor.visitCtJavaDocTag", "com.github.maracas.visitors.CombinedVisitor.visitCtLambda", "com.github.maracas.visitors.CombinedVisitor.visitCtLiteral", "com.github.maracas.visitors.CombinedVisitor.visitCtLocalVariable", "com.github.maracas.visitors.CombinedVisitor.visitCtLocalVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtMethod", "com.github.maracas.visitors.CombinedVisitor.visitCtModule", "com.github.maracas.visitors.CombinedVisitor.visitCtModuleReference", "com.github.maracas.visitors.CombinedVisitor.visitCtModuleRequirement", "com.github.maracas.visitors.CombinedVisitor.visitCtNewArray", "com.github.maracas.visitors.CombinedVisitor.visitCtNewClass", "com.github.maracas.visitors.CombinedVisitor.visitCtOperatorAssignment", "com.github.maracas.visitors.CombinedVisitor.visitCtPackage", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageDeclaration", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageExport", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageReference", "com.github.maracas.visitors.CombinedVisitor.visitCtParameter", "com.github.maracas.visitors.CombinedVisitor.visitCtParameterReference", "com.github.maracas.visitors.CombinedVisitor.visitCtProvidedService", "com.github.maracas.visitors.CombinedVisitor.visitCtReturn", "com.github.maracas.visitors.CombinedVisitor.visitCtStatementList", "com.github.maracas.visitors.CombinedVisitor.visitCtSuperAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtSwitch", "com.github.maracas.visitors.CombinedVisitor.visitCtSwitchExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtSynchronized", "com.github.maracas.visitors.CombinedVisitor.visitCtTextBlock", "com.github.maracas.visitors.CombinedVisitor.visitCtThisAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtThrow", "com.github.maracas.visitors.CombinedVisitor.visitCtTry", "com.github.maracas.visitors.CombinedVisitor.visitCtTryWithResource", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeMemberWildcardImportReference", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeParameter", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeParameterReference", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtUnaryOperator", "com.github.maracas.visitors.CombinedVisitor.visitCtUnboundVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtUsedService", "com.github.maracas.visitors.CombinedVisitor.visitCtVariableRead", "com.github.maracas.visitors.CombinedVisitor.visitCtVariableWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtWhile", "com.github.maracas.visitors.CombinedVisitor.visitCtWildcardReference", "com.github.maracas.visitors.CombinedVisitor.visitCtYieldStatement", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtConstructorCall", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtInvocation", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtNewClass", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldAccess", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.isStaticAccess", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldAccess", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldNowFinalVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldReferenceVisitor.visitCtFieldReference", "com.github.maracas.visitors.FieldTypeChangedVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldTypeChangedVisitor.visitCtFieldWrite", "com.github.maracas.visitors.MethodAddedToInterfaceVisitor.visitCtClass", "com.github.maracas.visitors.MethodNowAbstractVisitor.visitCtClass", "com.github.maracas.visitors.MethodNowAbstractVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodNowFinalVisitor.visitCtMethod", "com.github.maracas.visitors.MethodReferenceVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodReferenceVisitor.visitCtMethod", "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.visitCtMethod", "com.github.maracas.visitors.SupertypeAddedVisitor.visitCtClass", "com.github.maracas.visitors.SupertypeRemovedVisitor.isStaticInvocation", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtAssignment", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtFieldReference", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtInvocation", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtLocalVariable", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtMethod", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitExpAssignment", "com.github.maracas.visitors.TypeReferenceVisitor.visitCtTypeReference" ], + "ClientMethods" : [ "com.github.maracas.forges.Forge.fetchAllClients", "com.github.maracas.forges.Forge.fetchBreakbotConfig", "com.github.maracas.forges.Forge.fetchCommit", "com.github.maracas.forges.Forge.fetchCommit", "com.github.maracas.forges.Forge.fetchModules", "com.github.maracas.forges.Forge.fetchPullRequest", "com.github.maracas.forges.Forge.fetchPullRequest", "com.github.maracas.forges.Forge.fetchRepository", "com.github.maracas.forges.Forge.fetchRepository", "com.github.maracas.forges.Forge.fetchTopStarredClients", "com.github.maracas.forges.Usage.readmeUsage1", "com.github.maracas.forges.Usage.readmeUsage2", "com.github.maracas.forges.analysis.CommitAnalyzer.analyzeCommits", "com.github.maracas.forges.analysis.CommitAnalyzer.cloneAndAnalyzeClient", "com.github.maracas.forges.analysis.CommitAnalyzer.cloneAndBuildLibrary", "com.github.maracas.forges.analysis.CommitAnalyzer.computeDelta", "com.github.maracas.forges.analysis.CommitAnalyzer.computeImpact", "com.github.maracas.forges.analysis.PullRequestAnalyzer.analyzeModule", "com.github.maracas.forges.analysis.PullRequestAnalyzer.analyzePullRequest", "com.github.maracas.forges.analysis.PullRequestAnalyzer.cleanUp", "com.github.maracas.forges.analysis.PullRequestAnalyzer.getRepositoryModule", "com.github.maracas.forges.analysis.PullRequestAnalyzer.inferImpactedModules", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeBuilderForClient", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeBuilderForLibrary", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeClonePath", "com.github.maracas.forges.analysis.PullRequestAnalyzer.workingDirectory", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_GumTree", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_fixture_moduleA", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_fixture_nestedB", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeDelta_maracas_withBuildTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeDelta_maracas_withCloneTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeImpact_fixture_withCloneTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.setUp", "com.github.maracas.forges.analysis.CommitAnalyzerTest.analyzeCommits_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_buildException", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_cloneException", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_no_JAR_created", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_no_BC_in_delta", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_no_client", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_one_analysis_fails", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_one_clone_timeout", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.setUp", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.analyzePullRequest_fixture_two_broken_modules", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_no_impacted_module", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_one_impacted_module", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_two_impacted_modules", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.setUp", "com.github.maracas.forges.build.BuildConfig.addGoal", "com.github.maracas.forges.build.BuildConfig.getGoals", "com.github.maracas.forges.build.BuildConfig.getModule", "com.github.maracas.forges.build.BuildConfig.getProperties", "com.github.maracas.forges.build.BuildConfig.newDefault", "com.github.maracas.forges.build.BuildConfig.setProperty", "com.github.maracas.forges.build.BuildConfig.toString", "com.github.maracas.forges.build.Builder.build", "com.github.maracas.forges.build.Builder.build", "com.github.maracas.forges.build.Builder.locateJar", "com.github.maracas.forges.build.Builder.locateModules", "com.github.maracas.forges.build.Builder.of", "com.github.maracas.forges.build.Builder.of", "com.github.maracas.forges.build.CommitBuilder.buildCommit", "com.github.maracas.forges.build.CommitBuilder.cloneCommit", "com.github.maracas.forges.build.CommitBuilder.getBuildConfig", "com.github.maracas.forges.build.CommitBuilder.getBuilder", "com.github.maracas.forges.build.CommitBuilder.getClonePath", "com.github.maracas.forges.build.CommitBuilder.getCloner", "com.github.maracas.forges.build.CommitBuilder.getCommit", "com.github.maracas.forges.build.CommitBuilder.getModulePath", "com.github.maracas.forges.build.CommitBuilder.toString", "com.github.maracas.forges.build.BuilderTest.build_From_GradleProject", "com.github.maracas.forges.build.BuilderTest.build_From_MavenProject", "com.github.maracas.forges.build.BuilderTest.build_From_UnknownProject", "com.github.maracas.forges.build.gradle.GradleBuilder.build", "com.github.maracas.forges.build.gradle.GradleBuilder.getProjectConnection", "com.github.maracas.forges.build.gradle.GradleBuilder.isGradleProject", "com.github.maracas.forges.build.gradle.GradleBuilder.locateJar", "com.github.maracas.forges.build.gradle.GradleBuilder.locateModules", "com.github.maracas.forges.build.gradle.GradleBuilder.readGradleProperties", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_compileError", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_core_default_with_version", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_extra_default", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_invalid", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_default", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_invalidGoal", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_withGoal", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_with_invalidProperty", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_with_validProperty", "com.github.maracas.forges.build.gradle.GradleBuilderTest.setUp", "com.github.maracas.forges.build.maven.MavenBuilder.build", "com.github.maracas.forges.build.maven.MavenBuilder.isMavenProject", "com.github.maracas.forges.build.maven.MavenBuilder.locateJar", "com.github.maracas.forges.build.maven.MavenBuilder.locateModules", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_compileError", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_invalidGoal", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_maracas_timeout", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_core_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_extra_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_invalid", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_no_pom", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_withGoal", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_withProperty", "com.github.maracas.forges.build.maven.MavenBuilderTest.locate_modules_multi", "com.github.maracas.forges.build.maven.MavenBuilderTest.locate_modules_valid", "com.github.maracas.forges.build.maven.MavenBuilderTest.setUp", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.of", "com.github.maracas.forges.clone.ClonerTest.cloner_From_GitHub", "com.github.maracas.forges.clone.ClonerTest.cloner_From_Unknown", "com.github.maracas.forges.clone.git.GitCloner.clone", "com.github.maracas.forges.clone.git.GitCloner.clone", "com.github.maracas.forges.clone.git.GitCloner.executeCommand", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_HEAD", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_invalid_repository", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_invalid_sha", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_sha_branch", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_sha_main", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_timeout", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_timeout_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_branch", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_branch_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_invalid_location", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_timeout", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_timeout_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.readHEAD", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchClients", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchClients", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchModules", "com.github.maracas.forges.github.GitHubClientsScraper.clientsCacheFile", "com.github.maracas.forges.github.GitHubClientsScraper.fetchClients", "com.github.maracas.forges.github.GitHubClientsScraper.fetchClientsRec", "com.github.maracas.forges.github.GitHubClientsScraper.fetchModules", "com.github.maracas.forges.github.GitHubClientsScraper.fetchPage", "com.github.maracas.forges.github.GitHubClientsScraper.hasClientsCache", "com.github.maracas.forges.github.GitHubClientsScraper.readClientsCache", "com.github.maracas.forges.github.GitHubClientsScraper.writeClientsCache", "com.github.maracas.forges.github.GitHubForge.fetchAllClients", "com.github.maracas.forges.github.GitHubForge.fetchAndCacheRepository", "com.github.maracas.forges.github.GitHubForge.fetchBreakbotConfig", "com.github.maracas.forges.github.GitHubForge.fetchCommit", "com.github.maracas.forges.github.GitHubForge.fetchCustomClients", "com.github.maracas.forges.github.GitHubForge.fetchModules", "com.github.maracas.forges.github.GitHubForge.fetchPullRequest", "com.github.maracas.forges.github.GitHubForge.fetchRepository", "com.github.maracas.forges.github.GitHubForge.fetchRepository", "com.github.maracas.forges.github.GitHubForge.fetchTopStarredClients", "com.github.maracas.forges.github.GitHubForge.getRepositoryFromBreakbot", "com.github.maracas.forges.github.GitHubForge.getSourceRepository", "com.github.maracas.forges.github.GitHubForge.isValidClient", "com.github.maracas.forges.github.BreakbotConfigTest.client_with_commit_or_branch", "com.github.maracas.forges.github.BreakbotConfigTest.clients_with_sources", "com.github.maracas.forges.github.BreakbotConfigTest.custom_build", "com.github.maracas.forges.github.BreakbotConfigTest.custom_build_output", "com.github.maracas.forges.github.BreakbotConfigTest.custom_output", "com.github.maracas.forges.github.BreakbotConfigTest.default_configuration", "com.github.maracas.forges.github.BreakbotConfigTest.ignore_unknown_properties", "com.github.maracas.forges.github.BreakbotConfigTest.invalid_configuration", "com.github.maracas.forges.github.BreakbotConfigTest.one_client", "com.github.maracas.forges.github.BreakbotConfigTest.popular_clients", "com.github.maracas.forges.github.BreakbotConfigTest.several_clients", "com.github.maracas.forges.github.BreakbotConfigTest.top_clients", "com.github.maracas.forges.github.BreakbotConfigTest.top_clients_with_custom", "com.github.maracas.forges.github.BreakbotConfigTest.with_excludes", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_ews", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_guava_limit", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_ews", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_unknown", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_one_module_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_unknown_module_spoon", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_fixture", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_from_fork", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_no_module", "com.github.maracas.forges.github.GitHubForgeIT.fetchClients_unknown_module", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_HEAD", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_short_sha", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_closed", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_opened", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_that_was_synchronized", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_branch_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_branch_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchStarredClients_spoon", "com.github.maracas.forges.github.GitHubForgeIT.fetchTopClients_spoon", "com.github.maracas.forges.github.GitHubForgeIT.setUp", "com.github.maracas.forges.github.GitHubForgeTest.fetchCommit_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchCommit_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchPullRequest_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchPullRequest_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_withInvalidBranch_shouldFail", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_withValidBranch_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_oneClientFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_shouldOrder_Clients", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_shouldRetrieve_SourceClients", "com.github.maracas.forges.github.GitHubForgeTest.prFixture", "com.github.maracas.forges.github.GitHubForgeTest.repositoryFixture", "com.github.maracas.forges.github.GitHubForgeTest.repositoryFixture", "com.github.maracas.forges.github.GitHubForgeTest.setUp" ] } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 319143ca..19229517 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -73,6 +73,11 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab List variableList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { + if (arg == null) { + argList.add("null"); + continue; + } + String argumentValue = serializableDataToCode(arg, variableStackHandler); String argumentVariable = getDataVariableDeclaration(arg, variableStackHandler); String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); @@ -83,7 +88,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab variableList.add("%s;".formatted(argumentDeclaration)); } - String argumentParameters = String.join(",", argList); + String argumentParameters = String.join(", ", argList); String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); variableList.add(methodCallCode); @@ -104,6 +109,11 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan List argList = new ArrayList<>(); for (TraceData traceData : methodTrace.getPostCallArguments()) { + if (traceData == null) { + argList.add("null"); + continue; + } + // We return a value that we managed to serialize argList.add(getAssertionCodeLine(traceData, variableStackHandler)); } diff --git a/maracas-test.cmd b/maracas-test.cmd index 20bf16e8..48e2ea71 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -1,6 +1,29 @@ @echo off +call run-clean-workflow.cmd + set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 + +REM build samples +cd Samples +call .\gradlew.bat jar +cd .. + +REM build confgen +cd ConfGen +call .\gradlew.bat shadowJar +cd .. + +REM build traceview +cd TraceView +call .\gradlew.bat shadowJar +cd .. + +REM build tool +cd Instrumentation +call .\gradlew.bat shadowJar +cd .. + set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 %JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" From bfa55fb9b2288ab9a562c56b64fb908c13e6fd2f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 09:58:19 +0100 Subject: [PATCH 075/244] Refactor codegen to not generate the same class multiple times --- .../github/maracas/gilesi/traceview/Main.java | 98 +++++++++++++------ 1 file changed, 70 insertions(+), 28 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index ac715bcf..37441d21 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -7,6 +7,9 @@ import java.io.File; import java.io.IOException; import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Set; public class Main { private static TestTraceResults[] readTraces(String filePathStr) throws IOException { @@ -16,46 +19,85 @@ private static TestTraceResults[] readTraces(String filePathStr) throws IOExcept public static void main(String[] args) throws Exception { TestTraceResults[] testTraceResultsList = readTraces(args[0]); - for (TestTraceResults testTraceResults : testTraceResultsList) { - VariableStackHandler variableStackHandler = new VariableStackHandler(); + Map>> packageTraceResults = new HashMap<>(); + + for (TestTraceResults testTraceResults : testTraceResultsList) { String[] splitTestName = testTraceResults.Test.split("\\."); String packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); String className = splitTestName[splitTestName.length - 2]; String testName = splitTestName[splitTestName.length - 1]; - if (!packageName.isEmpty()) { - System.out.printf("package %s;%n", packageName); - System.out.println(); + if (!packageTraceResults.containsKey(packageName)) { + packageTraceResults.put(packageName, new HashMap<>()); } - System.out.println("import com.fasterxml.jackson.core.JsonProcessingException;"); - System.out.println("import com.fasterxml.jackson.databind.ObjectMapper;"); - System.out.println("import org.junit.jupiter.api.Test;"); - System.out.println(); - System.out.println("import static org.junit.jupiter.api.Assertions.assertEquals;"); - System.out.println("import static org.junit.jupiter.api.Assertions.assertArrayEquals;"); - System.out.println(); - System.out.printf("public class %s {%n", className); - System.out.println("\t@Test"); - System.out.printf("\tpublic void %s() throws JsonProcessingException {%n", testName); - - Trace[] methodTraces = testTraceResults.Traces; - - for (int i = 0; i < methodTraces.length; i++) { - Trace trace = methodTraces[i]; - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t"); - System.out.println(traceCode); - - if (i != methodTraces.length - 1) { + if (!packageTraceResults.get(packageName).containsKey(className)) { + packageTraceResults.get(packageName).put(className, new HashMap<>()); + } + + if (!packageTraceResults.get(packageName).get(className).containsKey(testName)) { + packageTraceResults.get(packageName).get(className).put(testName, testTraceResults.Traces); + } + } + + for (Map.Entry>> packageTraces : packageTraceResults.entrySet()) { + String packageName = packageTraces.getKey(); + + Set>> classTracesForPackage = packageTraces.getValue().entrySet(); + + for (Map.Entry> classTraces : classTracesForPackage) { + String className = classTraces.getKey(); + + if (!packageName.isEmpty()) { + System.out.printf("package %s;%n", packageName); System.out.println(); } - } - System.out.println("\t}"); - System.out.println("}"); - System.out.println(); + System.out.println("import com.fasterxml.jackson.core.JsonProcessingException;"); + System.out.println("import com.fasterxml.jackson.databind.ObjectMapper;"); + System.out.println("import org.junit.jupiter.api.Test;"); + System.out.println(); + System.out.println("import static org.junit.jupiter.api.Assertions.assertEquals;"); + System.out.println("import static org.junit.jupiter.api.Assertions.assertArrayEquals;"); + System.out.println(); + + System.out.printf("public class %s {%n", className); + + Map.Entry[] testTracesForClass = classTraces.getValue().entrySet().toArray(Map.Entry[]::new); + + for (int j = 0; j < testTracesForClass.length; j++) { + Map.Entry testTraces = testTracesForClass[j]; + String testName = testTraces.getKey(); + + System.out.println("\t@Test"); + System.out.printf("\tpublic void %s() throws JsonProcessingException {%n", testName); + + VariableStackHandler variableStackHandler = new VariableStackHandler(); + + Trace[] methodTraces = testTraces.getValue(); + + for (int i = 0; i < methodTraces.length; i++) { + Trace trace = methodTraces[i]; + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t"); + System.out.println(traceCode); + + if (i != methodTraces.length - 1) { + System.out.println(); + } + } + + System.out.println("\t}"); + + if (j != testTracesForClass.length - 1) { + System.out.println(); + } + } + + System.out.println("}"); + System.out.println(); + } } } } \ No newline at end of file From ab74ab5e9b2834983f678541dbb506607c388ddc Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 10:30:50 +0100 Subject: [PATCH 076/244] Generate test classes directly --- .../github/maracas/gilesi/traceview/Main.java | 60 +++++++++++++------ run-clean-workflow.cmd | 3 +- run-test-workflow.cmd | 29 ++++++++- 3 files changed, 72 insertions(+), 20 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 37441d21..f006a33a 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -6,6 +6,8 @@ import java.io.File; import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; import java.util.Arrays; import java.util.HashMap; import java.util.Map; @@ -42,28 +44,48 @@ public static void main(String[] args) throws Exception { } } + Path mainOutputPath = Path.of("TraceView.Output").toAbsolutePath(); + if (!Files.isDirectory(mainOutputPath)) { + Files.createDirectories(mainOutputPath); + } + for (Map.Entry>> packageTraces : packageTraceResults.entrySet()) { String packageName = packageTraces.getKey(); + Path packageOutputPath = mainOutputPath.toAbsolutePath(); + + if (!packageName.isEmpty()) { + for (String element : packageName.split("\\.")) { + packageOutputPath = packageOutputPath.resolve(element); + } + + if (!Files.isDirectory(packageOutputPath)) { + Files.createDirectories(packageOutputPath); + } + } + Set>> classTracesForPackage = packageTraces.getValue().entrySet(); for (Map.Entry> classTraces : classTracesForPackage) { String className = classTraces.getKey(); + Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); + + StringBuilder stringBuilder = new StringBuilder(); + if (!packageName.isEmpty()) { - System.out.printf("package %s;%n", packageName); - System.out.println(); + stringBuilder.append("package %s;\n\n".formatted(packageName)); } - System.out.println("import com.fasterxml.jackson.core.JsonProcessingException;"); - System.out.println("import com.fasterxml.jackson.databind.ObjectMapper;"); - System.out.println("import org.junit.jupiter.api.Test;"); - System.out.println(); - System.out.println("import static org.junit.jupiter.api.Assertions.assertEquals;"); - System.out.println("import static org.junit.jupiter.api.Assertions.assertArrayEquals;"); - System.out.println(); + stringBuilder.append("import com.fasterxml.jackson.core.JsonProcessingException;\n"); + stringBuilder.append("import com.fasterxml.jackson.databind.ObjectMapper;\n"); + stringBuilder.append("import org.junit.jupiter.api.Test;\n"); + stringBuilder.append("\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); + stringBuilder.append("\n"); - System.out.printf("public class %s {%n", className); + stringBuilder.append("public class %s {\n".formatted(className)); Map.Entry[] testTracesForClass = classTraces.getValue().entrySet().toArray(Map.Entry[]::new); @@ -71,8 +93,8 @@ public static void main(String[] args) throws Exception { Map.Entry testTraces = testTracesForClass[j]; String testName = testTraces.getKey(); - System.out.println("\t@Test"); - System.out.printf("\tpublic void %s() throws JsonProcessingException {%n", testName); + stringBuilder.append("\t@Test\n"); + stringBuilder.append("\tpublic void %s() throws JsonProcessingException {\n".formatted(testName)); VariableStackHandler variableStackHandler = new VariableStackHandler(); @@ -81,22 +103,24 @@ public static void main(String[] args) throws Exception { for (int i = 0; i < methodTraces.length; i++) { Trace trace = methodTraces[i]; String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t"); - System.out.println(traceCode); + stringBuilder.append("%s\n".formatted(traceCode)); if (i != methodTraces.length - 1) { - System.out.println(); + stringBuilder.append("\n"); } } - System.out.println("\t}"); + stringBuilder.append("\t}\n"); if (j != testTracesForClass.length - 1) { - System.out.println(); + stringBuilder.append("\n"); } } - System.out.println("}"); - System.out.println(); + stringBuilder.append("}\n"); + stringBuilder.append("\n"); + + Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); } } } diff --git a/run-clean-workflow.cmd b/run-clean-workflow.cmd index 4a93a296..50871a59 100644 --- a/run-clean-workflow.cmd +++ b/run-clean-workflow.cmd @@ -23,4 +23,5 @@ cd Samples del sampleclient\MethodTraces.json cd .. -del %CD%\Samples\sampleclient\TraceView.Output.txt \ No newline at end of file +rmdir /Q /S %CD%\TraceView.Output +del %CD%\Samples\sampleclient\gilesi.instrumentation.log \ No newline at end of file diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 143f1893..894fd3b1 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -4,30 +4,57 @@ call run-clean-workflow.cmd set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 + + +echo Building Samples + REM build samples cd Samples call .\gradlew.bat jar cd .. + + +echo Building ConfGen + REM build confgen cd ConfGen call .\gradlew.bat shadowJar cd .. + + +echo Building TraceView + REM build traceview cd TraceView call .\gradlew.bat shadowJar cd .. + +echo Building Agent + REM build tool cd Instrumentation call .\gradlew.bat shadowJar cd .. + + +echo Running ConfGen + %JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.json" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" + + +echo Running Sample's Client Test Suite with Agent + cd Samples call .\gradlew.bat sampleclient:test cd .. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" > %CD%\Samples\sampleclient\TraceView.Output.txt \ No newline at end of file + + +echo Running TraceView + +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" \ No newline at end of file From 81e4ffeba9254c8928983fabd94ef241b2df2366 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 11:10:10 +0100 Subject: [PATCH 077/244] Update dependencies and script improvements --- .gitignore | 3 +- ConfGen/build.gradle | 2 +- Instrumentation/build.gradle | 8 +---- Samples/sampleclient/build.gradle | 21 ++++++++---- TraceView/build.gradle | 2 +- run-clean-workflow.cmd | 9 +---- run-test-workflow.cmd | 55 +++++++++++++++++++++++-------- 7 files changed, 62 insertions(+), 38 deletions(-) diff --git a/.gitignore b/.gitignore index 0569916f..3abf9ae2 100644 --- a/.gitignore +++ b/.gitignore @@ -148,4 +148,5 @@ fabric.properties # End of https://www.toptal.com/developers/gitignore/api/jetbrains *.db -.vscode/ \ No newline at end of file +.vscode/ +Results/ \ No newline at end of file diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index 38cfbf3e..dc5afcc8 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.johnrengelman.shadow' version '7.0.0' + id 'com.github.johnrengelman.shadow' version '8.1.1' } group 'com.github.maracas.gilesi.confgen' diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 21320b39..d65c40c4 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.johnrengelman.shadow' version '7.0.0' + id 'com.github.johnrengelman.shadow' version '8.1.1' } java { @@ -19,8 +19,6 @@ dependencies { implementation 'net.bytebuddy:byte-buddy:1.14.2' implementation 'net.bytebuddy:byte-buddy-agent:1.14.2' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' - testImplementation platform('org.junit:junit-bom:5.9.2') - testImplementation 'org.junit.jupiter:junit-jupiter:5.9.2' } jar { @@ -62,8 +60,4 @@ idea { downloadJavadoc = true downloadSources = true } -} - -test { - useJUnitPlatform() } \ No newline at end of file diff --git a/Samples/sampleclient/build.gradle b/Samples/sampleclient/build.gradle index ae58e2d2..d070c8c1 100644 --- a/Samples/sampleclient/build.gradle +++ b/Samples/sampleclient/build.gradle @@ -12,12 +12,21 @@ repositories { dependencies { implementation project(':samplelibrary') implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.1' - testImplementation platform('org.junit:junit-bom:5.9.1') - testImplementation 'org.junit.jupiter:junit-jupiter' } -test { - useJUnitPlatform() - systemProperty 'net.bytebuddy.experimental', 'true' - jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.maracas.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.json"'] +testing { + suites { + test { + useJUnitJupiter() + + targets { + all { + testTask.configure { + systemProperty 'net.bytebuddy.experimental', 'true' + jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.maracas.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.json"'] + } + } + } + } + } } \ No newline at end of file diff --git a/TraceView/build.gradle b/TraceView/build.gradle index c8c091b6..54b6c322 100644 --- a/TraceView/build.gradle +++ b/TraceView/build.gradle @@ -1,6 +1,6 @@ plugins { id 'application' - id 'com.github.johnrengelman.shadow' version '7.0.0' + id 'com.github.johnrengelman.shadow' version '8.1.1' } group 'com.github.maracas.gilesi.traceview' diff --git a/run-clean-workflow.cmd b/run-clean-workflow.cmd index 50871a59..0aa03a09 100644 --- a/run-clean-workflow.cmd +++ b/run-clean-workflow.cmd @@ -17,11 +17,4 @@ cd Instrumentation rmdir /Q /S build cd .. -del "%CD%\TestWorkflowConfiguration.json" - -cd Samples -del sampleclient\MethodTraces.json -cd .. - -rmdir /Q /S %CD%\TraceView.Output -del %CD%\Samples\sampleclient\gilesi.instrumentation.log \ No newline at end of file +rmdir /Q /S Results \ No newline at end of file diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 894fd3b1..94f0ebf5 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -4,57 +4,84 @@ call run-clean-workflow.cmd set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 - - +echo. +echo =========================================================== echo Building Samples +echo =========================================================== +echo. REM build samples cd Samples -call .\gradlew.bat jar +call .\gradlew.bat jar --warning-mode all cd .. - +echo. +echo =========================================================== echo Building ConfGen +echo =========================================================== +echo. REM build confgen cd ConfGen -call .\gradlew.bat shadowJar +call .\gradlew.bat shadowJar --warning-mode all cd .. - +echo. +echo =========================================================== echo Building TraceView +echo =========================================================== +echo. REM build traceview cd TraceView -call .\gradlew.bat shadowJar +call .\gradlew.bat shadowJar --warning-mode all cd .. - +echo. +echo =========================================================== echo Building Agent +echo =========================================================== +echo. REM build tool cd Instrumentation -call .\gradlew.bat shadowJar +call .\gradlew.bat shadowJar --warning-mode all cd .. - +echo. +echo =========================================================== echo Running ConfGen +echo =========================================================== +echo. %JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.json" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" - +echo. +echo =========================================================== echo Running Sample's Client Test Suite with Agent +echo =========================================================== +echo. cd Samples -call .\gradlew.bat sampleclient:test +call .\gradlew.bat sampleclient:test --warning-mode all cd .. - +echo. +echo =========================================================== echo Running TraceView +echo =========================================================== +echo. + +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" + +mkdir Results -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" \ No newline at end of file +move %CD%\TestWorkflowConfiguration.json Results\ +move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ +move %CD%\Samples\sampleclient\MethodTraces.json Results\ +move %CD%\TraceView.Output Results\ \ No newline at end of file From b7e16e8f5422dd96b791193e38827d2da6e4b88f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 11:45:42 +0100 Subject: [PATCH 078/244] fixes --- .../gilesi/instrumentation/TraceDataFactory.java | 4 +++- .../maracas/gilesi/samples/samplelibrary/A.java | 2 +- .../gilesi/traceview/TestMethodGenerator.java | 12 ++++-------- 3 files changed, 8 insertions(+), 10 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 6b80abfa..607fa937 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -4,9 +4,11 @@ import com.github.maracas.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { + private static int NullCounter = 0; + public static TraceData valueOf(Object object) { if (object == null) { - return null; + return new TraceData("Object", "null", ++NullCounter * -1); } // /!\ CAUTION diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java index 85ea31e6..8fbe7311 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.samples.samplelibrary; public class A { - private int j; + private final int j; public A(int j) { this.j = j; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index 19229517..efced48d 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -8,9 +8,10 @@ public class TestMethodGenerator { private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler) throws Exception { - if (arg == null) { - return "null"; - } else if (arg.getDataAsJson() != null) { + if (arg.getDataAsJson() != null) { + if (arg.getDataAsJson().equals("null")) { + return arg.getDataAsJson(); + } return SerializationUtils.serializableDataToJava(arg); } else if (variableStackHandler.isInstanceVariableNameDefined(arg.getInstanceId())) { return variableStackHandler.getInstanceVariableName(arg.getInstanceId()); @@ -73,11 +74,6 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab List variableList = new ArrayList<>(); for (TraceData arg : methodTrace.getPreCallArguments()) { - if (arg == null) { - argList.add("null"); - continue; - } - String argumentValue = serializableDataToCode(arg, variableStackHandler); String argumentVariable = getDataVariableDeclaration(arg, variableStackHandler); String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); From 21bfa60b1a6fc7c941777174217148ad8be1837f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 12:10:17 +0100 Subject: [PATCH 079/244] Fixes --- .../gilesi/instrumentation/TraceFactory.java | 20 +- MaracasConfiguration.json | 871 ------------------ .../traceview/VariableStackHandler.java | 2 + compile.cmd | 37 + maracas-test.cmd | 51 +- run-test-workflow.cmd | 37 +- 6 files changed, 86 insertions(+), 932 deletions(-) delete mode 100644 MaracasConfiguration.json create mode 100644 compile.cmd diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index c88a1687..9928b05b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -66,7 +66,10 @@ private static List getArgumentsAsSerializableData(Object[] arguments */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { String methodSignature = getOriginName(origin); - TraceData serializableInstance = TraceDataFactory.valueOf(instance); + TraceData serializableInstance = null; + if (instance != null) { + serializableInstance = TraceDataFactory.valueOf(instance); + } List preCallArguments = getArgumentsAsSerializableData(arguments); return new PartialTrace(methodSignature, serializableInstance, preCallArguments, 0); @@ -92,12 +95,21 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String[] stackTrace) { String methodSignature = getOriginName(origin); - TraceData serializableInstance = TraceDataFactory.valueOf(instance); + TraceData serializableInstance = null; + if (instance != null) { + serializableInstance = TraceDataFactory.valueOf(instance); + } List preCallArguments = originatingTrace.getPreCallArguments(); List postCallArguments = getArgumentsAsSerializableData(arguments); - TraceData returnedValue = TraceDataFactory.valueOf(returned); + TraceData returnedValue = null; // TODO: Detect if the method returns nothing or not here! + if (returned != null) { + returnedValue = TraceDataFactory.valueOf(returned); + } long timeStampEntry = originatingTrace.getTimeStampEntry(); - TraceData exceptionThrown = TraceDataFactory.valueOf(thrown); + TraceData exceptionThrown = null; + if (thrown != null) { + exceptionThrown = TraceDataFactory.valueOf(thrown); + } return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, 0, exceptionThrown, stackTrace); } diff --git a/MaracasConfiguration.json b/MaracasConfiguration.json deleted file mode 100644 index 9b807c1c..00000000 --- a/MaracasConfiguration.json +++ /dev/null @@ -1,871 +0,0 @@ -{ - "Classes" : [ { - "Name" : "com.github.maracas.visitors.FieldNowFinalVisitor", - "Methods" : [ { - "Name" : "visitCtFieldWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.CombinedVisitor", - "Methods" : [ { - "Name" : "getBrokenUses", - "Descriptors" : [ "()Ljava/util/Set;" ] - }, { - "Name" : "visitCtAnnotation", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotation;)V" ] - }, { - "Name" : "visitCtAnnotationFieldAccess", - "Descriptors" : [ "(Lspoon/reflect/code/CtAnnotationFieldAccess;)V" ] - }, { - "Name" : "visitCtAnnotationMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotationMethod;)V" ] - }, { - "Name" : "visitCtAnnotationType", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnnotationType;)V" ] - }, { - "Name" : "visitCtAnonymousExecutable", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtAnonymousExecutable;)V" ] - }, { - "Name" : "visitCtArrayRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtArrayRead;)V" ] - }, { - "Name" : "visitCtArrayTypeReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtArrayTypeReference;)V" ] - }, { - "Name" : "visitCtArrayWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtArrayWrite;)V" ] - }, { - "Name" : "visitCtAssert", - "Descriptors" : [ "(Lspoon/reflect/code/CtAssert;)V" ] - }, { - "Name" : "visitCtAssignment", - "Descriptors" : [ "(Lspoon/reflect/code/CtAssignment;)V" ] - }, { - "Name" : "visitCtBinaryOperator", - "Descriptors" : [ "(Lspoon/reflect/code/CtBinaryOperator;)V" ] - }, { - "Name" : "visitCtBlock", - "Descriptors" : [ "(Lspoon/reflect/code/CtBlock;)V" ] - }, { - "Name" : "visitCtBreak", - "Descriptors" : [ "(Lspoon/reflect/code/CtBreak;)V" ] - }, { - "Name" : "visitCtCase", - "Descriptors" : [ "(Lspoon/reflect/code/CtCase;)V" ] - }, { - "Name" : "visitCtCatch", - "Descriptors" : [ "(Lspoon/reflect/code/CtCatch;)V" ] - }, { - "Name" : "visitCtCatchVariable", - "Descriptors" : [ "(Lspoon/reflect/code/CtCatchVariable;)V" ] - }, { - "Name" : "visitCtCatchVariableReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtCatchVariableReference;)V" ] - }, { - "Name" : "visitCtClass", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] - }, { - "Name" : "visitCtCodeSnippetExpression", - "Descriptors" : [ "(Lspoon/reflect/code/CtCodeSnippetExpression;)V" ] - }, { - "Name" : "visitCtCodeSnippetStatement", - "Descriptors" : [ "(Lspoon/reflect/code/CtCodeSnippetStatement;)V" ] - }, { - "Name" : "visitCtComment", - "Descriptors" : [ "(Lspoon/reflect/code/CtComment;)V" ] - }, { - "Name" : "visitCtCompilationUnit", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtCompilationUnit;)V" ] - }, { - "Name" : "visitCtConditional", - "Descriptors" : [ "(Lspoon/reflect/code/CtConditional;)V" ] - }, { - "Name" : "visitCtConstructor", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtConstructor;)V" ] - }, { - "Name" : "visitCtConstructorCall", - "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] - }, { - "Name" : "visitCtContinue", - "Descriptors" : [ "(Lspoon/reflect/code/CtContinue;)V" ] - }, { - "Name" : "visitCtDo", - "Descriptors" : [ "(Lspoon/reflect/code/CtDo;)V" ] - }, { - "Name" : "visitCtEnum", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtEnum;)V" ] - }, { - "Name" : "visitCtEnumValue", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtEnumValue;)V" ] - }, { - "Name" : "visitCtExecutableReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "visitCtExecutableReferenceExpression", - "Descriptors" : [ "(Lspoon/reflect/code/CtExecutableReferenceExpression;)V" ] - }, { - "Name" : "visitCtField", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtField;)V" ] - }, { - "Name" : "visitCtFieldRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] - }, { - "Name" : "visitCtFieldReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "visitCtFieldWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] - }, { - "Name" : "visitCtFor", - "Descriptors" : [ "(Lspoon/reflect/code/CtFor;)V" ] - }, { - "Name" : "visitCtForEach", - "Descriptors" : [ "(Lspoon/reflect/code/CtForEach;)V" ] - }, { - "Name" : "visitCtIf", - "Descriptors" : [ "(Lspoon/reflect/code/CtIf;)V" ] - }, { - "Name" : "visitCtImport", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtImport;)V" ] - }, { - "Name" : "visitCtInterface", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtInterface;)V" ] - }, { - "Name" : "visitCtIntersectionTypeReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtIntersectionTypeReference;)V" ] - }, { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - }, { - "Name" : "visitCtJavaDoc", - "Descriptors" : [ "(Lspoon/reflect/code/CtJavaDoc;)V" ] - }, { - "Name" : "visitCtJavaDocTag", - "Descriptors" : [ "(Lspoon/reflect/code/CtJavaDocTag;)V" ] - }, { - "Name" : "visitCtLambda", - "Descriptors" : [ "(Lspoon/reflect/code/CtLambda;)V" ] - }, { - "Name" : "visitCtLiteral", - "Descriptors" : [ "(Lspoon/reflect/code/CtLiteral;)V" ] - }, { - "Name" : "visitCtLocalVariable", - "Descriptors" : [ "(Lspoon/reflect/code/CtLocalVariable;)V" ] - }, { - "Name" : "visitCtLocalVariableReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtLocalVariableReference;)V" ] - }, { - "Name" : "visitCtMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] - }, { - "Name" : "visitCtModule", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtModule;)V" ] - }, { - "Name" : "visitCtModuleReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtModuleReference;)V" ] - }, { - "Name" : "visitCtModuleRequirement", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtModuleRequirement;)V" ] - }, { - "Name" : "visitCtNewArray", - "Descriptors" : [ "(Lspoon/reflect/code/CtNewArray;)V" ] - }, { - "Name" : "visitCtNewClass", - "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] - }, { - "Name" : "visitCtOperatorAssignment", - "Descriptors" : [ "(Lspoon/reflect/code/CtOperatorAssignment;)V" ] - }, { - "Name" : "visitCtPackage", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] - }, { - "Name" : "visitCtPackageDeclaration", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackageDeclaration;)V" ] - }, { - "Name" : "visitCtPackageExport", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackageExport;)V" ] - }, { - "Name" : "visitCtPackageReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtPackageReference;)V" ] - }, { - "Name" : "visitCtParameter", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtParameter;)V" ] - }, { - "Name" : "visitCtParameterReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtParameterReference;)V" ] - }, { - "Name" : "visitCtProvidedService", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtProvidedService;)V" ] - }, { - "Name" : "visitCtReturn", - "Descriptors" : [ "(Lspoon/reflect/code/CtReturn;)V" ] - }, { - "Name" : "visitCtStatementList", - "Descriptors" : [ "(Lspoon/reflect/code/CtStatementList;)V" ] - }, { - "Name" : "visitCtSuperAccess", - "Descriptors" : [ "(Lspoon/reflect/code/CtSuperAccess;)V" ] - }, { - "Name" : "visitCtSwitch", - "Descriptors" : [ "(Lspoon/reflect/code/CtSwitch;)V" ] - }, { - "Name" : "visitCtSwitchExpression", - "Descriptors" : [ "(Lspoon/reflect/code/CtSwitchExpression;)V" ] - }, { - "Name" : "visitCtSynchronized", - "Descriptors" : [ "(Lspoon/reflect/code/CtSynchronized;)V" ] - }, { - "Name" : "visitCtTextBlock", - "Descriptors" : [ "(Lspoon/reflect/code/CtTextBlock;)V" ] - }, { - "Name" : "visitCtThisAccess", - "Descriptors" : [ "(Lspoon/reflect/code/CtThisAccess;)V" ] - }, { - "Name" : "visitCtThrow", - "Descriptors" : [ "(Lspoon/reflect/code/CtThrow;)V" ] - }, { - "Name" : "visitCtTry", - "Descriptors" : [ "(Lspoon/reflect/code/CtTry;)V" ] - }, { - "Name" : "visitCtTryWithResource", - "Descriptors" : [ "(Lspoon/reflect/code/CtTryWithResource;)V" ] - }, { - "Name" : "visitCtTypeAccess", - "Descriptors" : [ "(Lspoon/reflect/code/CtTypeAccess;)V" ] - }, { - "Name" : "visitCtTypeMemberWildcardImportReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeMemberWildcardImportReference;)V" ] - }, { - "Name" : "visitCtTypeParameter", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtTypeParameter;)V" ] - }, { - "Name" : "visitCtTypeParameterReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeParameterReference;)V" ] - }, { - "Name" : "visitCtTypeReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "visitCtUnaryOperator", - "Descriptors" : [ "(Lspoon/reflect/code/CtUnaryOperator;)V" ] - }, { - "Name" : "visitCtUnboundVariableReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtUnboundVariableReference;)V" ] - }, { - "Name" : "visitCtUsedService", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtUsedService;)V" ] - }, { - "Name" : "visitCtVariableRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtVariableRead;)V" ] - }, { - "Name" : "visitCtVariableWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtVariableWrite;)V" ] - }, { - "Name" : "visitCtWhile", - "Descriptors" : [ "(Lspoon/reflect/code/CtWhile;)V" ] - }, { - "Name" : "visitCtWildcardReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtWildcardReference;)V" ] - }, { - "Name" : "visitCtYieldStatement", - "Descriptors" : [ "(Lspoon/reflect/code/CtYieldStatement;)V" ] - } ], - "Descriptors" : [ "(Ljava/util/Collection;Lcom/github/maracas/MaracasOptions;)V" ] - }, { - "Name" : "com.github.maracas.visitors.FieldRemovedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "com.github.maracas.LibraryJar", - "Methods" : [ { - "Name" : "buildModel", - "Descriptors" : [ "()Lspoon/reflect/CtModel;" ] - }, { - "Name" : "equals", - "Descriptors" : [ "(Ljava/lang/Object;)Z" ] - }, { - "Name" : "getClasspath", - "Descriptors" : [ "()Ljava/util/List;" ] - }, { - "Name" : "getJar", - "Descriptors" : [ "()Ljava/nio/file/Path;" ] - }, { - "Name" : "getLabel", - "Descriptors" : [ "()Ljava/lang/String;" ] - }, { - "Name" : "getSources", - "Descriptors" : [ "()Lcom/github/maracas/SourcesDirectory;" ] - }, { - "Name" : "hasSources", - "Descriptors" : [ "()Z" ] - }, { - "Name" : "hashCode", - "Descriptors" : [ "()I" ] - }, { - "Name" : "setNoClasspath", - "Descriptors" : [ "(Z)V" ] - }, { - "Name" : "setSources", - "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;)V" ] - }, { - "Name" : "toString", - "Descriptors" : [ "()Ljava/lang/String;" ] - }, { - "Name" : "withSources", - "Descriptors" : [ "(Ljava/nio/file/Path;Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/LibraryJar;", "(Ljava/nio/file/Path;Ljava/nio/file/Path;)Lcom/github/maracas/LibraryJar;" ] - }, { - "Name" : "withoutSources", - "Descriptors" : [ "(Ljava/nio/file/Path;)Lcom/github/maracas/LibraryJar;" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.delta.AbstractBreakingChange", - "Methods" : [ { - "Name" : "getChange", - "Descriptors" : [ "()Ljapicmp/model/JApiCompatibilityChange;" ] - }, { - "Name" : "getSourceElement", - "Descriptors" : [ "()Lspoon/reflect/declaration/CtElement;" ] - }, { - "Name" : "setSourceElement", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)V" ] - } ], - "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.util.SpoonHelpers", - "Methods" : [ { - "Name" : "buildSpoonSignature", - "Descriptors" : [ "(Ljapicmp/model/JApiConstructor;)Ljava/lang/String;", "(Ljapicmp/model/JApiMethod;)Ljava/lang/String;" ] - }, { - "Name" : "firstLocatableParent", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lspoon/reflect/declaration/CtElement;" ] - }, { - "Name" : "fullyQualifiedName", - "Descriptors" : [ "(Lspoon/reflect/reference/CtReference;)Ljava/lang/String;" ] - }, { - "Name" : "getEnclosingPkgName", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Ljava/lang/String;" ] - }, { - "Name" : "isImplicit", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Z" ] - }, { - "Name" : "matchingSignatures", - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Ljavassist/CtBehavior;)Z" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.visitors.FieldLessAccessibleVisitor", - "Methods" : [ { - "Name" : "visitCtFieldRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] - }, { - "Name" : "visitCtFieldWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/AccessModifier;)V" ] - }, { - "Name" : "com.github.maracas.visitors.FieldReferenceVisitor", - "Methods" : [ { - "Name" : "visitCtFieldReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.util.PathHelpers", - "Methods" : [ { - "Name" : "isValidDirectory", - "Descriptors" : [ "(Ljava/nio/file/Path;)Z" ] - }, { - "Name" : "isValidJar", - "Descriptors" : [ "(Ljava/nio/file/Path;)Z" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.visitors.FieldTypeChangedVisitor", - "Methods" : [ { - "Name" : "visitCtFieldRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] - }, { - "Name" : "visitCtFieldWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.MethodAddedToInterfaceVisitor", - "Methods" : [ { - "Name" : "visitCtClass", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.SupertypeRemovedVisitor", - "Methods" : [ { - "Name" : "visitCtAssignment", - "Descriptors" : [ "(Lspoon/reflect/code/CtAssignment;)V" ] - }, { - "Name" : "visitCtFieldReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - }, { - "Name" : "visitCtLocalVariable", - "Descriptors" : [ "(Lspoon/reflect/code/CtLocalVariable;)V" ] - }, { - "Name" : "visitCtMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.brokenuse.APIUse", - "Methods" : [ ], - "Descriptors" : [ "()V" ] - }, { - "Name" : "com.github.maracas.visitors.FieldNowStaticVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ClassRemovedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.util.BinaryToSourceMapper", - "Methods" : [ { - "Name" : "resolve", - "Descriptors" : [ "(Lspoon/reflect/reference/CtReference;)Lspoon/reflect/declaration/CtElement;" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] - }, { - "Name" : "com.github.maracas.visitors.InterfaceAddedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;)V" ] - }, { - "Name" : "com.github.maracas.visitors.InterfaceRemovedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;)V" ] - }, { - "Name" : "com.github.maracas.util.CtElementSerializer", - "Methods" : [ { - "Name" : "serialize", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;Lcom/fasterxml/jackson/core/JsonGenerator;Lcom/fasterxml/jackson/databind/SerializerProvider;)V" ] - } ], - "Descriptors" : [ "()V", "(Ljava/lang/Class;)V" ] - }, { - "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToFieldVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ClassNowAbstractVisitor", - "Methods" : [ { - "Name" : "visitCtConstructorCall", - "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.MaracasOptions", - "Methods" : [ { - "Name" : "defaultJApiOptions", - "Descriptors" : [ "()Ljapicmp/config/Options;" ] - }, { - "Name" : "excludeBreakingChange", - "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "getBuildTimeout", - "Descriptors" : [ "()Ljava/time/Duration;" ] - }, { - "Name" : "getClientsPerModule", - "Descriptors" : [ "()I" ] - }, { - "Name" : "getCloneTimeout", - "Descriptors" : [ "()Ljava/time/Duration;" ] - }, { - "Name" : "getExcludedBreakingChanges", - "Descriptors" : [ "()Ljava/util/Set;" ] - }, { - "Name" : "getJApiOptions", - "Descriptors" : [ "()Ljapicmp/config/Options;" ] - }, { - "Name" : "getMaxClassLines", - "Descriptors" : [ "()I" ] - }, { - "Name" : "getMinStarsPerClient", - "Descriptors" : [ "()I" ] - }, { - "Name" : "newDefault", - "Descriptors" : [ "()Lcom/github/maracas/MaracasOptions;" ] - }, { - "Name" : "setBuildTimeout", - "Descriptors" : [ "(Ljava/time/Duration;)V" ] - }, { - "Name" : "setClientsPerModule", - "Descriptors" : [ "(I)V" ] - }, { - "Name" : "setCloneTimeout", - "Descriptors" : [ "(Ljava/time/Duration;)V" ] - }, { - "Name" : "setMaxClassLines", - "Descriptors" : [ "(I)V" ] - }, { - "Name" : "setMinStarsPerClient", - "Descriptors" : [ "(I)V" ] - } ], - "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor", - "Methods" : [ { - "Name" : "visitCtThrow", - "Descriptors" : [ "(Lspoon/reflect/code/CtThrow;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.util.ParentLastURLClassLoader", - "Methods" : [ { - "Name" : "loadClass", - "Descriptors" : [ "(Ljava/lang/String;Z)Ljava/lang/Class;" ] - } ], - "Descriptors" : [ "([Ljava/net/URL;)V", "([Ljava/net/URL;Ljava/lang/ClassLoader;)V" ] - }, { - "Name" : "com.github.maracas.delta.Delta", - "Methods" : [ { - "Name" : "fromJApiCmpDelta", - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Ljava/util/List;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/delta/Delta;" ] - }, { - "Name" : "getBreakingChanges", - "Descriptors" : [ "()Ljava/util/List;" ] - }, { - "Name" : "getNewVersion", - "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] - }, { - "Name" : "getOldVersion", - "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] - }, { - "Name" : "getVisitors", - "Descriptors" : [ "()Ljava/util/List;" ] - }, { - "Name" : "isEmpty", - "Descriptors" : [ "()Z" ] - }, { - "Name" : "populateLocations", - "Descriptors" : [ "()V" ] - }, { - "Name" : "toJson", - "Descriptors" : [ "()Ljava/lang/String;" ] - }, { - "Name" : "toString", - "Descriptors" : [ "()Ljava/lang/String;" ] - } ], - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Ljava/util/List;)V" ] - }, { - "Name" : "com.github.maracas.Maracas", - "Methods" : [ { - "Name" : "analyze", - "Descriptors" : [ "(Lcom/github/maracas/AnalysisQuery;)Lcom/github/maracas/AnalysisResult;" ] - }, { - "Name" : "computeDelta", - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/delta/Delta;", "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/delta/Delta;" ] - }, { - "Name" : "computeDeltaImpact", - "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;Lcom/github/maracas/delta/Delta;)Lcom/github/maracas/brokenuse/DeltaImpact;", "(Lcom/github/maracas/SourcesDirectory;Lcom/github/maracas/delta/Delta;Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/brokenuse/DeltaImpact;" ] - } ], - "Descriptors" : [ "()V" ] - }, { - "Name" : "com.github.maracas.AnalysisQuery", - "Methods" : [ { - "Name" : "builder", - "Descriptors" : [ "()Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "getClients", - "Descriptors" : [ "()Ljava/util/Collection;" ] - }, { - "Name" : "getMaracasOptions", - "Descriptors" : [ "()Lcom/github/maracas/MaracasOptions;" ] - }, { - "Name" : "getNewVersion", - "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] - }, { - "Name" : "getOldVersion", - "Descriptors" : [ "()Lcom/github/maracas/LibraryJar;" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.visitors.MethodNowFinalVisitor", - "Methods" : [ { - "Name" : "visitCtMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.SuperclassRemovedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.MethodRemovedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.MethodReturnTypeChangedVisitor", - "Methods" : [ { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - }, { - "Name" : "visitCtMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ConstructorRemovedVisitor", - "Methods" : [ { - "Name" : "visitCtConstructorCall", - "Descriptors" : [ "(Lspoon/reflect/code/CtConstructorCall;)V" ] - }, { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - }, { - "Name" : "visitCtNewClass", - "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ClassNowFinalVisitor", - "Methods" : [ { - "Name" : "visitCtClass", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] - }, { - "Name" : "visitCtNewClass", - "Descriptors" : [ "(Lspoon/reflect/code/CtNewClass;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.SupertypeAddedVisitor", - "Methods" : [ { - "Name" : "visitCtClass", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljava/util/Set;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToClassVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.util.SpoonTypeHelpers", - "Methods" : [ { - "Name" : "haveUnimplAbstractMethods", - "Descriptors" : [ "(Ljava/util/Set;)Z" ] - }, { - "Name" : "inferExpectedType", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lspoon/reflect/reference/CtTypeReference;" ] - }, { - "Name" : "isAssignableFrom", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isAssignableFromOverride", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isBoxedType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isNarrowedPrimitiveType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isNarrowedType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isSubtype", - "Descriptors" : [ "(Ljava/util/Set;Lspoon/reflect/reference/CtTypeReference;)Z", "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isUnboxedType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isWidenedPrimitiveType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - }, { - "Name" : "isWidenedType", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)Z" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.delta.JApiCmpToSpoonVisitor", - "Methods" : [ { - "Name" : "getBreakingChanges", - "Descriptors" : [ "()Ljava/util/List;" ] - }, { - "Name" : "visit", - "Descriptors" : [ "(Ljapicmp/model/JApiAnnotation;)V", "(Ljapicmp/model/JApiClass;)V", "(Ljapicmp/model/JApiClass;Ljapicmp/model/JApiImplementedInterface;)V", "(Ljapicmp/model/JApiConstructor;)V", "(Ljapicmp/model/JApiField;)V", "(Ljapicmp/model/JApiImplementedInterface;)V", "(Ljapicmp/model/JApiMethod;)V", "(Ljapicmp/model/JApiSuperclass;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/declaration/CtPackage;)V" ] - }, { - "Name" : "com.github.maracas.util.GradleLauncher", - "Methods" : [ { - "Name" : "init", - "Descriptors" : [ "(Ljava/nio/file/Path;)V" ] - } ], - "Descriptors" : [ "(Ljava/nio/file/Path;)V" ] - }, { - "Name" : "com.github.maracas.SourcesDirectory", - "Methods" : [ { - "Name" : "buildModel", - "Descriptors" : [ "()Lspoon/reflect/CtModel;" ] - }, { - "Name" : "equals", - "Descriptors" : [ "(Ljava/lang/Object;)Z" ] - }, { - "Name" : "getLocation", - "Descriptors" : [ "()Ljava/nio/file/Path;" ] - }, { - "Name" : "hashCode", - "Descriptors" : [ "()I" ] - }, { - "Name" : "of", - "Descriptors" : [ "(Ljava/nio/file/Path;)Lcom/github/maracas/SourcesDirectory;" ] - }, { - "Name" : "setClasspath", - "Descriptors" : [ "(Ljava/util/List;)V" ] - }, { - "Name" : "toString", - "Descriptors" : [ "()Ljava/lang/String;" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.visitors.FieldNoLongerStaticVisitor", - "Methods" : [ { - "Name" : "visitCtFieldRead", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldRead;)V" ] - }, { - "Name" : "visitCtFieldWrite", - "Descriptors" : [ "(Lspoon/reflect/code/CtFieldWrite;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtFieldReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.SuperclassAddedVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Lspoon/reflect/reference/CtTypeReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.TypeReferenceVisitor", - "Methods" : [ { - "Name" : "visitCtTypeReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.delta.FieldBreakingChange", - "Methods" : [ { - "Name" : "getReference", - "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] - }, { - "Name" : "getVisitor", - "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] - } ], - "Descriptors" : [ "(Ljapicmp/model/JApiField;Lspoon/reflect/reference/CtFieldReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.visitors.ClassLessAccessibleVisitor", - "Methods" : [ { - "Name" : "visitCtTypeReference", - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/AccessModifier;)V" ] - }, { - "Name" : "com.github.maracas.AnalysisQuery$Builder", - "Methods" : [ { - "Name" : "build", - "Descriptors" : [ "()Lcom/github/maracas/AnalysisQuery;" ] - }, { - "Name" : "client", - "Descriptors" : [ "(Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "clients", - "Descriptors" : [ "([Lcom/github/maracas/SourcesDirectory;)Lcom/github/maracas/AnalysisQuery$Builder;", "(Ljava/util/Collection;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "exclude", - "Descriptors" : [ "(Ljava/lang/String;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "newVersion", - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "of", - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "oldVersion", - "Descriptors" : [ "(Lcom/github/maracas/LibraryJar;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - }, { - "Name" : "options", - "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)Lcom/github/maracas/AnalysisQuery$Builder;" ] - } ], - "Descriptors" : [ ] - }, { - "Name" : "com.github.maracas.MaracasCLI", - "Methods" : [ { - "Name" : "main", - "Descriptors" : [ "([Ljava/lang/String;)V" ] - }, { - "Name" : "run", - "Descriptors" : [ "()V" ] - } ], - "Descriptors" : [ "()V" ] - }, { - "Name" : "com.github.maracas.delta.TypeBreakingChange", - "Methods" : [ { - "Name" : "getReference", - "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] - }, { - "Name" : "getVisitor", - "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] - } ], - "Descriptors" : [ "(Ljapicmp/model/JApiClass;Lspoon/reflect/reference/CtTypeReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.visitors.BreakingChangeVisitor", - "Methods" : [ { - "Name" : "brokenUse", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;Lspoon/reflect/declaration/CtElement;Lspoon/reflect/reference/CtReference;Lcom/github/maracas/brokenuse/APIUse;)V" ] - }, { - "Name" : "getAPIUseByRole", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtElement;)Lcom/github/maracas/brokenuse/APIUse;" ] - }, { - "Name" : "getBrokenUses", - "Descriptors" : [ "()Ljava/util/Set;" ] - } ], - "Descriptors" : [ "(Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.visitors.MethodNowAbstractVisitor", - "Methods" : [ { - "Name" : "visitCtClass", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtClass;)V" ] - }, { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "com.github.maracas.delta.JApiCmpDeltaFilter", - "Methods" : [ { - "Name" : "filter", - "Descriptors" : [ "(Ljava/util/List;)V" ] - } ], - "Descriptors" : [ "(Lcom/github/maracas/MaracasOptions;)V" ] - }, { - "Name" : "com.github.maracas.delta.MethodBreakingChange", - "Methods" : [ { - "Name" : "getReference", - "Descriptors" : [ "()Lspoon/reflect/reference/CtReference;" ] - }, { - "Name" : "getVisitor", - "Descriptors" : [ "()Lcom/github/maracas/visitors/BreakingChangeVisitor;" ] - } ], - "Descriptors" : [ "(Ljapicmp/model/JApiBehavior;Lspoon/reflect/reference/CtExecutableReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - }, { - "Name" : "com.github.maracas.visitors.AnnotationDeprecatedAddedToMethodVisitor", - "Methods" : [ ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;)V" ] - }, { - "Name" : "com.github.maracas.visitors.MethodReferenceVisitor", - "Methods" : [ { - "Name" : "visitCtInvocation", - "Descriptors" : [ "(Lspoon/reflect/code/CtInvocation;)V" ] - }, { - "Name" : "visitCtMethod", - "Descriptors" : [ "(Lspoon/reflect/declaration/CtMethod;)V" ] - } ], - "Descriptors" : [ "(Lspoon/reflect/reference/CtExecutableReference;Ljapicmp/model/JApiCompatibilityChange;)V" ] - } ], - "LibraryMethods" : [ "com.github.maracas.AnalysisQuery.builder", "com.github.maracas.AnalysisQuery.getClients", "com.github.maracas.AnalysisQuery.getMaracasOptions", "com.github.maracas.AnalysisQuery.getNewVersion", "com.github.maracas.AnalysisQuery.getOldVersion", "com.github.maracas.LibraryJar.buildClasspath", "com.github.maracas.LibraryJar.buildClasspathFromPom", "com.github.maracas.LibraryJar.buildModel", "com.github.maracas.LibraryJar.equals", "com.github.maracas.LibraryJar.extractPomFromJar", "com.github.maracas.LibraryJar.getClasspath", "com.github.maracas.LibraryJar.getJar", "com.github.maracas.LibraryJar.getLabel", "com.github.maracas.LibraryJar.getSources", "com.github.maracas.LibraryJar.hasSources", "com.github.maracas.LibraryJar.hashCode", "com.github.maracas.LibraryJar.setNoClasspath", "com.github.maracas.LibraryJar.setSources", "com.github.maracas.LibraryJar.toString", "com.github.maracas.LibraryJar.withSources", "com.github.maracas.LibraryJar.withSources", "com.github.maracas.LibraryJar.withoutSources", "com.github.maracas.Maracas.analyze", "com.github.maracas.Maracas.computeDelta", "com.github.maracas.Maracas.computeDelta", "com.github.maracas.Maracas.computeDeltaImpact", "com.github.maracas.Maracas.computeDeltaImpact", "com.github.maracas.MaracasCLI.main", "com.github.maracas.MaracasCLI.run", "com.github.maracas.MaracasOptions.defaultJApiOptions", "com.github.maracas.MaracasOptions.excludeBreakingChange", "com.github.maracas.MaracasOptions.getBuildTimeout", "com.github.maracas.MaracasOptions.getClientsPerModule", "com.github.maracas.MaracasOptions.getCloneTimeout", "com.github.maracas.MaracasOptions.getExcludedBreakingChanges", "com.github.maracas.MaracasOptions.getJApiOptions", "com.github.maracas.MaracasOptions.getMaxClassLines", "com.github.maracas.MaracasOptions.getMinStarsPerClient", "com.github.maracas.MaracasOptions.newDefault", "com.github.maracas.MaracasOptions.setBuildTimeout", "com.github.maracas.MaracasOptions.setClientsPerModule", "com.github.maracas.MaracasOptions.setCloneTimeout", "com.github.maracas.MaracasOptions.setMaxClassLines", "com.github.maracas.MaracasOptions.setMinStarsPerClient", "com.github.maracas.SourcesDirectory.buildModel", "com.github.maracas.SourcesDirectory.equals", "com.github.maracas.SourcesDirectory.getLocation", "com.github.maracas.SourcesDirectory.hashCode", "com.github.maracas.SourcesDirectory.of", "com.github.maracas.SourcesDirectory.setClasspath", "com.github.maracas.SourcesDirectory.toString", "com.github.maracas.Usage.main", "com.github.maracas.Usage.readmeUsage1", "com.github.maracas.Usage.readmeUsage2", "com.github.maracas.delta.AbstractBreakingChange.getChange", "com.github.maracas.delta.AbstractBreakingChange.getSourceElement", "com.github.maracas.delta.AbstractBreakingChange.setSourceElement", "com.github.maracas.delta.BreakingChange.getChange", "com.github.maracas.delta.BreakingChange.getReference", "com.github.maracas.delta.BreakingChange.getSourceElement", "com.github.maracas.delta.BreakingChange.getVisitor", "com.github.maracas.delta.BreakingChange.setSourceElement", "com.github.maracas.delta.Delta.fromJApiCmpDelta", "com.github.maracas.delta.Delta.getBreakingChanges", "com.github.maracas.delta.Delta.getNewVersion", "com.github.maracas.delta.Delta.getOldVersion", "com.github.maracas.delta.Delta.getVisitors", "com.github.maracas.delta.Delta.isEmpty", "com.github.maracas.delta.Delta.populateLocations", "com.github.maracas.delta.Delta.toJson", "com.github.maracas.delta.Delta.toString", "com.github.maracas.delta.FieldBreakingChange.getReference", "com.github.maracas.delta.FieldBreakingChange.getVisitor", "com.github.maracas.delta.JApiCmpDeltaFilter.filter", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpDeltaVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.getBreakingChanges", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.JApiCmpToSpoonVisitor.visit", "com.github.maracas.delta.MethodBreakingChange.getReference", "com.github.maracas.delta.MethodBreakingChange.getVisitor", "com.github.maracas.delta.TypeBreakingChange.getReference", "com.github.maracas.delta.TypeBreakingChange.getVisitor", "com.github.maracas.util.BinaryToSourceMapper.cache", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.BinaryToSourceMapper.resolve", "com.github.maracas.util.CtElementSerializer.serialize", "com.github.maracas.util.GradleLauncher.init", "com.github.maracas.util.ParentLastURLClassLoader.loadClass", "com.github.maracas.util.PathHelpers.isValidDirectory", "com.github.maracas.util.PathHelpers.isValidJar", "com.github.maracas.util.SpoonHelpers.buildSpoonSignature", "com.github.maracas.util.SpoonHelpers.buildSpoonSignature", "com.github.maracas.util.SpoonHelpers.firstLocatableParent", "com.github.maracas.util.SpoonHelpers.fullyQualifiedName", "com.github.maracas.util.SpoonHelpers.getEnclosingPkgName", "com.github.maracas.util.SpoonHelpers.isImplicit", "com.github.maracas.util.SpoonHelpers.matchingSignatures", "com.github.maracas.util.SpoonTypeHelpers.haveUnimplAbstractMethods", "com.github.maracas.util.SpoonTypeHelpers.inferExpectedType", "com.github.maracas.util.SpoonTypeHelpers.isAssignableFrom", "com.github.maracas.util.SpoonTypeHelpers.isAssignableFromOverride", "com.github.maracas.util.SpoonTypeHelpers.isBoxedType", "com.github.maracas.util.SpoonTypeHelpers.isNarrowedPrimitiveType", "com.github.maracas.util.SpoonTypeHelpers.isNarrowedType", "com.github.maracas.util.SpoonTypeHelpers.isSubtype", "com.github.maracas.util.SpoonTypeHelpers.isSubtype", "com.github.maracas.util.SpoonTypeHelpers.isUnboxedType", "com.github.maracas.util.SpoonTypeHelpers.isWidenedPrimitiveType", "com.github.maracas.util.SpoonTypeHelpers.isWidenedType", "com.github.maracas.util.SpoonTypeHelpers.primitivesAreCompatible", "com.github.maracas.visitors.BreakingChangeVisitor.brokenUse", "com.github.maracas.visitors.BreakingChangeVisitor.getAPIUseByRole", "com.github.maracas.visitors.BreakingChangeVisitor.getBrokenUses", "com.github.maracas.visitors.ClassLessAccessibleVisitor.visitCtTypeReference", "com.github.maracas.visitors.ClassNowAbstractVisitor.visitCtConstructorCall", "com.github.maracas.visitors.ClassNowCheckedExceptionVisitor.visitCtThrow", "com.github.maracas.visitors.ClassNowFinalVisitor.visitCtClass", "com.github.maracas.visitors.ClassNowFinalVisitor.visitCtNewClass", "com.github.maracas.visitors.CombinedVisitor.getBrokenUses", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotation", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationFieldAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationMethod", "com.github.maracas.visitors.CombinedVisitor.visitCtAnnotationType", "com.github.maracas.visitors.CombinedVisitor.visitCtAnonymousExecutable", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayRead", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtArrayWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtAssert", "com.github.maracas.visitors.CombinedVisitor.visitCtAssignment", "com.github.maracas.visitors.CombinedVisitor.visitCtBinaryOperator", "com.github.maracas.visitors.CombinedVisitor.visitCtBlock", "com.github.maracas.visitors.CombinedVisitor.visitCtBreak", "com.github.maracas.visitors.CombinedVisitor.visitCtCase", "com.github.maracas.visitors.CombinedVisitor.visitCtCatch", "com.github.maracas.visitors.CombinedVisitor.visitCtCatchVariable", "com.github.maracas.visitors.CombinedVisitor.visitCtCatchVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtClass", "com.github.maracas.visitors.CombinedVisitor.visitCtCodeSnippetExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtCodeSnippetStatement", "com.github.maracas.visitors.CombinedVisitor.visitCtComment", "com.github.maracas.visitors.CombinedVisitor.visitCtCompilationUnit", "com.github.maracas.visitors.CombinedVisitor.visitCtConditional", "com.github.maracas.visitors.CombinedVisitor.visitCtConstructor", "com.github.maracas.visitors.CombinedVisitor.visitCtConstructorCall", "com.github.maracas.visitors.CombinedVisitor.visitCtContinue", "com.github.maracas.visitors.CombinedVisitor.visitCtDo", "com.github.maracas.visitors.CombinedVisitor.visitCtEnum", "com.github.maracas.visitors.CombinedVisitor.visitCtEnumValue", "com.github.maracas.visitors.CombinedVisitor.visitCtExecutableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtExecutableReferenceExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtField", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldRead", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldReference", "com.github.maracas.visitors.CombinedVisitor.visitCtFieldWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtFor", "com.github.maracas.visitors.CombinedVisitor.visitCtForEach", "com.github.maracas.visitors.CombinedVisitor.visitCtIf", "com.github.maracas.visitors.CombinedVisitor.visitCtImport", "com.github.maracas.visitors.CombinedVisitor.visitCtInterface", "com.github.maracas.visitors.CombinedVisitor.visitCtIntersectionTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtInvocation", "com.github.maracas.visitors.CombinedVisitor.visitCtJavaDoc", "com.github.maracas.visitors.CombinedVisitor.visitCtJavaDocTag", "com.github.maracas.visitors.CombinedVisitor.visitCtLambda", "com.github.maracas.visitors.CombinedVisitor.visitCtLiteral", "com.github.maracas.visitors.CombinedVisitor.visitCtLocalVariable", "com.github.maracas.visitors.CombinedVisitor.visitCtLocalVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtMethod", "com.github.maracas.visitors.CombinedVisitor.visitCtModule", "com.github.maracas.visitors.CombinedVisitor.visitCtModuleReference", "com.github.maracas.visitors.CombinedVisitor.visitCtModuleRequirement", "com.github.maracas.visitors.CombinedVisitor.visitCtNewArray", "com.github.maracas.visitors.CombinedVisitor.visitCtNewClass", "com.github.maracas.visitors.CombinedVisitor.visitCtOperatorAssignment", "com.github.maracas.visitors.CombinedVisitor.visitCtPackage", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageDeclaration", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageExport", "com.github.maracas.visitors.CombinedVisitor.visitCtPackageReference", "com.github.maracas.visitors.CombinedVisitor.visitCtParameter", "com.github.maracas.visitors.CombinedVisitor.visitCtParameterReference", "com.github.maracas.visitors.CombinedVisitor.visitCtProvidedService", "com.github.maracas.visitors.CombinedVisitor.visitCtReturn", "com.github.maracas.visitors.CombinedVisitor.visitCtStatementList", "com.github.maracas.visitors.CombinedVisitor.visitCtSuperAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtSwitch", "com.github.maracas.visitors.CombinedVisitor.visitCtSwitchExpression", "com.github.maracas.visitors.CombinedVisitor.visitCtSynchronized", "com.github.maracas.visitors.CombinedVisitor.visitCtTextBlock", "com.github.maracas.visitors.CombinedVisitor.visitCtThisAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtThrow", "com.github.maracas.visitors.CombinedVisitor.visitCtTry", "com.github.maracas.visitors.CombinedVisitor.visitCtTryWithResource", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeAccess", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeMemberWildcardImportReference", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeParameter", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeParameterReference", "com.github.maracas.visitors.CombinedVisitor.visitCtTypeReference", "com.github.maracas.visitors.CombinedVisitor.visitCtUnaryOperator", "com.github.maracas.visitors.CombinedVisitor.visitCtUnboundVariableReference", "com.github.maracas.visitors.CombinedVisitor.visitCtUsedService", "com.github.maracas.visitors.CombinedVisitor.visitCtVariableRead", "com.github.maracas.visitors.CombinedVisitor.visitCtVariableWrite", "com.github.maracas.visitors.CombinedVisitor.visitCtWhile", "com.github.maracas.visitors.CombinedVisitor.visitCtWildcardReference", "com.github.maracas.visitors.CombinedVisitor.visitCtYieldStatement", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtConstructorCall", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtInvocation", "com.github.maracas.visitors.ConstructorRemovedVisitor.visitCtNewClass", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldAccess", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldLessAccessibleVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.isStaticAccess", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldAccess", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldNoLongerStaticVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldNowFinalVisitor.visitCtFieldWrite", "com.github.maracas.visitors.FieldReferenceVisitor.visitCtFieldReference", "com.github.maracas.visitors.FieldTypeChangedVisitor.visitCtFieldRead", "com.github.maracas.visitors.FieldTypeChangedVisitor.visitCtFieldWrite", "com.github.maracas.visitors.MethodAddedToInterfaceVisitor.visitCtClass", "com.github.maracas.visitors.MethodNowAbstractVisitor.visitCtClass", "com.github.maracas.visitors.MethodNowAbstractVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodNowFinalVisitor.visitCtMethod", "com.github.maracas.visitors.MethodReferenceVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodReferenceVisitor.visitCtMethod", "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.visitCtInvocation", "com.github.maracas.visitors.MethodReturnTypeChangedVisitor.visitCtMethod", "com.github.maracas.visitors.SupertypeAddedVisitor.visitCtClass", "com.github.maracas.visitors.SupertypeRemovedVisitor.isStaticInvocation", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtAssignment", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtFieldReference", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtInvocation", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtLocalVariable", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitCtMethod", "com.github.maracas.visitors.SupertypeRemovedVisitor.visitExpAssignment", "com.github.maracas.visitors.TypeReferenceVisitor.visitCtTypeReference" ], - "ClientMethods" : [ "com.github.maracas.forges.Forge.fetchAllClients", "com.github.maracas.forges.Forge.fetchBreakbotConfig", "com.github.maracas.forges.Forge.fetchCommit", "com.github.maracas.forges.Forge.fetchCommit", "com.github.maracas.forges.Forge.fetchModules", "com.github.maracas.forges.Forge.fetchPullRequest", "com.github.maracas.forges.Forge.fetchPullRequest", "com.github.maracas.forges.Forge.fetchRepository", "com.github.maracas.forges.Forge.fetchRepository", "com.github.maracas.forges.Forge.fetchTopStarredClients", "com.github.maracas.forges.Usage.readmeUsage1", "com.github.maracas.forges.Usage.readmeUsage2", "com.github.maracas.forges.analysis.CommitAnalyzer.analyzeCommits", "com.github.maracas.forges.analysis.CommitAnalyzer.cloneAndAnalyzeClient", "com.github.maracas.forges.analysis.CommitAnalyzer.cloneAndBuildLibrary", "com.github.maracas.forges.analysis.CommitAnalyzer.computeDelta", "com.github.maracas.forges.analysis.CommitAnalyzer.computeImpact", "com.github.maracas.forges.analysis.PullRequestAnalyzer.analyzeModule", "com.github.maracas.forges.analysis.PullRequestAnalyzer.analyzePullRequest", "com.github.maracas.forges.analysis.PullRequestAnalyzer.cleanUp", "com.github.maracas.forges.analysis.PullRequestAnalyzer.getRepositoryModule", "com.github.maracas.forges.analysis.PullRequestAnalyzer.inferImpactedModules", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeBuilderForClient", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeBuilderForLibrary", "com.github.maracas.forges.analysis.PullRequestAnalyzer.makeClonePath", "com.github.maracas.forges.analysis.PullRequestAnalyzer.workingDirectory", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_GumTree", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_fixture_moduleA", "com.github.maracas.forges.analysis.CommitAnalyzerIT.analyzeCommits_fixture_nestedB", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeDelta_maracas_withBuildTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeDelta_maracas_withCloneTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.computeImpact_fixture_withCloneTimeout", "com.github.maracas.forges.analysis.CommitAnalyzerIT.setUp", "com.github.maracas.forges.analysis.CommitAnalyzerTest.analyzeCommits_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_buildException", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_cloneException", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_no_JAR_created", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeDelta_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_no_BC_in_delta", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_no_client", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_one_analysis_fails", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_one_clone_timeout", "com.github.maracas.forges.analysis.CommitAnalyzerTest.computeImpact_two_clients_success", "com.github.maracas.forges.analysis.CommitAnalyzerTest.setUp", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.analyzePullRequest_fixture_two_broken_modules", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_no_impacted_module", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_one_impacted_module", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.inferImpactedModules_fixture_two_impacted_modules", "com.github.maracas.forges.analysis.PullRequestAnalyzerTest.setUp", "com.github.maracas.forges.build.BuildConfig.addGoal", "com.github.maracas.forges.build.BuildConfig.getGoals", "com.github.maracas.forges.build.BuildConfig.getModule", "com.github.maracas.forges.build.BuildConfig.getProperties", "com.github.maracas.forges.build.BuildConfig.newDefault", "com.github.maracas.forges.build.BuildConfig.setProperty", "com.github.maracas.forges.build.BuildConfig.toString", "com.github.maracas.forges.build.Builder.build", "com.github.maracas.forges.build.Builder.build", "com.github.maracas.forges.build.Builder.locateJar", "com.github.maracas.forges.build.Builder.locateModules", "com.github.maracas.forges.build.Builder.of", "com.github.maracas.forges.build.Builder.of", "com.github.maracas.forges.build.CommitBuilder.buildCommit", "com.github.maracas.forges.build.CommitBuilder.cloneCommit", "com.github.maracas.forges.build.CommitBuilder.getBuildConfig", "com.github.maracas.forges.build.CommitBuilder.getBuilder", "com.github.maracas.forges.build.CommitBuilder.getClonePath", "com.github.maracas.forges.build.CommitBuilder.getCloner", "com.github.maracas.forges.build.CommitBuilder.getCommit", "com.github.maracas.forges.build.CommitBuilder.getModulePath", "com.github.maracas.forges.build.CommitBuilder.toString", "com.github.maracas.forges.build.BuilderTest.build_From_GradleProject", "com.github.maracas.forges.build.BuilderTest.build_From_MavenProject", "com.github.maracas.forges.build.BuilderTest.build_From_UnknownProject", "com.github.maracas.forges.build.gradle.GradleBuilder.build", "com.github.maracas.forges.build.gradle.GradleBuilder.getProjectConnection", "com.github.maracas.forges.build.gradle.GradleBuilder.isGradleProject", "com.github.maracas.forges.build.gradle.GradleBuilder.locateJar", "com.github.maracas.forges.build.gradle.GradleBuilder.locateModules", "com.github.maracas.forges.build.gradle.GradleBuilder.readGradleProperties", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_compileError", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_core_default_with_version", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_extra_default", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_multi_invalid", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_default", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_invalidGoal", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_withGoal", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_with_invalidProperty", "com.github.maracas.forges.build.gradle.GradleBuilderTest.build_validGradle_with_validProperty", "com.github.maracas.forges.build.gradle.GradleBuilderTest.setUp", "com.github.maracas.forges.build.maven.MavenBuilder.build", "com.github.maracas.forges.build.maven.MavenBuilder.isMavenProject", "com.github.maracas.forges.build.maven.MavenBuilder.locateJar", "com.github.maracas.forges.build.maven.MavenBuilder.locateModules", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_compileError", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_invalidGoal", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_maracas_timeout", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_core_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_extra_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_multi_invalid", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_no_pom", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_default", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_withGoal", "com.github.maracas.forges.build.maven.MavenBuilderTest.build_validPom_withProperty", "com.github.maracas.forges.build.maven.MavenBuilderTest.locate_modules_multi", "com.github.maracas.forges.build.maven.MavenBuilderTest.locate_modules_valid", "com.github.maracas.forges.build.maven.MavenBuilderTest.setUp", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.clone", "com.github.maracas.forges.clone.Cloner.of", "com.github.maracas.forges.clone.ClonerTest.cloner_From_GitHub", "com.github.maracas.forges.clone.ClonerTest.cloner_From_Unknown", "com.github.maracas.forges.clone.git.GitCloner.clone", "com.github.maracas.forges.clone.git.GitCloner.clone", "com.github.maracas.forges.clone.git.GitCloner.executeCommand", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_HEAD", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_invalid_repository", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_invalid_sha", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_sha_branch", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_sha_main", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_timeout", "com.github.maracas.forges.clone.git.GitClonerTest.clone_commit_timeout_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_branch", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_branch_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_invalid_location", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_timeout", "com.github.maracas.forges.clone.git.GitClonerTest.clone_repository_timeout_invalid", "com.github.maracas.forges.clone.git.GitClonerTest.readHEAD", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchClients", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchClients", "com.github.maracas.forges.github.GitHubClientsFetcher.fetchModules", "com.github.maracas.forges.github.GitHubClientsScraper.clientsCacheFile", "com.github.maracas.forges.github.GitHubClientsScraper.fetchClients", "com.github.maracas.forges.github.GitHubClientsScraper.fetchClientsRec", "com.github.maracas.forges.github.GitHubClientsScraper.fetchModules", "com.github.maracas.forges.github.GitHubClientsScraper.fetchPage", "com.github.maracas.forges.github.GitHubClientsScraper.hasClientsCache", "com.github.maracas.forges.github.GitHubClientsScraper.readClientsCache", "com.github.maracas.forges.github.GitHubClientsScraper.writeClientsCache", "com.github.maracas.forges.github.GitHubForge.fetchAllClients", "com.github.maracas.forges.github.GitHubForge.fetchAndCacheRepository", "com.github.maracas.forges.github.GitHubForge.fetchBreakbotConfig", "com.github.maracas.forges.github.GitHubForge.fetchCommit", "com.github.maracas.forges.github.GitHubForge.fetchCustomClients", "com.github.maracas.forges.github.GitHubForge.fetchModules", "com.github.maracas.forges.github.GitHubForge.fetchPullRequest", "com.github.maracas.forges.github.GitHubForge.fetchRepository", "com.github.maracas.forges.github.GitHubForge.fetchRepository", "com.github.maracas.forges.github.GitHubForge.fetchTopStarredClients", "com.github.maracas.forges.github.GitHubForge.getRepositoryFromBreakbot", "com.github.maracas.forges.github.GitHubForge.getSourceRepository", "com.github.maracas.forges.github.GitHubForge.isValidClient", "com.github.maracas.forges.github.BreakbotConfigTest.client_with_commit_or_branch", "com.github.maracas.forges.github.BreakbotConfigTest.clients_with_sources", "com.github.maracas.forges.github.BreakbotConfigTest.custom_build", "com.github.maracas.forges.github.BreakbotConfigTest.custom_build_output", "com.github.maracas.forges.github.BreakbotConfigTest.custom_output", "com.github.maracas.forges.github.BreakbotConfigTest.default_configuration", "com.github.maracas.forges.github.BreakbotConfigTest.ignore_unknown_properties", "com.github.maracas.forges.github.BreakbotConfigTest.invalid_configuration", "com.github.maracas.forges.github.BreakbotConfigTest.one_client", "com.github.maracas.forges.github.BreakbotConfigTest.popular_clients", "com.github.maracas.forges.github.BreakbotConfigTest.several_clients", "com.github.maracas.forges.github.BreakbotConfigTest.top_clients", "com.github.maracas.forges.github.BreakbotConfigTest.top_clients_with_custom", "com.github.maracas.forges.github.BreakbotConfigTest.with_excludes", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_ews", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_guava_limit", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_clients_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_ews", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_modules_unknown", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_one_module_spoon", "com.github.maracas.forges.github.GitHubClientsScraperTest.fetch_unknown_module_spoon", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_fixture", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_from_fork", "com.github.maracas.forges.github.GitHubForgeIT.fetchAllClients_no_module", "com.github.maracas.forges.github.GitHubForgeIT.fetchClients_unknown_module", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_HEAD", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_short_sha", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchCommit_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_closed", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_opened", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_that_was_synchronized", "com.github.maracas.forges.github.GitHubForgeIT.fetchPullRequest_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_branch_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_branch_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_unknown", "com.github.maracas.forges.github.GitHubForgeIT.fetchRepository_valid", "com.github.maracas.forges.github.GitHubForgeIT.fetchStarredClients_spoon", "com.github.maracas.forges.github.GitHubForgeIT.fetchTopClients_spoon", "com.github.maracas.forges.github.GitHubForgeIT.setUp", "com.github.maracas.forges.github.GitHubForgeTest.fetchCommit_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchCommit_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchPullRequest_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchPullRequest_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_shouldFail_whenGitHubFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_withInvalidBranch_shouldFail", "com.github.maracas.forges.github.GitHubForgeTest.fetchRepository_withValidBranch_shouldSucceed", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_oneClientFails", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_shouldOrder_Clients", "com.github.maracas.forges.github.GitHubForgeTest.fetchTopStarredClients_shouldRetrieve_SourceClients", "com.github.maracas.forges.github.GitHubForgeTest.prFixture", "com.github.maracas.forges.github.GitHubForgeTest.repositoryFixture", "com.github.maracas.forges.github.GitHubForgeTest.repositoryFixture", "com.github.maracas.forges.github.GitHubForgeTest.setUp" ] -} \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java index ea0d0813..f089fd91 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java @@ -13,6 +13,7 @@ public String getInstanceVariableName(int instanceId) throws Exception { return "var%d".formatted(mapOfInstancesToIndexes.get(instanceId)); } + System.out.println(instanceId); throw new Exception("Instance Id is not already defined"); } @@ -23,6 +24,7 @@ public String newInstanceVariableName(int instanceId) throws Exception { return "var%d".formatted(i); } + System.out.println(instanceId); throw new Exception("Instance Id is already defined"); } diff --git a/compile.cmd b/compile.cmd new file mode 100644 index 00000000..4e0da057 --- /dev/null +++ b/compile.cmd @@ -0,0 +1,37 @@ +@echo off + +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 + +echo. +echo =========================================================== +echo Building ConfGen +echo =========================================================== +echo. + +REM build confgen +cd ConfGen +call .\gradlew.bat shadowJar --warning-mode all +cd .. + + +echo. +echo =========================================================== +echo Building TraceView +echo =========================================================== +echo. + +REM build traceview +cd TraceView +call .\gradlew.bat shadowJar --warning-mode all +cd .. + +echo. +echo =========================================================== +echo Building Agent +echo =========================================================== +echo. + +REM build tool +cd Instrumentation +call .\gradlew.bat shadowJar --warning-mode all +cd .. \ No newline at end of file diff --git a/maracas-test.cmd b/maracas-test.cmd index 48e2ea71..2aba2479 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -1,35 +1,42 @@ @echo off call run-clean-workflow.cmd +call compile.cmd set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 +set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 -REM build samples -cd Samples -call .\gradlew.bat jar -cd .. - -REM build confgen -cd ConfGen -call .\gradlew.bat shadowJar -cd .. - -REM build traceview -cd TraceView -call .\gradlew.bat shadowJar -cd .. - -REM build tool -cd Instrumentation -call .\gradlew.bat shadowJar -cd .. -set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 +echo. +echo =========================================================== +echo Running ConfGen +echo =========================================================== +echo. %JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" -cd C:\Users\Gus\Documents\GitHub\maracas +echo. +echo =========================================================== +echo Running Maracas Forges' Test Suite with Agent +echo =========================================================== +echo. + +cd C:\Users\Gus\Documents\GitHub\maracas\forges call "%MAVEN_HOME%\bin\mvn" surefire:test cd C:\Users\Gus\Documents\GitHub\gilesi -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\MethodTraces.json" > C:\Users\Gus\Documents\GitHub\maracas\TraceView.Output.txt \ No newline at end of file + +echo. +echo =========================================================== +echo Running TraceView +echo =========================================================== +echo. + +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.json" + +mkdir Results + +move %CD%\MaracasConfiguration.json Results\ +move C:\Users\Gus\Documents\GitHub\maracas\forges\gilesi.instrumentation.log Results\ +move C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.json Results\ +move %CD%\TraceView.Output Results\ \ No newline at end of file diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 94f0ebf5..ce473f75 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -1,9 +1,11 @@ @echo off call run-clean-workflow.cmd +call compile.cmd set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 + echo. echo =========================================================== echo Building Samples @@ -16,41 +18,6 @@ call .\gradlew.bat jar --warning-mode all cd .. -echo. -echo =========================================================== -echo Building ConfGen -echo =========================================================== -echo. - -REM build confgen -cd ConfGen -call .\gradlew.bat shadowJar --warning-mode all -cd .. - - -echo. -echo =========================================================== -echo Building TraceView -echo =========================================================== -echo. - -REM build traceview -cd TraceView -call .\gradlew.bat shadowJar --warning-mode all -cd .. - -echo. -echo =========================================================== -echo Building Agent -echo =========================================================== -echo. - -REM build tool -cd Instrumentation -call .\gradlew.bat shadowJar --warning-mode all -cd .. - - echo. echo =========================================================== echo Running ConfGen From 83f951c0f7f2a41956b2d8738861b42f85ab9d96 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 13:08:43 +0100 Subject: [PATCH 080/244] fix: workaround issue with some null values passed in args --- .../instrumentation/TraceDataFactory.java | 6 ++--- .../gilesi/instrumentation/TraceFactory.java | 22 ++++++++++++++----- 2 files changed, 19 insertions(+), 9 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index 607fa937..a9c21786 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -4,11 +4,9 @@ import com.github.maracas.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - private static int NullCounter = 0; - - public static TraceData valueOf(Object object) { + public static TraceData valueOf(Object object, int nullInstanceId) { if (object == null) { - return new TraceData("Object", "null", ++NullCounter * -1); + return new TraceData("Object", "null", nullInstanceId); } // /!\ CAUTION diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index 9928b05b..f39a3236 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -13,6 +13,8 @@ import java.util.stream.Collectors; public class TraceFactory { + private static int NullCounter = 0; + public static final long ProcessEntryTimeStamp = System.nanoTime(); /** @@ -45,7 +47,7 @@ private static List getArgumentsAsSerializableData(Object[] arguments List argumentStrings = new ArrayList<>(); if (arguments != null) { - argumentStrings = Arrays.stream(arguments).map(TraceDataFactory::valueOf).collect(Collectors.toList()); + argumentStrings = Arrays.stream(arguments).map(t -> TraceDataFactory.valueOf(t, ++NullCounter * -1)).collect(Collectors.toList()); } return argumentStrings; @@ -68,7 +70,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg String methodSignature = getOriginName(origin); TraceData serializableInstance = null; if (instance != null) { - serializableInstance = TraceDataFactory.valueOf(instance); + serializableInstance = TraceDataFactory.valueOf(instance, ++NullCounter * -1); } List preCallArguments = getArgumentsAsSerializableData(arguments); @@ -97,18 +99,28 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object String methodSignature = getOriginName(origin); TraceData serializableInstance = null; if (instance != null) { - serializableInstance = TraceDataFactory.valueOf(instance); + serializableInstance = TraceDataFactory.valueOf(instance, ++NullCounter * -1); } List preCallArguments = originatingTrace.getPreCallArguments(); List postCallArguments = getArgumentsAsSerializableData(arguments); + + // Every argument of a method should have the same instance id, in the case of null params, they will be different, so fix that + for (int i = 0; i < preCallArguments.size(); i++) { + if (postCallArguments.get(i).getInstanceId() < 0) { // Null ids are intentionally negative + postCallArguments.get(i).setInstanceId(preCallArguments.get(i).getInstanceId()); + } + } + TraceData returnedValue = null; // TODO: Detect if the method returns nothing or not here! if (returned != null) { - returnedValue = TraceDataFactory.valueOf(returned); + returnedValue = TraceDataFactory.valueOf(returned, ++NullCounter * -1); } + long timeStampEntry = originatingTrace.getTimeStampEntry(); + TraceData exceptionThrown = null; if (thrown != null) { - exceptionThrown = TraceDataFactory.valueOf(thrown); + exceptionThrown = TraceDataFactory.valueOf(thrown, ++NullCounter * -1); } return new Trace(methodSignature, serializableInstance, preCallArguments, postCallArguments, returnedValue, timeStampEntry, 0, exceptionThrown, stackTrace); From e29c1b632b30b066996e4e83104bf5c977c5fc58 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 22 Feb 2024 13:10:28 +0100 Subject: [PATCH 081/244] add option to remove post call asserts --- .../github/maracas/gilesi/traceview/Main.java | 2 +- .../gilesi/traceview/TestMethodGenerator.java | 19 ++++++++++--------- 2 files changed, 11 insertions(+), 10 deletions(-) diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index f006a33a..9c9ce6f9 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -102,7 +102,7 @@ public static void main(String[] args) throws Exception { for (int i = 0; i < methodTraces.length; i++) { Trace trace = methodTraces[i]; - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t"); + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); stringBuilder.append("%s\n".formatted(traceCode)); if (i != methodTraces.length - 1) { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index efced48d..d8f8b7cd 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -133,23 +133,24 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari return null; } - public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix) throws Exception { - String methodCallLine = traceToCode(trace, variableStackHandler, indentationPrefix); - String returnAssertionLine = traceToAssert(trace, variableStackHandler); - String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler, indentationPrefix); - + public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix, boolean addAssertsForArgumentsPostCall) throws Exception { String traceCode = ""; + String methodCallLine = traceToCode(trace, variableStackHandler, indentationPrefix); if (methodCallLine != null && !methodCallLine.isEmpty()) { - traceCode += String.format("%s%s\n", indentationPrefix, methodCallLine); + traceCode += "%s%s\n".formatted(indentationPrefix, methodCallLine); } + String returnAssertionLine = traceToAssert(trace, variableStackHandler); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - traceCode += String.format("%s%s\n", indentationPrefix, returnAssertionLine); + traceCode += "%s%s\n".formatted(indentationPrefix, returnAssertionLine); } - if (!postCallParameterAssertionLine.isEmpty()) { - traceCode += String.format("%s%s\n", indentationPrefix, postCallParameterAssertionLine); + if (addAssertsForArgumentsPostCall) { + String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler, indentationPrefix); + if (!postCallParameterAssertionLine.isEmpty()) { + traceCode += "%s%s\n".formatted(indentationPrefix, postCallParameterAssertionLine); + } } while (traceCode.endsWith("\n")) { From 2d6b987ae40a4b442aa39e19fef04c9f6b86412b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 5 Apr 2024 04:06:35 +0200 Subject: [PATCH 082/244] Update to work with latest roseau --- .../main/java/com/github/maracas/gilesi/confgen/Main.java | 6 +++--- compile.cmd | 2 +- run-test-workflow.cmd | 2 +- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index d6099f6e..3a5edc67 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -126,14 +126,14 @@ public static void main(String[] args) throws Exception { CtModel libraryModel = libraryLauncher.buildModel(); // API model for libraries - API libraryApiModel = new SpoonAPIExtractor(libraryModel).extractAPI(); + API libraryApiModel = new SpoonAPIExtractor().extractAPI(libraryModel); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.Classes = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); - for (ClassDecl classDecl : libraryApiModel.getExportedTypes().stream() + for (ClassDecl classDecl : libraryApiModel.getExportedTypes() .filter(ClassDecl.class::isInstance) .map(ClassDecl.class::cast).toList()) { @@ -144,7 +144,7 @@ public static void main(String[] args) throws Exception { addToInstrumentationObject(instrumentationParameters, className, methodDescriptor); } - for (MethodDecl method : classDecl.getMethods()) { + for (MethodDecl method : classDecl.getAllMethods().toList()) { String FQN = method.getQualifiedName(); String className = getClassNameFromFQN(FQN); String methodName = getMethodNameFromFQN(FQN); diff --git a/compile.cmd b/compile.cmd index 4e0da057..f9c00201 100644 --- a/compile.cmd +++ b/compile.cmd @@ -1,6 +1,6 @@ @echo off -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 echo. echo =========================================================== diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index ce473f75..901133a7 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -3,7 +3,7 @@ call run-clean-workflow.cmd call compile.cmd -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 echo. From 9e00d8a01b64d1091623017aa443a0b2811c6785 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 17 Apr 2024 23:22:17 +0100 Subject: [PATCH 083/244] Start migrating to xstream XStream is more configurable to ignore failures supposedly, so lets switch to it in order to explore its usability --- Instrumentation/build.gradle | 1 + .../maracas/gilesi/instrumentation/Agent.java | 5 ++++- .../gilesi/instrumentation/TraceCollector.java | 17 +++++++++-------- .../instrumentation/TraceDataFactory.java | 6 +++--- 4 files changed, 17 insertions(+), 12 deletions(-) diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index d65c40c4..5be55f8a 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -19,6 +19,7 @@ dependencies { implementation 'net.bytebuddy:byte-buddy:1.14.2' implementation 'net.bytebuddy:byte-buddy-agent:1.14.2' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' } jar { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 6a99535a..cf547d06 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -5,6 +5,8 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; @@ -15,7 +17,8 @@ Our main agent class */ public class Agent { - public static ObjectMapper objectMapper = new ObjectMapper(); + private static ObjectMapper objectMapper = new ObjectMapper(); + public static XStream xstream = new XStream(new DomDriver()); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { return objectMapper.readValue(file, InstrumentationParameters.class); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 9a6752f4..4918f216 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -5,6 +5,10 @@ import com.github.maracas.gilesi.instrumentation.models.Trace; import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.nio.file.Path; +import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; @@ -45,20 +49,17 @@ public static Collection getMethodTraces() { /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults() { - File outputFile = new File("MethodTraces.json"); + public static void SaveTraceResults() throws IOException { + FileWriter outputFile = new FileWriter("MethodTraces.json"); System.out.println("Saving trace results in progress..."); - System.out.printf("Output location: %s%n", outputFile.getAbsolutePath()); - - Agent.objectMapper.enable(SerializationFeature.INDENT_OUTPUT); + System.out.printf("Output location: %s%n", Paths.get("MethodTraces.json").toAbsolutePath()); try { - Agent.objectMapper.writeValue(outputFile, TraceCollector.getMethodTraces()); + String xmlOutputString = Agent.xstream.toXML(TraceCollector.getMethodTraces()); + outputFile.write(xmlOutputString); } catch (Exception e) { System.err.println("ERROR"); e.printStackTrace(); } - - Agent.objectMapper.disable(SerializationFeature.INDENT_OUTPUT); } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index a9c21786..de19e7a2 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation; -import com.fasterxml.jackson.core.JsonProcessingException; import com.github.maracas.gilesi.instrumentation.models.TraceData; +import com.thoughtworks.xstream.XStreamException; public class TraceDataFactory { public static TraceData valueOf(Object object, int nullInstanceId) { @@ -26,8 +26,8 @@ public static TraceData valueOf(Object object, int nullInstanceId) { String serializedString = null; try { - serializedString = Agent.objectMapper.writeValueAsString(object); - } catch (JsonProcessingException e) { + serializedString = Agent.xstream.toXML(object); + } catch (XStreamException e) { System.err.printf("ERROR: Cannot serialize specific argument: %s%n", e); } From f8c66a3c140e5872e4de00995a8f3d0c0b148f0e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 18 Apr 2024 10:08:42 +0100 Subject: [PATCH 084/244] Move to XStream for serialization Further work is needed especially towards the types that cannot be correctly serialized as well as generated code output --- ConfGen/build.gradle | 4 +- .../github/maracas/gilesi/confgen/Main.java | 10 ++--- Instrumentation/build.gradle | 1 - .../maracas/gilesi/instrumentation/Agent.java | 13 ++++-- .../instrumentation/TraceCollector.java | 8 ++-- .../instrumentation/TraceDataFactory.java | 13 +++++- .../gilesi/instrumentation/TraceFactory.java | 4 +- .../instrumentation/models/PartialTrace.java | 12 ++---- .../gilesi/instrumentation/models/Trace.java | 22 ++++------ .../instrumentation/models/TraceData.java | 43 ++----------------- Samples/sampleclient/build.gradle | 2 +- TraceView/build.gradle | 2 +- .../instrumentation/models/PartialTrace.java | 12 ++---- .../gilesi/instrumentation/models/Trace.java | 22 ++++------ .../instrumentation/models/TraceData.java | 43 ++----------------- .../github/maracas/gilesi/traceview/Main.java | 22 +++++++--- .../gilesi/traceview/SerializationUtils.java | 13 +++--- .../gilesi/traceview/TestMethodGenerator.java | 34 +++++++-------- compile.cmd | 2 +- maracas-test.cmd | 10 ++--- run-test-workflow.cmd | 10 ++--- test.cmd | 2 +- 22 files changed, 118 insertions(+), 186 deletions(-) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index dc5afcc8..187eead8 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -33,13 +33,11 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-databind:2.16.1' - implementation 'com.fasterxml.jackson.datatype:jackson-datatype-jdk8:2.16.1' - implementation 'com.fasterxml.jackson.module:jackson-module-paranamer:2.15.3' implementation 'com.google.guava:guava:32.1.3-jre' implementation 'fr.inria.gforge.spoon:spoon-core:10.4.2' implementation 'info.picocli:picocli:4.7.5' implementation 'com.github.maracas:roseau:0.0.2-SNAPSHOT' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' } jar { diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 3a5edc67..7725c3b7 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -1,7 +1,5 @@ package com.github.maracas.gilesi.confgen; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; import com.github.maracas.gilesi.instrumentation.models.ClassParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; @@ -11,6 +9,8 @@ import com.github.maracas.roseau.api.model.ClassDecl; import com.github.maracas.roseau.api.model.ConstructorDecl; import com.github.maracas.roseau.api.model.MethodDecl; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; import spoon.Launcher; import spoon.reflect.CtModel; @@ -172,8 +172,8 @@ public static void main(String[] args) throws Exception { .forEach(method -> instrumentationParameters.ClientMethods .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); - ObjectMapper objectMapper = new ObjectMapper().enable(SerializationFeature.INDENT_OUTPUT); - String apiJson = objectMapper.writeValueAsString(instrumentationParameters); - Files.writeString(apiReportOutputPath, apiJson, StandardOpenOption.CREATE); + XStream xstream = new XStream(new DomDriver()); + String apiXml = xstream.toXML(instrumentationParameters); + Files.writeString(apiReportOutputPath, apiXml, StandardOpenOption.CREATE); } } \ No newline at end of file diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 5be55f8a..88a2c0ee 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -18,7 +18,6 @@ repositories { dependencies { implementation 'net.bytebuddy:byte-buddy:1.14.2' implementation 'net.bytebuddy:byte-buddy-agent:1.14.2' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index cf547d06..41b0d143 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -1,34 +1,39 @@ package com.github.maracas.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; import com.github.maracas.gilesi.instrumentation.models.ClassParameter; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; +import java.io.FileReader; import java.io.IOException; import java.lang.instrument.Instrumentation; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; /* Our main agent class */ public class Agent { - private static ObjectMapper objectMapper = new ObjectMapper(); public static XStream xstream = new XStream(new DomDriver()); public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { - return objectMapper.readValue(file, InstrumentationParameters.class); + String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + return (InstrumentationParameters) xstream.fromXML(xmlContent); } /* Our primary method to install the agent required to trace methods during execution - We take in as parameter a JSON file with the list of methods to instrument and their class + We take in as parameter a XML file with the list of methods to instrument and their class */ private static void installAgent(String arg, Instrumentation inst) { + xstream.addPermission(AnyTypePermission.ANY); + // First, install the ByteBuddy Agent required to redefine classes during execution // Sometimes this can fail, so try to catch it try { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index 4918f216..a4164925 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -1,6 +1,5 @@ package com.github.maracas.gilesi.instrumentation; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; @@ -49,14 +48,15 @@ public static Collection getMethodTraces() { /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults() throws IOException { - FileWriter outputFile = new FileWriter("MethodTraces.json"); + public static void SaveTraceResults() { System.out.println("Saving trace results in progress..."); - System.out.printf("Output location: %s%n", Paths.get("MethodTraces.json").toAbsolutePath()); + System.out.printf("Output location: %s%n", Paths.get("MethodTraces.xml").toAbsolutePath()); try { String xmlOutputString = Agent.xstream.toXML(TraceCollector.getMethodTraces()); + FileWriter outputFile = new FileWriter("MethodTraces.xml"); outputFile.write(xmlOutputString); + outputFile.close(); } catch (Exception e) { System.err.println("ERROR"); e.printStackTrace(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index de19e7a2..fe763e22 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -5,8 +5,13 @@ public class TraceDataFactory { public static TraceData valueOf(Object object, int nullInstanceId) { + TraceData traceData = new TraceData(); + if (object == null) { - return new TraceData("Object", "null", nullInstanceId); + traceData.fullyQualifiedTypeName = "Object"; + traceData.dataAsXml = "null"; + traceData.instanceId = nullInstanceId; + return traceData; } // /!\ CAUTION @@ -31,6 +36,10 @@ public static TraceData valueOf(Object object, int nullInstanceId) { System.err.printf("ERROR: Cannot serialize specific argument: %s%n", e); } - return new TraceData(objectClassName, serializedString, instanceId); + traceData.fullyQualifiedTypeName = objectClassName; + traceData.dataAsXml = serializedString; + traceData.instanceId = instanceId; + + return traceData; } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index f39a3236..a509cd5b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -106,8 +106,8 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object // Every argument of a method should have the same instance id, in the case of null params, they will be different, so fix that for (int i = 0; i < preCallArguments.size(); i++) { - if (postCallArguments.get(i).getInstanceId() < 0) { // Null ids are intentionally negative - postCallArguments.get(i).setInstanceId(preCallArguments.get(i).getInstanceId()); + if (postCallArguments.get(i).instanceId < 0) { // Null ids are intentionally negative + postCallArguments.get(i).instanceId = preCallArguments.get(i).instanceId; } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java index b94cb05d..41ac5d61 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java @@ -1,8 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class PartialTrace { @@ -11,12 +8,11 @@ public class PartialTrace { private List preCallArguments; private long timeStampEntry; - @JsonCreator public PartialTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("timeStampEntry") long timeStampEntry) { + String methodSignature, + TraceData instance, + List preCallArguments, + long timeStampEntry) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java index 9b7be17e..ad81bd23 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -1,8 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class Trace extends PartialTrace { @@ -12,17 +9,16 @@ public class Trace extends PartialTrace { private TraceData exceptionThrown; private String[] stackTrace; - @JsonCreator public Trace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") TraceData returnedValue, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown, - @JsonProperty("stackTrace") String[] stackTrace) { + String methodSignature, + TraceData instance, + List preCallArguments, + List postCallArguments, + TraceData returnedValue, + long timeStampEntry, + long timeStampExit, + TraceData exceptionThrown, + String[] stackTrace) { super(methodSignature, instance, preCallArguments, timeStampEntry); this.postCallArguments = postCallArguments; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java index bb40ae81..11779617 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java @@ -1,44 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - public class TraceData { - private String fullyQualifiedTypeName; - private String dataAsJson; - private int instanceId; - - @JsonCreator - public TraceData( - @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, - @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - this.dataAsJson = dataAsJson; - this.instanceId = instanceId; - } - - public String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; - } - - public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - } - - public String getDataAsJson() { - return dataAsJson; - } - - public void setDataAsJson(String dataAsJson) { - this.dataAsJson = dataAsJson; - } - - public int getInstanceId() { - return instanceId; - } - - public void setInstanceId(int instanceId) { - this.instanceId = instanceId; - } + public String fullyQualifiedTypeName; + public String dataAsXml; + public int instanceId; } \ No newline at end of file diff --git a/Samples/sampleclient/build.gradle b/Samples/sampleclient/build.gradle index d070c8c1..a763a8b6 100644 --- a/Samples/sampleclient/build.gradle +++ b/Samples/sampleclient/build.gradle @@ -23,7 +23,7 @@ testing { all { testTask.configure { systemProperty 'net.bytebuddy.experimental', 'true' - jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.maracas.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.json"'] + jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.maracas.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.xml"'] } } } diff --git a/TraceView/build.gradle b/TraceView/build.gradle index 54b6c322..3134e079 100644 --- a/TraceView/build.gradle +++ b/TraceView/build.gradle @@ -24,8 +24,8 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' implementation 'org.apache.commons:commons-text:1.10.0' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' } jar { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java index b94cb05d..41ac5d61 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java @@ -1,8 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class PartialTrace { @@ -11,12 +8,11 @@ public class PartialTrace { private List preCallArguments; private long timeStampEntry; - @JsonCreator public PartialTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("timeStampEntry") long timeStampEntry) { + String methodSignature, + TraceData instance, + List preCallArguments, + long timeStampEntry) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java index 9b7be17e..ad81bd23 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java @@ -1,8 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - import java.util.List; public class Trace extends PartialTrace { @@ -12,17 +9,16 @@ public class Trace extends PartialTrace { private TraceData exceptionThrown; private String[] stackTrace; - @JsonCreator public Trace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") TraceData returnedValue, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown, - @JsonProperty("stackTrace") String[] stackTrace) { + String methodSignature, + TraceData instance, + List preCallArguments, + List postCallArguments, + TraceData returnedValue, + long timeStampEntry, + long timeStampExit, + TraceData exceptionThrown, + String[] stackTrace) { super(methodSignature, instance, preCallArguments, timeStampEntry); this.postCallArguments = postCallArguments; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java index bb40ae81..11779617 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java @@ -1,44 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - public class TraceData { - private String fullyQualifiedTypeName; - private String dataAsJson; - private int instanceId; - - @JsonCreator - public TraceData( - @JsonProperty("fullyQualifiedTypeName") String fullyQualifiedTypeName, - @JsonProperty("dataAsJson") String dataAsJson, - @JsonProperty("instanceId") int instanceId) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - this.dataAsJson = dataAsJson; - this.instanceId = instanceId; - } - - public String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; - } - - public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - } - - public String getDataAsJson() { - return dataAsJson; - } - - public void setDataAsJson(String dataAsJson) { - this.dataAsJson = dataAsJson; - } - - public int getInstanceId() { - return instanceId; - } - - public void setInstanceId(int instanceId) { - this.instanceId = instanceId; - } + public String fullyQualifiedTypeName; + public String dataAsXml; + public int instanceId; } \ No newline at end of file diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java index 9c9ce6f9..60c174dd 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java @@ -1,11 +1,13 @@ package com.github.maracas.gilesi.traceview; -import com.fasterxml.jackson.databind.ObjectMapper; import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; -import java.io.File; import java.io.IOException; +import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.Arrays; @@ -13,10 +15,15 @@ import java.util.Map; import java.util.Set; +import java.util.ArrayList; +import java.util.List; + public class Main { private static TestTraceResults[] readTraces(String filePathStr) throws IOException { - ObjectMapper objectMapper = new ObjectMapper(); - return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); + XStream xstream = new XStream(new DomDriver()); + xstream.addPermission(AnyTypePermission.ANY); + String xmlContent = new String(Files.readAllBytes(Path.of(filePathStr)), StandardCharsets.UTF_8); + return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new); } public static void main(String[] args) throws Exception { @@ -77,8 +84,9 @@ public static void main(String[] args) throws Exception { stringBuilder.append("package %s;\n\n".formatted(packageName)); } - stringBuilder.append("import com.fasterxml.jackson.core.JsonProcessingException;\n"); - stringBuilder.append("import com.fasterxml.jackson.databind.ObjectMapper;\n"); + stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); + stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); + stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); stringBuilder.append("import org.junit.jupiter.api.Test;\n"); stringBuilder.append("\n"); stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); @@ -94,7 +102,7 @@ public static void main(String[] args) throws Exception { String testName = testTraces.getKey(); stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws JsonProcessingException {\n".formatted(testName)); + stringBuilder.append("\tpublic void %s() throws XStreamException {\n".formatted(testName)); VariableStackHandler variableStackHandler = new VariableStackHandler(); diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java index e9b05484..2c2f903b 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java @@ -44,10 +44,10 @@ public static String getCleanedType(String FQN) { } public static String serializableDataToJava(TraceData serializableData) { - String valueToBeEqualTo = serializableData.getDataAsJson(); - String FQN = getCleanedType(serializableData.getFullyQualifiedTypeName()); + String valueToBeEqualTo = serializableData.dataAsXml; + String FQN = getCleanedType(serializableData.fullyQualifiedTypeName); - if (!FQN.equals("java.lang.Integer") && + /*if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && !FQN.equals("java.lang.Boolean") && !FQN.equals("java.lang.Byte") && @@ -57,8 +57,11 @@ public static String serializableDataToJava(TraceData serializableData) { !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - valueToBeEqualTo = "new ObjectMapper().readValue(\"%s\", %s.class)".formatted(StringEscapeUtils.escapeJava(serializableData.getDataAsJson()), FQN); - } + valueToBeEqualTo = "(%s) (new XStream(new DomDriver()).fromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + }*/ + + valueToBeEqualTo = "(%s) (new XStream(new DomDriver()).fromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + return valueToBeEqualTo; } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java index d8f8b7cd..e4909ce6 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java @@ -8,24 +8,24 @@ public class TestMethodGenerator { private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler) throws Exception { - if (arg.getDataAsJson() != null) { - if (arg.getDataAsJson().equals("null")) { - return arg.getDataAsJson(); + if (arg.dataAsXml != null) { + if (arg.dataAsXml.equals("null")) { + return arg.dataAsXml; } return SerializationUtils.serializableDataToJava(arg); - } else if (variableStackHandler.isInstanceVariableNameDefined(arg.getInstanceId())) { - return variableStackHandler.getInstanceVariableName(arg.getInstanceId()); + } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { + return variableStackHandler.getInstanceVariableName(arg.instanceId); } else { - return "/* Unserializable Instance with Id: %d */".formatted(arg.getInstanceId()); + return "/* Unserializable Instance with Id: %d */".formatted(arg.instanceId); } } private static String getDataVariableDeclaration(TraceData serializableData, VariableStackHandler variableStackHandler) throws Exception { - if (variableStackHandler.isInstanceVariableNameDefined(serializableData.getInstanceId())) { - return variableStackHandler.getInstanceVariableName(serializableData.getInstanceId()); + if (variableStackHandler.isInstanceVariableNameDefined(serializableData.instanceId)) { + return variableStackHandler.getInstanceVariableName(serializableData.instanceId); } else { - String returnType = SerializationUtils.getCleanedType(serializableData.getFullyQualifiedTypeName()); - String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.getInstanceId()); + String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); return "%s %s".formatted(returnType, instanceVariableName); } } @@ -36,8 +36,8 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler TraceData traceData = methodTrace.getInstance(); - boolean isConstructor = traceData != null && traceData.getFullyQualifiedTypeName().equals(methodName); - boolean isInstanceCall = traceData != null && !traceData.getFullyQualifiedTypeName().equals(methodName); + boolean isConstructor = traceData != null && traceData.fullyQualifiedTypeName.equals(methodName); + boolean isInstanceCall = traceData != null && !traceData.fullyQualifiedTypeName.equals(methodName); String methodCall = methodName; @@ -45,7 +45,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler methodCall = "new %s".formatted(methodCall); // TODO: we need to fix the tracer so for constructors we get to return an instance, and instead leave instance field empty, to make more sense and simplify this part too!! - // TODO: also we may want seen indexes to keep the order in the json in general for traces, like which index we added something at for sanity, can be useful when ordering things properly! + // TODO: also we may want seen indexes to keep the order in the xml in general for traces, like which index we added something at for sanity, can be useful when ordering things properly! // TODO: last but not least, we can return instances that either previously existed or never did. // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? @@ -54,7 +54,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler methodCall = "%s = %s".formatted(argumentVariable, methodCall); } else if (isInstanceCall) { String instanceMethodCallName = methodCall.split("\\.")[methodCall.split("\\.").length - 1]; - String instanceVariableName = variableStackHandler.getInstanceVariableName(traceData.getInstanceId()); + String instanceVariableName = variableStackHandler.getInstanceVariableName(traceData.instanceId); methodCall = "%s.%s".formatted(instanceVariableName, instanceMethodCallName); } @@ -78,7 +78,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab String argumentVariable = getDataVariableDeclaration(arg, variableStackHandler); String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); - argList.add(variableStackHandler.getInstanceVariableName(arg.getInstanceId())); + argList.add(variableStackHandler.getInstanceVariableName(arg.instanceId)); // Define the variable before the method variableList.add("%s;".formatted(argumentDeclaration)); @@ -93,7 +93,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler) throws Exception { String valueAsCode = serializableDataToCode(traceData, variableStackHandler); - int instanceId = traceData.getInstanceId(); + int instanceId = traceData.instanceId; if (valueAsCode.endsWith("[].class)")) { return "assertArrayEquals(%s, %s);".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); } else { @@ -120,7 +120,7 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws Exception { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().getFullyQualifiedTypeName().equals(cleanedMethodName); + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().fullyQualifiedTypeName.equals(cleanedMethodName); TraceData traceData = methodTrace.getReturnedValue(); diff --git a/compile.cmd b/compile.cmd index f9c00201..feb7414e 100644 --- a/compile.cmd +++ b/compile.cmd @@ -1,6 +1,6 @@ @echo off -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 +set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot echo. echo =========================================================== diff --git a/maracas-test.cmd b/maracas-test.cmd index 2aba2479..cc7404ff 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -3,7 +3,7 @@ call run-clean-workflow.cmd call compile.cmd -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.1 +set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 @@ -13,7 +13,7 @@ echo Running ConfGen echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" +%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" echo. echo =========================================================== @@ -32,11 +32,11 @@ echo Running TraceView echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.json" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" mkdir Results -move %CD%\MaracasConfiguration.json Results\ +move %CD%\MaracasConfiguration.xml Results\ move C:\Users\Gus\Documents\GitHub\maracas\forges\gilesi.instrumentation.log Results\ -move C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.json Results\ +move C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml Results\ move %CD%\TraceView.Output Results\ \ No newline at end of file diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 901133a7..e48ab3f0 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -3,7 +3,7 @@ call run-clean-workflow.cmd call compile.cmd -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 +set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot echo. @@ -24,7 +24,7 @@ echo Running ConfGen echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.json" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" echo. @@ -44,11 +44,11 @@ echo Running TraceView echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.json" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" mkdir Results -move %CD%\TestWorkflowConfiguration.json Results\ +move %CD%\TestWorkflowConfiguration.xnl Results\ move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ -move %CD%\Samples\sampleclient\MethodTraces.json Results\ +move %CD%\Samples\sampleclient\MethodTraces.xml Results\ move %CD%\TraceView.Output Results\ \ No newline at end of file diff --git a/test.cmd b/test.cmd index c3921363..20dfe283 100644 --- a/test.cmd +++ b/test.cmd @@ -1 +1 @@ -%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.maracas.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.json" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.maracas.gilesi.samples.sampleclient.Main2 \ No newline at end of file +%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.maracas.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.xml" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.maracas.gilesi.samples.sampleclient.Main2 \ No newline at end of file From a1316f31be39dbf0a30ba9611b94cf5dbb2ac96d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 22 Apr 2024 08:55:14 +0200 Subject: [PATCH 085/244] Rename model classes --- .../github/maracas/gilesi/confgen/Main.java | 70 +++++++++---------- .../gilesi/instrumentation/models/Class.java | 9 +++ .../models/ClassParameter.java | 9 --- .../models/InstrumentationParameters.java | 2 +- .../gilesi/instrumentation/models/Method.java | 8 +++ .../models/MethodParameter.java | 8 --- .../maracas/gilesi/instrumentation/Agent.java | 4 +- .../gilesi/instrumentation/models/Class.java | 7 ++ .../models/ClassParameter.java | 7 -- .../models/InstrumentationParameters.java | 2 +- .../gilesi/instrumentation/models/Method.java | 8 +++ .../models/MethodParameter.java | 6 -- .../visitors/MethodInstrumentor.java | 20 +++--- compile.cmd | 2 +- maracas-test.cmd | 2 +- run-test-workflow.cmd | 5 +- 16 files changed, 86 insertions(+), 83 deletions(-) create mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java create mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java delete mode 100644 ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java delete mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java index 7725c3b7..981f17e3 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java @@ -1,9 +1,9 @@ package com.github.maracas.gilesi.confgen; import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; -import com.github.maracas.gilesi.instrumentation.models.ClassParameter; +import com.github.maracas.gilesi.instrumentation.models.Class; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; -import com.github.maracas.gilesi.instrumentation.models.MethodParameter; +import com.github.maracas.gilesi.instrumentation.models.Method; import com.github.maracas.roseau.api.SpoonAPIExtractor; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; @@ -47,11 +47,11 @@ private static String getMethodNameFromFQN(String fullyQualifiedName) { } private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName, String methodDescriptor) { - for (ClassParameter classToInstrument : instrumentationParameters.Classes) { - if (classToInstrument.Name.equals(className)) { - for (MethodParameter methodParameter : classToInstrument.Methods) { - if (methodParameter.Name.equals(methodName)) { - for (String descriptorToInstrument : methodParameter.Descriptors) { + for (Class classToInstrument : instrumentationParameters.InstrumentedAPIClasses) { + if (classToInstrument.ClassName.equals(className)) { + for (Method methodParameter : classToInstrument.ClassMethods) { + if (methodParameter.MethodName.equals(methodName)) { + for (String descriptorToInstrument : methodParameter.MethodDescriptors) { if (descriptorToInstrument.equals(methodDescriptor)) { // Element is already in the config, return now return; @@ -59,60 +59,60 @@ private static void addToInstrumentationObject(InstrumentationParameters instrum } // Element doesn't have a descriptor in the config, add now - methodParameter.Descriptors.add(methodDescriptor); + methodParameter.MethodDescriptors.add(methodDescriptor); return; } } // Element doesn't have a method in the config, add now - MethodParameter methodParameter = new MethodParameter(); - methodParameter.Name = methodName; - methodParameter.Descriptors = new ArrayList<>(); - methodParameter.Descriptors.add(methodDescriptor); + Method methodParameter = new Method(); + methodParameter.MethodName = methodName; + methodParameter.MethodDescriptors = new ArrayList<>(); + methodParameter.MethodDescriptors.add(methodDescriptor); - classToInstrument.Methods.add(methodParameter); + classToInstrument.ClassMethods.add(methodParameter); return; } } // Element doesn't have a class in the config, add now - ClassParameter classParameter = new ClassParameter(); - classParameter.Name = className; - classParameter.Methods = new ArrayList<>(); - classParameter.Descriptors = new ArrayList<>(); - MethodParameter methodParameter = new MethodParameter(); - methodParameter.Name = methodName; - methodParameter.Descriptors = new ArrayList<>(); - methodParameter.Descriptors.add(methodDescriptor); - classParameter.Methods.add(methodParameter); - - instrumentationParameters.Classes.add(classParameter); + Class classParameter = new Class(); + classParameter.ClassName = className; + classParameter.ClassMethods = new ArrayList<>(); + classParameter.ClassDescriptors = new ArrayList<>(); + Method methodParameter = new Method(); + methodParameter.MethodName = methodName; + methodParameter.MethodDescriptors = new ArrayList<>(); + methodParameter.MethodDescriptors.add(methodDescriptor); + classParameter.ClassMethods.add(methodParameter); + + instrumentationParameters.InstrumentedAPIClasses.add(classParameter); } private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String constructorDescriptor) { - for (ClassParameter classToInstrument : instrumentationParameters.Classes) { - if (classToInstrument.Name.equals(className)) { - for (String descriptorToInstrument : classToInstrument.Descriptors) { + for (Class classToInstrument : instrumentationParameters.InstrumentedAPIClasses) { + if (classToInstrument.ClassName.equals(className)) { + for (String descriptorToInstrument : classToInstrument.ClassDescriptors) { if (descriptorToInstrument.equals(constructorDescriptor)) { // Element is already in the config, return now return; } // Element doesn't have a descriptor in the config, add now - classToInstrument.Descriptors.add(constructorDescriptor); + classToInstrument.ClassDescriptors.add(constructorDescriptor); return; } } } // Element doesn't have a class in the config, add now - ClassParameter classParameter = new ClassParameter(); - classParameter.Name = className; - classParameter.Methods = new ArrayList<>(); - classParameter.Descriptors = new ArrayList<>(); - classParameter.Descriptors.add(constructorDescriptor); + Class classParameter = new Class(); + classParameter.ClassName = className; + classParameter.ClassMethods = new ArrayList<>(); + classParameter.ClassDescriptors = new ArrayList<>(); + classParameter.ClassDescriptors.add(constructorDescriptor); - instrumentationParameters.Classes.add(classParameter); + instrumentationParameters.InstrumentedAPIClasses.add(classParameter); } public static void main(String[] args) throws Exception { @@ -129,7 +129,7 @@ public static void main(String[] args) throws Exception { API libraryApiModel = new SpoonAPIExtractor().extractAPI(libraryModel); InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); - instrumentationParameters.Classes = new ArrayList<>(); + instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java new file mode 100644 index 00000000..ee5d16ab --- /dev/null +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java @@ -0,0 +1,9 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class Class { + public String ClassName; + public List ClassMethods; + public List ClassDescriptors; +} diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java deleted file mode 100644 index d7e78db4..00000000 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -import java.util.List; - -public class ClassParameter { - public String Name; - public List Methods; - public List Descriptors; -} diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 511b8a4e..9bed95c6 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -3,7 +3,7 @@ import java.util.List; public class InstrumentationParameters { - public List Classes; + public List InstrumentedAPIClasses; public List LibraryMethods; public List ClientMethods; } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java new file mode 100644 index 00000000..3e8de891 --- /dev/null +++ b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class Method { + public String MethodName; + public List MethodDescriptors; +} \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java deleted file mode 100644 index 2646931a..00000000 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java +++ /dev/null @@ -1,8 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -import java.util.List; - -public class MethodParameter { - public String Name; - public List Descriptors; -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 41b0d143..37d72584 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -1,6 +1,6 @@ package com.github.maracas.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.ClassParameter; +import com.github.maracas.gilesi.instrumentation.models.Class; import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; @@ -67,7 +67,7 @@ private static void installAgent(String arg, Instrumentation inst) { CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; // Instrument every class - for (ClassParameter instrumentationParameter : instrumentationParameters.Classes) { + for (Class instrumentationParameter : instrumentationParameters.InstrumentedAPIClasses) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java new file mode 100644 index 00000000..070377b7 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java @@ -0,0 +1,7 @@ +package com.github.maracas.gilesi.instrumentation.models; + +public class Class { + public String ClassName; + public Method[] ClassMethods; + public String[] ClassDescriptors; +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java deleted file mode 100644 index a7bed2d5..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/ClassParameter.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -public class ClassParameter { - public String Name; - public MethodParameter[] Methods; - public String[] Descriptors; -} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java index 76ec2e09..27fa54e9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation.models; public class InstrumentationParameters { - public ClassParameter[] Classes; + public Class[] InstrumentedAPIClasses; public String[] LibraryMethods; public String[] ClientMethods; } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java new file mode 100644 index 00000000..881f209b --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java @@ -0,0 +1,8 @@ +package com.github.maracas.gilesi.instrumentation.models; + +import java.util.List; + +public class Method { + public String MethodName; + public String[] MethodDescriptors; +} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java deleted file mode 100644 index 3549d846..00000000 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/MethodParameter.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.github.maracas.gilesi.instrumentation.models; - -public class MethodParameter { - public String Name; - public String[] Descriptors; -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java index 9c06ecf7..34d4b480 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -1,7 +1,7 @@ package com.github.maracas.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.ClassParameter; -import com.github.maracas.gilesi.instrumentation.models.MethodParameter; +import com.github.maracas.gilesi.instrumentation.models.Class; +import com.github.maracas.gilesi.instrumentation.models.Method; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; @@ -14,9 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; public class MethodInstrumentor { - private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(ClassParameter classParameter) { + private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(Class classParameter) { ElementMatcher.Junction descriptorMatcher = null; - for (String descriptorParameter : classParameter.Descriptors) { + for (String descriptorParameter : classParameter.ClassDescriptors) { if (descriptorMatcher == null) { descriptorMatcher = hasDescriptor(descriptorParameter); } else { @@ -26,12 +26,12 @@ private static ElementMatcher.Junction getConstructorElementM return descriptorMatcher; } - private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(ClassParameter classParameter) { + private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(Class classParameter) { ElementMatcher.Junction classMatcher = null; - for (MethodParameter methodParameter : classParameter.Methods) { - ElementMatcher.Junction methodMatcher = named(methodParameter.Name); + for (Method methodParameter : classParameter.ClassMethods) { + ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); ElementMatcher.Junction descriptorMatcher = null; - for (String descriptorParameter : methodParameter.Descriptors) { + for (String descriptorParameter : methodParameter.MethodDescriptors) { if (descriptorMatcher == null) { descriptorMatcher = hasDescriptor(descriptorParameter); } else { @@ -49,12 +49,12 @@ private static ElementMatcher.Junction getMethodElementMatche return classMatcher; } - public static void instrumentClassForTracingAgent(Instrumentation inst, ClassParameter classParameter) { + public static void instrumentClassForTracingAgent(Instrumentation inst, Class classParameter) { ElementMatcher.Junction methodMatcher = getMethodElementMatcherFromClassParameter(classParameter); ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); new AgentBuilder.Default() - .type(named(classParameter.Name)) + .type(named(classParameter.ClassName)) .transform((builder, typeDescription, classLoader, diff --git a/compile.cmd b/compile.cmd index feb7414e..f9c00201 100644 --- a/compile.cmd +++ b/compile.cmd @@ -1,6 +1,6 @@ @echo off -set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 echo. echo =========================================================== diff --git a/maracas-test.cmd b/maracas-test.cmd index cc7404ff..cb7bac1c 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -3,7 +3,7 @@ call run-clean-workflow.cmd call compile.cmd -set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index e48ab3f0..0939d81c 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -3,7 +3,7 @@ call run-clean-workflow.cmd call compile.cmd -set JAVA_HOME=C:\Program Files (Arm)\Microsoft\jdk-21.0.2.13-hotspot +set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 echo. @@ -51,4 +51,5 @@ mkdir Results move %CD%\TestWorkflowConfiguration.xnl Results\ move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ move %CD%\Samples\sampleclient\MethodTraces.xml Results\ -move %CD%\TraceView.Output Results\ \ No newline at end of file +move %CD%\TraceView.Output Results\ +move %CD%\TestWorkflowConfiguration.xml Results\ \ No newline at end of file From 7af64814408f2117477168b1e1cdd17681da9d96 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 22 Apr 2024 09:24:37 +0200 Subject: [PATCH 086/244] Create utility Xml class --- .../maracas/gilesi/instrumentation/Agent.java | 10 +-------- .../instrumentation/TraceCollector.java | 5 +---- .../instrumentation/TraceDataFactory.java | 5 ++--- .../gilesi/instrumentation/TraceFactory.java | 3 +-- .../gilesi/instrumentation/XmlUtils.java | 22 +++++++++++++++++++ .../gilesi/instrumentation/models/Method.java | 2 -- 6 files changed, 27 insertions(+), 20 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java index 37d72584..4d46912e 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java @@ -4,13 +4,9 @@ import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.xml.DomDriver; -import com.thoughtworks.xstream.security.AnyTypePermission; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; -import java.io.FileReader; import java.io.IOException; import java.lang.instrument.Instrumentation; import java.nio.charset.StandardCharsets; @@ -20,11 +16,9 @@ Our main agent class */ public class Agent { - public static XStream xstream = new XStream(new DomDriver()); - public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - return (InstrumentationParameters) xstream.fromXML(xmlContent); + return XmlUtils.getFromXml(xmlContent); } /* @@ -32,8 +26,6 @@ public static InstrumentationParameters parseInstrumentationparameters(File file We take in as parameter a XML file with the list of methods to instrument and their class */ private static void installAgent(String arg, Instrumentation inst) { - xstream.addPermission(AnyTypePermission.ANY); - // First, install the ByteBuddy Agent required to redefine classes during execution // Sometimes this can fail, so try to catch it try { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java index a4164925..83687fea 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java @@ -3,10 +3,7 @@ import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; import com.github.maracas.gilesi.instrumentation.models.Trace; -import java.io.File; import java.io.FileWriter; -import java.io.IOException; -import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; import java.util.Collection; @@ -53,7 +50,7 @@ public static void SaveTraceResults() { System.out.printf("Output location: %s%n", Paths.get("MethodTraces.xml").toAbsolutePath()); try { - String xmlOutputString = Agent.xstream.toXML(TraceCollector.getMethodTraces()); + String xmlOutputString = XmlUtils.getToXml(TraceCollector.getMethodTraces()); FileWriter outputFile = new FileWriter("MethodTraces.xml"); outputFile.write(xmlOutputString); outputFile.close(); diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java index fe763e22..09b3b0f0 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java @@ -1,7 +1,6 @@ package com.github.maracas.gilesi.instrumentation; import com.github.maracas.gilesi.instrumentation.models.TraceData; -import com.thoughtworks.xstream.XStreamException; public class TraceDataFactory { public static TraceData valueOf(Object object, int nullInstanceId) { @@ -31,8 +30,8 @@ public static TraceData valueOf(Object object, int nullInstanceId) { String serializedString = null; try { - serializedString = Agent.xstream.toXML(object); - } catch (XStreamException e) { + serializedString = XmlUtils.getToXml(object); + } catch (Exception e) { System.err.printf("ERROR: Cannot serialize specific argument: %s%n", e); } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java index a509cd5b..6af2236d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java @@ -13,9 +13,8 @@ import java.util.stream.Collectors; public class TraceFactory { - private static int NullCounter = 0; - public static final long ProcessEntryTimeStamp = System.nanoTime(); + private static int NullCounter = 0; /** * Gets the origin name from an Exectuable object with the signature if possible. diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java new file mode 100644 index 00000000..c49f78ab --- /dev/null +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java @@ -0,0 +1,22 @@ +package com.github.maracas.gilesi.instrumentation; + +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; + +public class XmlUtils { + @SuppressWarnings("unchecked") + public static T getFromXml(String xmlString) { + DomDriver domDriver = new DomDriver(); + XStream xStream = new XStream(domDriver); + xStream.addPermission(AnyTypePermission.ANY); + Object obj = xStream.fromXML(xmlString); + return (T) obj; + } + + public static String getToXml(Object obj) { + DomDriver domDriver = new DomDriver(); + XStream xStream = new XStream(domDriver); + return xStream.toXML(obj); + } +} diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java index 881f209b..63f168d8 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java +++ b/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java @@ -1,7 +1,5 @@ package com.github.maracas.gilesi.instrumentation.models; -import java.util.List; - public class Method { public String MethodName; public String[] MethodDescriptors; From b6dc040a62e0ed77c701f3c560ce1140b7c685c8 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 22 Apr 2024 09:30:41 +0200 Subject: [PATCH 087/244] Rename package names --- ConfGen/build.gradle | 10 +++---- .../gilesi/confgen/CodeType.java | 2 +- .../{maracas => }/gilesi/confgen/Main.java | 10 +++---- .../gilesi/confgen/RoseauDescriptor.java | 2 +- .../confgen/spoon/SpoonLauncherUtilities.java | 4 +-- .../gilesi/instrumentation/models/Class.java | 2 +- .../models/InstrumentationParameters.java | 2 +- .../gilesi/instrumentation/models/Method.java | 2 +- Instrumentation/build.gradle | 16 +++++----- .../gilesi/instrumentation/Agent.java | 10 +++---- .../gilesi/instrumentation/Logger.java | 2 +- .../instrumentation/TraceCollector.java | 6 ++-- .../instrumentation/TraceDataFactory.java | 4 +-- .../gilesi/instrumentation/TraceFactory.java | 12 ++++---- .../gilesi/instrumentation/XmlUtils.java | 2 +- .../gilesi/instrumentation/models/Class.java | 2 +- .../models/InstrumentationParameters.java | 2 +- .../gilesi/instrumentation/models/Method.java | 2 +- .../instrumentation/models/PartialTrace.java | 2 +- .../models/TestTraceResults.java | 2 +- .../gilesi/instrumentation/models/Trace.java | 2 +- .../instrumentation/models/TraceData.java | 2 +- .../visitors/CommonAdvisor.java | 30 +++++++++---------- .../visitors/ConstructorAdvisor.java | 4 +-- .../visitors/MethodAdvisor.java | 4 +-- .../visitors/MethodInstrumentor.java | 6 ++-- Samples/sampleclient/build.gradle | 4 +-- .../gilesi/samples/sampleclient/C1.java | 4 +-- .../gilesi/samples/sampleclient/C2.java | 9 ++++++ .../gilesi/samples/sampleclient/Main.java | 4 +-- .../gilesi/samples/sampleclient/Main2.java | 6 ++-- .../gilesi/samples/sampleclient/C2.java | 9 ------ Samples/sampleclient/src/test/java/CTest.java | 6 ++-- .../sampleclient/src/test/java/FooTest.java | 6 ++-- Samples/samplelibrary/build.gradle | 2 +- .../gilesi/samples/samplelibrary/A.java | 2 +- .../gilesi/samples/samplelibrary/A2.java | 2 +- .../gilesi/samples/samplelibrary/Foo.java | 2 +- .../gilesi/samples/samplelibrary/Foo2.java | 2 +- .../samples/samplelibrary/IDoSomething.java | 5 ++++ .../samples/samplelibrary/IDoSomething.java | 5 ---- .../samplelibrary/src/test/java/ATest.java | 2 +- Samples/settings.gradle | 2 +- TraceView/build.gradle | 10 +++---- .../instrumentation/models/PartialTrace.java | 2 +- .../models/TestTraceResults.java | 2 +- .../gilesi/instrumentation/models/Trace.java | 2 +- .../instrumentation/models/TraceData.java | 2 +- .../{maracas => }/gilesi/traceview/Main.java | 6 ++-- .../gilesi/traceview/SerializationUtils.java | 4 +-- .../gilesi/traceview/TestMethodGenerator.java | 6 ++-- .../traceview/VariableStackHandler.java | 2 +- maracas-test.cmd | 4 +-- run-test-workflow.cmd | 4 +-- test.cmd | 2 +- 55 files changed, 131 insertions(+), 131 deletions(-) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/confgen/CodeType.java (79%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/confgen/Main.java (96%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/confgen/RoseauDescriptor.java (98%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/confgen/spoon/SpoonLauncherUtilities.java (98%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Class.java (73%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/InstrumentationParameters.java (76%) rename ConfGen/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Method.java (67%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/Agent.java (90%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/Logger.java (94%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/TraceCollector.java (91%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/TraceDataFactory.java (93%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/TraceFactory.java (92%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/XmlUtils.java (93%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Class.java (68%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/InstrumentationParameters.java (73%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Method.java (61%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/PartialTrace.java (95%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/TestTraceResults.java (66%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Trace.java (97%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/TraceData.java (68%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/visitors/CommonAdvisor.java (84%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/visitors/ConstructorAdvisor.java (89%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/visitors/MethodAdvisor.java (90%) rename Instrumentation/src/main/java/com/github/{maracas => }/gilesi/instrumentation/visitors/MethodInstrumentor.java (94%) rename Samples/sampleclient/src/main/java/com/github/{maracas => }/gilesi/samples/sampleclient/C1.java (54%) create mode 100644 Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java rename Samples/sampleclient/src/main/java/com/github/{maracas => }/gilesi/samples/sampleclient/Main.java (75%) rename Samples/sampleclient/src/main/java/com/github/{maracas => }/gilesi/samples/sampleclient/Main2.java (96%) delete mode 100644 Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C2.java rename Samples/samplelibrary/src/main/java/com/github/{maracas => }/gilesi/samples/samplelibrary/A.java (84%) rename Samples/samplelibrary/src/main/java/com/github/{maracas => }/gilesi/samples/samplelibrary/A2.java (82%) rename Samples/samplelibrary/src/main/java/com/github/{maracas => }/gilesi/samples/samplelibrary/Foo.java (96%) rename Samples/samplelibrary/src/main/java/com/github/{maracas => }/gilesi/samples/samplelibrary/Foo2.java (96%) create mode 100644 Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java delete mode 100644 Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java rename TraceView/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/PartialTrace.java (95%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/TestTraceResults.java (59%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/Trace.java (97%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/instrumentation/models/TraceData.java (68%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/traceview/Main.java (96%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/traceview/SerializationUtils.java (96%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/traceview/TestMethodGenerator.java (97%) rename TraceView/src/main/java/com/github/{maracas => }/gilesi/traceview/VariableStackHandler.java (96%) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index 187eead8..e4317259 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -3,7 +3,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '8.1.1' } -group 'com.github.maracas.gilesi.confgen' +group 'com.github.gilesi.confgen' version '1.0-SNAPSHOT' @@ -42,19 +42,19 @@ dependencies { jar { manifest { - attributes 'Main-Class': 'com.github.maracas.gilesi.confgen.Main', + attributes 'Main-Class': 'com.github.gilesi.confgen.Main', 'Multi-Release': 'true' } } application { - mainClass = 'com.github.maracas.gilesi.confgen.Main' + mainClass = 'com.github.gilesi.confgen.Main' } description = 'Main distribution.' shadowJar { - archiveBaseName.set('com.github.maracas.gilesi.confgen') + archiveBaseName.set('com.github.gilesi.confgen') archiveClassifier.set('') archiveVersion.set('') mergeServiceFiles() @@ -62,7 +62,7 @@ shadowJar { distributions { shadow { - distributionBaseName = 'com.github.maracas.gilesi.confgen' + distributionBaseName = 'com.github.gilesi.confgen' } } diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/CodeType.java b/ConfGen/src/main/java/com/github/gilesi/confgen/CodeType.java similarity index 79% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/CodeType.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/CodeType.java index 5e25f986..19a08cc4 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/CodeType.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/CodeType.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.confgen; +package com.github.gilesi.confgen; import java.util.EnumSet; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java similarity index 96% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 981f17e3..e110840a 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -1,9 +1,9 @@ -package com.github.maracas.gilesi.confgen; +package com.github.gilesi.confgen; -import com.github.maracas.gilesi.confgen.spoon.SpoonLauncherUtilities; -import com.github.maracas.gilesi.instrumentation.models.Class; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; -import com.github.maracas.gilesi.instrumentation.models.Method; +import com.github.gilesi.confgen.spoon.SpoonLauncherUtilities; +import com.github.gilesi.instrumentation.models.Class; +import com.github.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.gilesi.instrumentation.models.Method; import com.github.maracas.roseau.api.SpoonAPIExtractor; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java b/ConfGen/src/main/java/com/github/gilesi/confgen/RoseauDescriptor.java similarity index 98% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/RoseauDescriptor.java index a954d7e0..b0bae722 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/RoseauDescriptor.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/RoseauDescriptor.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.confgen; +package com.github.gilesi.confgen; import com.github.maracas.roseau.api.model.ConstructorDecl; import com.github.maracas.roseau.api.model.MethodDecl; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java similarity index 98% rename from ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java index cd703281..f7aeff3f 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.confgen.spoon; +package com.github.gilesi.confgen.spoon; -import com.github.maracas.gilesi.confgen.CodeType; +import com.github.gilesi.confgen.CodeType; import spoon.Launcher; import spoon.MavenLauncher; import spoon.SpoonException; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java similarity index 73% rename from ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java rename to ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java index ee5d16ab..f1f91237 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java +++ b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java similarity index 76% rename from ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java rename to ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java index 9bed95c6..6fd63595 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java similarity index 67% rename from ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java rename to ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java index 3e8de891..815720fe 100644 --- a/ConfGen/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java +++ b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 88a2c0ee..995aab0c 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -8,7 +8,7 @@ java { targetCompatibility = JavaVersion.VERSION_1_8 } -group = 'com.github.maracas.gilesi.instrumentation' +group = 'com.github.gilesi.instrumentation' version = '1.0-SNAPSHOT' repositories { @@ -23,24 +23,24 @@ dependencies { jar { manifest { - attributes 'Premain-Class': 'com.github.maracas.gilesi.instrumentation.Agent', - 'Agent-Class': 'com.github.maracas.gilesi.instrumentation.Agent', - 'Launcher-Agent-Class': 'com.github.maracas.gilesi.instrumentation.Agent', + attributes 'Premain-Class': 'com.github.gilesi.instrumentation.Agent', + 'Agent-Class': 'com.github.gilesi.instrumentation.Agent', + 'Launcher-Agent-Class': 'com.github.gilesi.instrumentation.Agent', 'Can-Retransform-Classes': 'true', 'Can-Redefine-Classes': 'true', - 'Main-Class': 'com.github.maracas.gilesi.instrumentation.Agent', + 'Main-Class': 'com.github.gilesi.instrumentation.Agent', 'Multi-Release': 'true' } } application { - mainClass = 'com.github.maracas.gilesi.instrumentation.Agent' + mainClass = 'com.github.gilesi.instrumentation.Agent' } description = 'Agent distribution.' shadowJar { - archiveBaseName.set('com.github.maracas.gilesi.instrumentation') + archiveBaseName.set('com.github.gilesi.instrumentation') archiveClassifier.set('') archiveVersion.set('') mergeServiceFiles() @@ -48,7 +48,7 @@ shadowJar { distributions { shadow { - distributionBaseName = 'com.github.maracas.gilesi.instrumentation' + distributionBaseName = 'com.github.gilesi.instrumentation' } } diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java similarity index 90% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 4d46912e..91ac1f00 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -1,9 +1,9 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.Class; -import com.github.maracas.gilesi.instrumentation.models.InstrumentationParameters; -import com.github.maracas.gilesi.instrumentation.visitors.CommonAdvisor; -import com.github.maracas.gilesi.instrumentation.visitors.MethodInstrumentor; +import com.github.gilesi.instrumentation.models.Class; +import com.github.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.gilesi.instrumentation.visitors.CommonAdvisor; +import com.github.gilesi.instrumentation.visitors.MethodInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java similarity index 94% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index bd2ca1da..f24e51d6 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; import java.io.File; import java.nio.file.Files; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java similarity index 91% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index 83687fea..190cca3a 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -1,7 +1,7 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; -import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.gilesi.instrumentation.models.TestTraceResults; +import com.github.gilesi.instrumentation.models.Trace; import java.io.FileWriter; import java.nio.file.Paths; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java similarity index 93% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index 09b3b0f0..d07a84ac 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { public static TraceData valueOf(Object object, int nullInstanceId) { diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java similarity index 92% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java index 6af2236d..32e1eae5 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java @@ -1,8 +1,8 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; -import com.github.maracas.gilesi.instrumentation.models.Trace; -import com.github.maracas.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.PartialTrace; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.instrumentation.models.TraceData; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -19,8 +19,8 @@ public class TraceFactory { /** * Gets the origin name from an Exectuable object with the signature if possible. *

- * E.g. for a constructor: public com.github.maracas.gilesi.tests.legacy.Foo(java.lang.String) - * for a method: public static java.lang.String com.github.maracas.gilesi.tests.legacy.Foo.HelloEveryone(java.lang.String[]) + * E.g. for a constructor: public com.github.gilesi.tests.legacy.Foo(java.lang.String) + * for a method: public static java.lang.String com.github.gilesi.tests.legacy.Foo.HelloEveryone(java.lang.String[]) * * @param origin The executable to get an origin name string from * @return the origin name string matching the passed in executable diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java similarity index 93% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java index c49f78ab..9be1906b 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/XmlUtils.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation; +package com.github.gilesi.instrumentation; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java similarity index 68% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java index 070377b7..a3ad9d76 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Class.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class Class { public String ClassName; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java similarity index 73% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java index 27fa54e9..1dc63771 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java similarity index 61% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java index 63f168d8..144a81da 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Method.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class Method { public String MethodName; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java similarity index 95% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index 41ac5d61..c9c5a707 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java similarity index 66% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java index 00b94913..e88b2162 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java similarity index 97% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index ad81bd23..4cc97861 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java similarity index 68% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index 11779617..7b459ec2 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class TraceData { public String fullyQualifiedTypeName; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java similarity index 84% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index 0fdbea37..57b951c9 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -1,16 +1,16 @@ -package com.github.maracas.gilesi.instrumentation.visitors; +package com.github.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.Logger; -import com.github.maracas.gilesi.instrumentation.TraceCollector; -import com.github.maracas.gilesi.instrumentation.TraceFactory; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; -import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.gilesi.instrumentation.Logger; +import com.github.gilesi.instrumentation.TraceCollector; +import com.github.gilesi.instrumentation.TraceFactory; +import com.github.gilesi.instrumentation.models.PartialTrace; +import com.github.gilesi.instrumentation.models.Trace; import java.lang.reflect.Executable; import java.util.Arrays; public class CommonAdvisor { - private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.maracas.gilesi.instrumentation"; + private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.gilesi.instrumentation"; private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; @@ -91,8 +91,8 @@ private static boolean isAcceptedTrace(String[] stackTrace) { Logger.Log(loggerInstance, String.format(" %s", methodName)); } - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) + // 0: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) + // 1: The instrumented method: com.github.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) // 2: The caller: FooTest.mainTest(FooTest.java:50) // 3: ... @@ -115,8 +115,8 @@ private static boolean isAcceptedTrace(String[] stackTrace) { // Serialize an object, and while doing so, we go into our entry/exit methods // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - // 0: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 1: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 0: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 1: The instrumented method: com.github.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) @@ -126,10 +126,10 @@ private static boolean isAcceptedTrace(String[] stackTrace) { // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.maracas.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.maracas.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.maracas.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 14: The instrumented method: com.github.maracas.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) + // 11: com.github.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) + // 12: com.github.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) + // 13: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) + // 14: The instrumented method: com.github.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) // 15: The caller: ... if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTrace.length >= instrumentedMethodStackTraceIndex + 10) { String originatingReflectMethodName = stackTrace[instrumentedMethodStackTraceIndex + 10]; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/ConstructorAdvisor.java similarity index 89% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/ConstructorAdvisor.java index 0a254d08..d74cb408 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/ConstructorAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/ConstructorAdvisor.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.instrumentation.visitors; +package com.github.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.gilesi.instrumentation.models.PartialTrace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java similarity index 90% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java index a41fe99f..d7d2f235 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.instrumentation.visitors; +package com.github.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.PartialTrace; +import com.github.gilesi.instrumentation.models.PartialTrace; import net.bytebuddy.asm.Advice; import net.bytebuddy.implementation.bytecode.assign.Assigner; diff --git a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java similarity index 94% rename from Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java rename to Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java index 34d4b480..7647c18d 100644 --- a/Instrumentation/src/main/java/com/github/maracas/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -1,7 +1,7 @@ -package com.github.maracas.gilesi.instrumentation.visitors; +package com.github.gilesi.instrumentation.visitors; -import com.github.maracas.gilesi.instrumentation.models.Class; -import com.github.maracas.gilesi.instrumentation.models.Method; +import com.github.gilesi.instrumentation.models.Class; +import com.github.gilesi.instrumentation.models.Method; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; diff --git a/Samples/sampleclient/build.gradle b/Samples/sampleclient/build.gradle index a763a8b6..96606acc 100644 --- a/Samples/sampleclient/build.gradle +++ b/Samples/sampleclient/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' } -group = 'com.github.maracas.gilesi.samples.sampleclient' +group = 'com.github.gilesi.samples.sampleclient' version = '1.0-SNAPSHOT' repositories { @@ -23,7 +23,7 @@ testing { all { testTask.configure { systemProperty 'net.bytebuddy.experimental', 'true' - jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.maracas.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.xml"'] + jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.xml"'] } } } diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C1.java b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java similarity index 54% rename from Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C1.java rename to Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java index 07fec197..d9d039c3 100644 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C1.java +++ b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.samples.sampleclient; +package com.github.gilesi.samples.sampleclient; -import com.github.maracas.gilesi.samples.samplelibrary.A2; +import com.github.gilesi.samples.samplelibrary.A2; public class C1 { public static int Do(int i) { diff --git a/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java new file mode 100644 index 00000000..8867bcc0 --- /dev/null +++ b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java @@ -0,0 +1,9 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.A2; + +public class C2 { + public static int bar(A2 a) { + return a.foo(1); + } +} diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main.java b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java similarity index 75% rename from Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main.java rename to Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java index 5a148ab5..19cfb299 100644 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main.java +++ b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.samples.sampleclient; +package com.github.gilesi.samples.sampleclient; -import com.github.maracas.gilesi.samples.samplelibrary.A; +import com.github.gilesi.samples.samplelibrary.A; public class Main { public static void main(String[] args) { diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java similarity index 96% rename from Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java rename to Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java index 58da04d6..3beeb9eb 100644 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/Main2.java +++ b/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java @@ -1,7 +1,7 @@ -package com.github.maracas.gilesi.samples.sampleclient; +package com.github.gilesi.samples.sampleclient; -import com.github.maracas.gilesi.samples.samplelibrary.Foo; -import com.github.maracas.gilesi.samples.samplelibrary.Foo2; +import com.github.gilesi.samples.samplelibrary.Foo; +import com.github.gilesi.samples.samplelibrary.Foo2; import java.util.ArrayList; import java.util.Arrays; diff --git a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C2.java b/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C2.java deleted file mode 100644 index 2277ded0..00000000 --- a/Samples/sampleclient/src/main/java/com/github/maracas/gilesi/samples/sampleclient/C2.java +++ /dev/null @@ -1,9 +0,0 @@ -package com.github.maracas.gilesi.samples.sampleclient; - -import com.github.maracas.gilesi.samples.samplelibrary.A2; - -public class C2 { - public static int bar(A2 a) { - return a.foo(1); - } -} diff --git a/Samples/sampleclient/src/test/java/CTest.java b/Samples/sampleclient/src/test/java/CTest.java index 9addc7fc..2231b639 100644 --- a/Samples/sampleclient/src/test/java/CTest.java +++ b/Samples/sampleclient/src/test/java/CTest.java @@ -1,5 +1,5 @@ -import com.github.maracas.gilesi.samples.sampleclient.C1; -import com.github.maracas.gilesi.samples.samplelibrary.A2; +import com.github.gilesi.samples.sampleclient.C1; +import com.github.gilesi.samples.samplelibrary.A2; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; @@ -14,7 +14,7 @@ public void Test() { @Test public void ClientATest() { - com.github.maracas.gilesi.samples.samplelibrary.A2 a = new A2(5); + com.github.gilesi.samples.samplelibrary.A2 a = new A2(5); int r = a.foo(1); assertEquals(r, 11); } diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/sampleclient/src/test/java/FooTest.java index a3f52487..e34b122b 100644 --- a/Samples/sampleclient/src/test/java/FooTest.java +++ b/Samples/sampleclient/src/test/java/FooTest.java @@ -1,6 +1,6 @@ -import com.github.maracas.gilesi.samples.samplelibrary.A; -import com.github.maracas.gilesi.samples.samplelibrary.Foo; -import com.github.maracas.gilesi.samples.samplelibrary.Foo2; +import com.github.gilesi.samples.samplelibrary.A; +import com.github.gilesi.samples.samplelibrary.Foo; +import com.github.gilesi.samples.samplelibrary.Foo2; import org.junit.jupiter.api.Test; import java.util.ArrayList; diff --git a/Samples/samplelibrary/build.gradle b/Samples/samplelibrary/build.gradle index 4f6e9b56..64d8e360 100644 --- a/Samples/samplelibrary/build.gradle +++ b/Samples/samplelibrary/build.gradle @@ -2,7 +2,7 @@ plugins { id 'java' } -group = 'com.github.maracas.gilesi.samples.samplelibrary' +group = 'com.github.gilesi.samples.samplelibrary' version = '1.0-SNAPSHOT' repositories { diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java similarity index 84% rename from Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java rename to Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java index 8fbe7311..b9751faa 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A.java +++ b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.samples.samplelibrary; +package com.github.gilesi.samples.samplelibrary; public class A { private final int j; diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java similarity index 82% rename from Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java rename to Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java index 00c497c6..cf025104 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/A2.java +++ b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.samples.samplelibrary; +package com.github.gilesi.samples.samplelibrary; public class A2 { private int i; diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java similarity index 96% rename from Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java rename to Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java index 004ca3af..4109500d 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo.java +++ b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.samples.samplelibrary; +package com.github.gilesi.samples.samplelibrary; import java.util.Arrays; import java.util.Collection; diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java similarity index 96% rename from Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java rename to Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java index 80cc7930..34b98d84 100644 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/Foo2.java +++ b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.samples.samplelibrary; +package com.github.gilesi.samples.samplelibrary; import java.util.Arrays; import java.util.Collection; diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java new file mode 100644 index 00000000..fff02e20 --- /dev/null +++ b/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java @@ -0,0 +1,5 @@ +package com.github.gilesi.samples.samplelibrary; + +public interface IDoSomething { + void Do(); +} diff --git a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java b/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java deleted file mode 100644 index ee407447..00000000 --- a/Samples/samplelibrary/src/main/java/com/github/maracas/gilesi/samples/samplelibrary/IDoSomething.java +++ /dev/null @@ -1,5 +0,0 @@ -package com.github.maracas.gilesi.samples.samplelibrary; - -public interface IDoSomething { - void Do(); -} diff --git a/Samples/samplelibrary/src/test/java/ATest.java b/Samples/samplelibrary/src/test/java/ATest.java index 74ceef94..b86dd475 100644 --- a/Samples/samplelibrary/src/test/java/ATest.java +++ b/Samples/samplelibrary/src/test/java/ATest.java @@ -1,4 +1,4 @@ -import com.github.maracas.gilesi.samples.samplelibrary.A; +import com.github.gilesi.samples.samplelibrary.A; import org.junit.jupiter.api.Test; import static org.junit.jupiter.api.Assertions.assertEquals; diff --git a/Samples/settings.gradle b/Samples/settings.gradle index f5840b90..61edb789 100644 --- a/Samples/settings.gradle +++ b/Samples/settings.gradle @@ -1,2 +1,2 @@ -rootProject.name = 'com.github.maracas.gilesi.samples' +rootProject.name = 'com.github.gilesi.samples' include 'samplelibrary', 'sampleclient' \ No newline at end of file diff --git a/TraceView/build.gradle b/TraceView/build.gradle index 3134e079..baf184e9 100644 --- a/TraceView/build.gradle +++ b/TraceView/build.gradle @@ -3,7 +3,7 @@ plugins { id 'com.github.johnrengelman.shadow' version '8.1.1' } -group 'com.github.maracas.gilesi.traceview' +group 'com.github.gilesi.traceview' version '1.0-SNAPSHOT' @@ -30,19 +30,19 @@ dependencies { jar { manifest { - attributes 'Main-Class': 'com.github.maracas.gilesi.traceview.Main', + attributes 'Main-Class': 'com.github.gilesi.traceview.Main', 'Multi-Release': 'true' } } application { - mainClass = 'com.github.maracas.gilesi.traceview.Main' + mainClass = 'com.github.gilesi.traceview.Main' } description = 'Main distribution.' shadowJar { - archiveBaseName.set('com.github.maracas.gilesi.traceview') + archiveBaseName.set('com.github.gilesi.traceview') archiveClassifier.set('') archiveVersion.set('') mergeServiceFiles() @@ -50,7 +50,7 @@ shadowJar { distributions { shadow { - distributionBaseName = 'com.github.maracas.gilesi.traceview' + distributionBaseName = 'com.github.gilesi.traceview' } } diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java similarity index 95% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java rename to TraceView/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index 41ac5d61..c9c5a707 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/PartialTrace.java +++ b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java similarity index 59% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java rename to TraceView/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java index 7cf11727..e419c06c 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TestTraceResults.java +++ b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class TestTraceResults { public Trace[] Traces; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/Trace.java similarity index 97% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java rename to TraceView/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index ad81bd23..4cc97861 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/Trace.java +++ b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; import java.util.List; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java similarity index 68% rename from TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java rename to TraceView/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index 11779617..7b459ec2 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/instrumentation/models/TraceData.java +++ b/TraceView/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.instrumentation.models; +package com.github.gilesi.instrumentation.models; public class TraceData { public String fullyQualifiedTypeName; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java b/TraceView/src/main/java/com/github/gilesi/traceview/Main.java similarity index 96% rename from TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java rename to TraceView/src/main/java/com/github/gilesi/traceview/Main.java index 60c174dd..401fa6a1 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/Main.java +++ b/TraceView/src/main/java/com/github/gilesi/traceview/Main.java @@ -1,7 +1,7 @@ -package com.github.maracas.gilesi.traceview; +package com.github.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.models.TestTraceResults; -import com.github.maracas.gilesi.instrumentation.models.Trace; +import com.github.gilesi.instrumentation.models.TestTraceResults; +import com.github.gilesi.instrumentation.models.Trace; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java b/TraceView/src/main/java/com/github/gilesi/traceview/SerializationUtils.java similarity index 96% rename from TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java rename to TraceView/src/main/java/com/github/gilesi/traceview/SerializationUtils.java index 2c2f903b..356af5ae 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/SerializationUtils.java +++ b/TraceView/src/main/java/com/github/gilesi/traceview/SerializationUtils.java @@ -1,6 +1,6 @@ -package com.github.maracas.gilesi.traceview; +package com.github.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.TraceData; import org.apache.commons.text.StringEscapeUtils; public class SerializationUtils { diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java b/TraceView/src/main/java/com/github/gilesi/traceview/TestMethodGenerator.java similarity index 97% rename from TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java rename to TraceView/src/main/java/com/github/gilesi/traceview/TestMethodGenerator.java index e4909ce6..06e4483f 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/TestMethodGenerator.java +++ b/TraceView/src/main/java/com/github/gilesi/traceview/TestMethodGenerator.java @@ -1,7 +1,7 @@ -package com.github.maracas.gilesi.traceview; +package com.github.gilesi.traceview; -import com.github.maracas.gilesi.instrumentation.models.Trace; -import com.github.maracas.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.instrumentation.models.TraceData; import java.util.ArrayList; import java.util.List; diff --git a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java b/TraceView/src/main/java/com/github/gilesi/traceview/VariableStackHandler.java similarity index 96% rename from TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java rename to TraceView/src/main/java/com/github/gilesi/traceview/VariableStackHandler.java index f089fd91..db357fe0 100644 --- a/TraceView/src/main/java/com/github/maracas/gilesi/traceview/VariableStackHandler.java +++ b/TraceView/src/main/java/com/github/gilesi/traceview/VariableStackHandler.java @@ -1,4 +1,4 @@ -package com.github.maracas.gilesi.traceview; +package com.github.gilesi.traceview; import java.util.HashMap; diff --git a/maracas-test.cmd b/maracas-test.cmd index cb7bac1c..dec43142 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -13,7 +13,7 @@ echo Running ConfGen echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" +%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" echo. echo =========================================================== @@ -32,7 +32,7 @@ echo Running TraceView echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TraceView\build\libs\com.github.gilesi.traceview.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" mkdir Results diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 0939d81c..1089b601 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -24,7 +24,7 @@ echo Running ConfGen echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.maracas.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" echo. @@ -44,7 +44,7 @@ echo Running TraceView echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TraceView\build\libs\com.github.maracas.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TraceView\build\libs\com.github.gilesi.traceview.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" mkdir Results diff --git a/test.cmd b/test.cmd index 20dfe283..49a9e608 100644 --- a/test.cmd +++ b/test.cmd @@ -1 +1 @@ -%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.maracas.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.xml" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.maracas.gilesi.samples.sampleclient.Main2 \ No newline at end of file +%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.xml" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.gilesi.samples.sampleclient.Main2 \ No newline at end of file From 6bb23ade2189d310d19145af70d6581318268d8e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 22 Apr 2024 09:32:39 +0200 Subject: [PATCH 088/244] Remove further hardcoded paths --- maracas-test.cmd | 3 ++- test.cmd | 2 +- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/maracas-test.cmd b/maracas-test.cmd index dec43142..a1afbf51 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -21,9 +21,10 @@ echo Running Maracas Forges' Test Suite with Agent echo =========================================================== echo. +set CURRENT_DIR=%CD% cd C:\Users\Gus\Documents\GitHub\maracas\forges call "%MAVEN_HOME%\bin\mvn" surefire:test -cd C:\Users\Gus\Documents\GitHub\gilesi +cd %CURRENT_DIR% echo. diff --git a/test.cmd b/test.cmd index 49a9e608..ba81285a 100644 --- a/test.cmd +++ b/test.cmd @@ -1 +1 @@ -%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:C:\Users\Gus\Documents\GitHub\gilesi\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar="C:\Users\Gus\Documents\GitHub\gilesi\TestWorkflowConfiguration.xml" -cp C:\Users\Gus\Documents\GitHub\gilesi\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;C:\Users\Gus\Documents\GitHub\gilesi\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.gilesi.samples.sampleclient.Main2 \ No newline at end of file +%JAVA_HOME%\bin\java.exe -Dnet.bytebuddy.experimental=true -XX:+EnableDynamicAgentLoading -javaagent:%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar="%CD%\TestWorkflowConfiguration.xml" -cp %CD%\Samples\sampleclient\build\libs\sampleclient-1.0-SNAPSHOT.jar;%CD%\Samples\samplelibrary\build\libs\samplelibrary-1.0-SNAPSHOT.jar com.github.gilesi.samples.sampleclient.Main2 \ No newline at end of file From b21b6564051eca65764860f81f17a5d2991b7c05 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 22 Apr 2024 09:57:38 +0200 Subject: [PATCH 089/244] Add sh scripts --- Samples/sampleclient/build.gradle | 2 +- compile.sh | 35 +++++++++++++++++++ maracas-test.sh | 40 ++++++++++++++++++++++ run-clean-workflow.sh | 20 +++++++++++ run-test-workflow.cmd | 8 +++-- run-test-workflow.sh | 57 +++++++++++++++++++++++++++++++ 6 files changed, 159 insertions(+), 3 deletions(-) create mode 100644 compile.sh create mode 100644 maracas-test.sh create mode 100644 run-clean-workflow.sh create mode 100644 run-test-workflow.sh diff --git a/Samples/sampleclient/build.gradle b/Samples/sampleclient/build.gradle index 96606acc..aa5a7883 100644 --- a/Samples/sampleclient/build.gradle +++ b/Samples/sampleclient/build.gradle @@ -23,7 +23,7 @@ testing { all { testTask.configure { systemProperty 'net.bytebuddy.experimental', 'true' - jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\Instrumentation\\build\\libs\\com.github.gilesi.instrumentation.jar="C:\\Users\\Gus\\Documents\\GitHub\\gilesi\\TestWorkflowConfiguration.xml"'] + jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml'] } } } diff --git a/compile.sh b/compile.sh new file mode 100644 index 00000000..590a9a5f --- /dev/null +++ b/compile.sh @@ -0,0 +1,35 @@ +#!/bin/bash + +echo +echo =========================================================== +echo Building ConfGen +echo =========================================================== +echo + +# build confgen +cd ConfGen +sh ./gradlew shadowJar --warning-mode all +cd .. + + +echo +echo =========================================================== +echo Building TraceView +echo =========================================================== +echo + +# build traceview +cd TraceView +sh ./gradlew shadowJar --warning-mode all +cd .. + +echo +echo =========================================================== +echo Building Agent +echo =========================================================== +echo + +# build tool +cd Instrumentation +sh ./gradlew shadowJar --warning-mode all +cd .. \ No newline at end of file diff --git a/maracas-test.sh b/maracas-test.sh new file mode 100644 index 00000000..4b1f717b --- /dev/null +++ b/maracas-test.sh @@ -0,0 +1,40 @@ +#!/bin/bash + +sh run-clean-workflow.sh +sh compile.sh + + +echo +echo =========================================================== +echo Running ConfGen +echo =========================================================== +echo + +$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.xml" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" + +echo +echo =========================================================== +echo $'Running Maracas Forges\' Test Suite with Agent' +echo =========================================================== +echo + +CURRENT_DIR=$PWD +cd /mnt/c/Users/Gus/Documents/GitHub/maracas/forges +sh "$MAVEN_HOME/bin/mvn" surefire:test +cd $CURRENT_DIR + + +echo +echo =========================================================== +echo Running TraceView +echo =========================================================== +echo + +$JAVA_HOME/bin/java -jar "$PWD/TraceView/build/libs/com.github.gilesi.traceview.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" + +mkdir Results + +mv $PWD/MaracasConfiguration.xml Results/ +mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/gilesi.instrumentation.log Results/ +mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml Results/ +mv $PWD/TraceView.Output Results/ \ No newline at end of file diff --git a/run-clean-workflow.sh b/run-clean-workflow.sh new file mode 100644 index 00000000..91ca247e --- /dev/null +++ b/run-clean-workflow.sh @@ -0,0 +1,20 @@ +#!/bin/bash + +cd Samples +rm -rf ./sampleclient/build +rm -rf ./samplelibrary/build +cd .. + +cd ConfGen +rm -rf ./build +cd .. + +cd TraceView +rm -rf ./build +cd .. + +cd Instrumentation +rm -rf ./build +cd .. + +rm -rf ./Results \ No newline at end of file diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 1089b601..d18bb86f 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -33,10 +33,15 @@ echo Running Sample's Client Test Suite with Agent echo =========================================================== echo. +copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\sampleclient\" +copy "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\sampleclient\" + cd Samples call .\gradlew.bat sampleclient:test --warning-mode all cd .. +del "%CD%\Samples\sampleclient\com.github.gilesi.instrumentation.jar" +del "%CD%\Samples\sampleclient\TestWorkflowConfiguration.xml" echo. echo =========================================================== @@ -51,5 +56,4 @@ mkdir Results move %CD%\TestWorkflowConfiguration.xnl Results\ move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ move %CD%\Samples\sampleclient\MethodTraces.xml Results\ -move %CD%\TraceView.Output Results\ -move %CD%\TestWorkflowConfiguration.xml Results\ \ No newline at end of file +move %CD%\TraceView.Output Results\ \ No newline at end of file diff --git a/run-test-workflow.sh b/run-test-workflow.sh new file mode 100644 index 00000000..dd54ba59 --- /dev/null +++ b/run-test-workflow.sh @@ -0,0 +1,57 @@ +#!/bin/bash + +sh ./run-clean-workflow.sh +sh ./compile.sh + + +echo +echo =========================================================== +echo Building Samples +echo =========================================================== +echo + +# build samples +cd Samples +sh ./gradlew jar --warning-mode all +cd .. + + +echo +echo =========================================================== +echo Running ConfGen +echo =========================================================== +echo + +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Samples/samplelibrary" "$PWD/Samples/sampleclient" + + +echo +echo =========================================================== +echo $'Running Sample\'s Client Test Suite with Agent' +echo =========================================================== +echo + +cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/sampleclient/ +cp $PWD/TestWorkflowConfiguration.xml $PWD/Samples/sampleclient/ + +cd Samples +sh ./gradlew sampleclient:test --warning-mode all +cd .. + +rm $PWD/Samples/sampleclient/com.github.gilesi.instrumentation.jar +rm $PWD/Samples/sampleclient/TestWorkflowConfiguration.xml + +echo +echo =========================================================== +echo Running TraceView +echo =========================================================== +echo + +"$JAVA_HOME/bin/java" -jar "$PWD/TraceView/build/libs/com.github.gilesi.traceview.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" + +mkdir Results + +mv $PWD/TestWorkflowConfiguration.xnl Results/ +mv $PWD/Samples/sampleclient/gilesi.instrumentation.log Results/ +mv $PWD/Samples/sampleclient/MethodTraces.xml Results/ +mv $PWD/TraceView.Output Results/ \ No newline at end of file From 240f89a71e238f8377f60265b8377d244e137402 Mon Sep 17 00:00:00 2001 From: Thomas Degueule Date: Mon, 22 Apr 2024 10:56:18 +0200 Subject: [PATCH 090/244] Fixed typo in run-test-workflow.* --- ConfGen/build.gradle | 4 ++-- run-test-workflow.cmd | 4 ++-- run-test-workflow.sh | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index e4317259..ab67fe03 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -17,7 +17,7 @@ tasks.withType(JavaCompile) { repositories { mavenCentral() - mavenLocal() + //mavenLocal() maven { name = "IntelliJ" url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' @@ -81,4 +81,4 @@ run { "-XX:InitialHeapSize=2G", "-XX:MaxHeapSize=2G" ] -} \ No newline at end of file +} diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index d18bb86f..76e26e4a 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -53,7 +53,7 @@ echo. mkdir Results -move %CD%\TestWorkflowConfiguration.xnl Results\ +move %CD%\TestWorkflowConfiguration.xml Results\ move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ move %CD%\Samples\sampleclient\MethodTraces.xml Results\ -move %CD%\TraceView.Output Results\ \ No newline at end of file +move %CD%\TraceView.Output Results\ diff --git a/run-test-workflow.sh b/run-test-workflow.sh index dd54ba59..cd253e67 100644 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -51,7 +51,7 @@ echo mkdir Results -mv $PWD/TestWorkflowConfiguration.xnl Results/ +mv $PWD/TestWorkflowConfiguration.xml Results/ mv $PWD/Samples/sampleclient/gilesi.instrumentation.log Results/ mv $PWD/Samples/sampleclient/MethodTraces.xml Results/ -mv $PWD/TraceView.Output Results/ \ No newline at end of file +mv $PWD/TraceView.Output Results/ From f111886268fb0ed41b8b35b5d1d35c4f2a3bcddd Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 24 Apr 2024 09:46:32 +0200 Subject: [PATCH 091/244] Improvements for the instrumentation tool --- .idea/jarRepositories.xml | 5 + .../instrumentation/TraceCollector.java | 22 +- Samples/sampleclient/CTest.ClientATest.xml | 92 +++ Samples/sampleclient/CTest.Test.xml | 89 ++ Samples/sampleclient/FooTest.TestFoo.xml | 67 ++ .../FooTest.TestFooIsLifeNice.xml | 170 ++++ Samples/sampleclient/FooTest.mainTest.xml | 778 ++++++++++++++++++ Samples/sampleclient/src/test/java/CTest.java | 1 + .../gilesi/traceview/SerializationUtils.java | 18 +- run-test-workflow.sh | 0 10 files changed, 1237 insertions(+), 5 deletions(-) create mode 100644 Samples/sampleclient/CTest.ClientATest.xml create mode 100644 Samples/sampleclient/CTest.Test.xml create mode 100644 Samples/sampleclient/FooTest.TestFoo.xml create mode 100644 Samples/sampleclient/FooTest.TestFooIsLifeNice.xml create mode 100644 Samples/sampleclient/FooTest.mainTest.xml mode change 100644 => 100755 run-test-workflow.sh diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index cf47410e..570ea2b5 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -31,5 +31,10 @@

- * This method is public so it can be accessed as part of the modified instrumented classes + * This method is public, so it can be accessed as part of the modified instrumented classes * without security problems at the JVM level * * @param origin The originating trace Executable object @@ -87,7 +87,7 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg *

* Callers must call later getMethodTraces to retrieve the trace information. *

- * This method is public so it can be accessed as part of the modified instrumented classes + * This method is public, so it can be accessed as part of the modified instrumented classes * without security problems at the JVM level * * @param origin The originating trace Executable object diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java index 7647c18d..8a152b97 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -38,7 +38,10 @@ private static ElementMatcher.Junction getMethodElementMatche descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); } } - methodMatcher = methodMatcher.and(descriptorMatcher); + + if (descriptorMatcher != null) { + methodMatcher = methodMatcher.and(descriptorMatcher); + } if (classMatcher == null) { classMatcher = methodMatcher; diff --git a/Samples/sampleclient/build.gradle b/Samples/sampleclient/build.gradle index aa5a7883..78a063e1 100644 --- a/Samples/sampleclient/build.gradle +++ b/Samples/sampleclient/build.gradle @@ -11,7 +11,7 @@ repositories { dependencies { implementation project(':samplelibrary') - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.1' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' } testing { diff --git a/Samples/samplelibrary/build.gradle b/Samples/samplelibrary/build.gradle index 64d8e360..34871021 100644 --- a/Samples/samplelibrary/build.gradle +++ b/Samples/samplelibrary/build.gradle @@ -11,8 +11,8 @@ repositories { dependencies { implementation 'com.fasterxml:jackson-xml-databind:0.6.2' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.15.1' - testImplementation platform('org.junit:junit-bom:5.9.1') + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' + testImplementation platform('org.junit:junit-bom:5.11.0-M1') testImplementation 'org.junit.jupiter:junit-jupiter' } diff --git a/TestGenerator/build.gradle b/TestGenerator/build.gradle index 1fa8bdf4..9f3a9c5a 100644 --- a/TestGenerator/build.gradle +++ b/TestGenerator/build.gradle @@ -11,7 +11,7 @@ compileJava { options.encoding = 'UTF-8' } -tasks.withType(JavaCompile) { +tasks.withType(JavaCompile).configureEach { options.encoding = 'UTF-8' } @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'org.apache.commons:commons-text:1.10.0' + implementation 'org.apache.commons:commons-text:1.11.0' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 92604644..f86cb144 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -2,6 +2,8 @@ import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; +import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; @@ -10,23 +12,21 @@ import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; -import java.util.Arrays; -import java.util.HashMap; -import java.util.Map; -import java.util.Set; - -import java.util.ArrayList; +import java.util.*; public class Main { private static TestTraceResults[] readTraces(String filePathStr) throws IOException { XStream xstream = new XStream(new DomDriver()); xstream.addPermission(AnyTypePermission.ANY); - String xmlContent = new String(Files.readAllBytes(Path.of(filePathStr)), StandardCharsets.UTF_8); + String xmlContent = Files.readString(Path.of(filePathStr)); return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new); } - public static void main(String[] args) throws Exception { - TestTraceResults[] testTraceResultsList = readTraces(args[0]); + public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException { + String traceXml = args[0]; + String testPath = args[1]; + + TestTraceResults[] testTraceResultsList = readTraces(traceXml); Map>> packageTraceResults = new HashMap<>(); @@ -50,7 +50,7 @@ public static void main(String[] args) throws Exception { } } - Path mainOutputPath = Path.of("TestGenerator.Output").toAbsolutePath(); + Path mainOutputPath = Path.of(testPath).toAbsolutePath(); if (!Files.isDirectory(mainOutputPath)) { Files.createDirectories(mainOutputPath); } @@ -94,7 +94,7 @@ public static void main(String[] args) throws Exception { stringBuilder.append("public class %s {\n".formatted(className)); - Map.Entry[] testTracesForClass = classTraces.getValue().entrySet().toArray(Map.Entry[]::new); + Map.Entry[] testTracesForClass = classTraces.getValue().entrySet().toArray(Map.Entry[]::new); for (int j = 0; j < testTracesForClass.length; j++) { Map.Entry testTraces = testTracesForClass[j]; @@ -124,11 +124,14 @@ public static void main(String[] args) throws Exception { } } - stringBuilder.append("\n\tpublic static String getToXml(Object obj) {\n" + - "\t\tDomDriver domDriver = new DomDriver();\n" + - "\t\tXStream xStream = new XStream(domDriver);\n" + - "\t\treturn xStream.toXML(obj);\n" + - "\t}\n"); + stringBuilder.append(""" + + \tpublic static String getToXml(Object obj) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\treturn xStream.toXML(obj); + \t} + """); stringBuilder.append("}\n"); stringBuilder.append("\n"); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index e675af51..e6b734cd 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -1,10 +1,11 @@ package com.github.gilesi.testgenerator; import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import org.apache.commons.text.StringEscapeUtils; public class SerializationUtils { - private static String JvmTypeToLangType(String name) throws Exception { + private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { return switch (name.charAt(0)) { case 'I' -> "java.lang.Integer"; case 'V' -> "java.lang.Void"; @@ -17,7 +18,7 @@ private static String JvmTypeToLangType(String name) throws Exception { case 'J' -> "java.lang.Long"; case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new Exception("Unsupported primitive type: %s".formatted(name)); + default -> throw new UnsupportedJavaPrimitiveTypeException(name); }; } @@ -36,7 +37,7 @@ public static String getCleanedType(String FQN) { (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN); - } catch (Exception ignored) { + } catch (UnsupportedJavaPrimitiveTypeException ignored) { } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index 14455181..e2b163de 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -2,6 +2,9 @@ import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; +import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; +import com.github.gilesi.testgenerator.exceptions.SerializationException; import org.apache.commons.text.StringEscapeUtils; import java.util.ArrayList; @@ -30,8 +33,7 @@ private static String serializableDataToCode2(TraceData arg, VariableStackHandle if (arg.dataAsXml.equals("null")) { return arg.dataAsXml; } - String dataLine = SerializationUtils.serializableDataToJava(arg); - return dataLine; + return SerializationUtils.serializableDataToJava(arg); } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { return variableStackHandler.getInstanceVariableName(arg.instanceId); } else { @@ -85,7 +87,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler // TODO: We could return null as well! If we do, then we got a type, just set to null, how do we check that even..? // Value returned is of course, the instance! - String argumentVariable = ""; + String argumentVariable; try { argumentVariable = getDataVariableDeclaration(traceData, variableStackHandler); @@ -105,7 +107,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler TraceData returnedValue = methodTrace.getReturnedValue(); if (returnedValue != null) { // We return a value that we managed to serialize - String argumentVariable = ""; + String argumentVariable; try { argumentVariable = getDataVariableDeclaration(returnedValue, variableStackHandler); @@ -119,7 +121,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler } if (commentItAll) { - methodCall = "/* " + methodCall + " */"; + methodCall = "/* %s */".formatted(methodCall); } return methodCall; @@ -134,7 +136,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab boolean commentItAll = false; for (TraceData preCallArgument : methodTrace.getPreCallArguments()) { - String argumentValue = ""; + String argumentValue; try { argumentValue = serializableDataToCode(preCallArgument, variableStackHandler); } @@ -143,7 +145,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab commentItAll = true; } - String argumentVariable = ""; + String argumentVariable; try { argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler); } @@ -206,12 +208,11 @@ private static String getAssertionCodeLine2(TraceData traceData, VariableStackHa } String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - String assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); - return assertionLine; + return "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); } else if (variableStackHandler.isInstanceVariableNameDefined(instanceId)) { return "// assertEquals(%s, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId), variableStackHandler.getInstanceVariableName(instanceId)); } else { - return "// Unserializable data with instance id: " + traceData.instanceId; + return "// Unserializable data with instance id: %d".formatted(traceData.instanceId); } } @@ -225,12 +226,12 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan } // We return a value that we managed to serialize - String assertionCodeLine = ""; + String assertionCodeLine; try { assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler); } catch (SerializationException e) { - assertionCodeLine = "// " + getAssertionCodeLine2(traceData, variableStackHandler); + assertionCodeLine = "// %s".formatted(getAssertionCodeLine2(traceData, variableStackHandler)); } argList.add(assertionCodeLine); } @@ -245,15 +246,13 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari TraceData traceData = methodTrace.getReturnedValue(); - if (isConstructor) { - // Nothing to do! - } else if (traceData != null) { - String assertionCodeLine = ""; + if (!isConstructor && traceData != null) { + String assertionCodeLine; try { assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler); } catch (SerializationException e) { - assertionCodeLine = "// " + getAssertionCodeLine2(traceData, variableStackHandler); + assertionCodeLine = "// %s".formatted(getAssertionCodeLine2(traceData, variableStackHandler)); } return assertionCodeLine; } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java index ac51457c..1ee2b1b6 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java @@ -1,5 +1,8 @@ package com.github.gilesi.testgenerator; +import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; +import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; + import java.util.HashMap; public class VariableStackHandler { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceAlreadyDefinedException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java similarity index 79% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceAlreadyDefinedException.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java index 66f8c41a..bad23d0e 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceAlreadyDefinedException.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.exceptions; public class InstanceAlreadyDefinedException extends Exception { public InstanceAlreadyDefinedException(Integer instanceId) { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceNotDefinedException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java similarity index 79% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceNotDefinedException.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java index 95aeca45..71f8e677 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/InstanceNotDefinedException.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.exceptions; public class InstanceNotDefinedException extends Exception { public InstanceNotDefinedException(Integer instanceId) { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java similarity index 73% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationException.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java index 27e72221..e502a6b1 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationException.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.exceptions; public class SerializationException extends Exception { public SerializationException(String message) { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java new file mode 100644 index 00000000..47ae435c --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java @@ -0,0 +1,7 @@ +package com.github.gilesi.testgenerator.exceptions; + +public class UnsupportedJavaPrimitiveTypeException extends Exception { + public UnsupportedJavaPrimitiveTypeException(String primitive) { + super("Unsupported primitive type: %s".formatted(primitive)); + } +} diff --git a/maracas-test.cmd b/maracas-test.cmd index 0c4feb04..d8306d53 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -33,7 +33,7 @@ echo Running TestGenerator echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" "C:\Users\Gus\Documents\GitHub\maracas\forges\TestGenerator.Output" mkdir Results diff --git a/maracas-test.sh b/maracas-test.sh index 1fee6ec2..80c9f926 100644 --- a/maracas-test.sh +++ b/maracas-test.sh @@ -30,7 +30,7 @@ echo Running TestGenerator echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" +$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/TestGenerator.Output" mkdir Results diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index f1240ab9..4c2ee07a 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -49,7 +49,7 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" "%CD%\Samples\sampleclient\TestGenerator.Output" mkdir Results diff --git a/run-test-workflow.sh b/run-test-workflow.sh index 80d87f85..c63ac0a6 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -47,7 +47,7 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" "$PWD/Samples/sampleclient/TestGenerator.Output" mkdir Results From 0f5bf31289bfe289ffce760a15665462b9b79384 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 13 May 2024 11:03:37 +0200 Subject: [PATCH 096/244] Fix mistake in test scripts --- maracas-test.cmd | 4 ++-- maracas-test.sh | 4 ++-- run-test-workflow.cmd | 2 +- run-test-workflow.sh | 2 +- 4 files changed, 6 insertions(+), 6 deletions(-) diff --git a/maracas-test.cmd b/maracas-test.cmd index d8306d53..59bd1470 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -33,7 +33,7 @@ echo Running TestGenerator echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" "C:\Users\Gus\Documents\GitHub\maracas\forges\TestGenerator.Output" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" "%CD%\TestGenerator.Output" mkdir Results @@ -41,4 +41,4 @@ move %CD%\MaracasConfiguration.xml Results\ move C:\Users\Gus\Documents\GitHub\maracas\forges\gilesi.instrumentation.log Results\ move C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml Results\ move C:\Users\Gus\Documents\GitHub\maracas\forges\*.xml Results\ -move %CD%\TestGenerator.Output Results\ \ No newline at end of file +move %CD%\TestGenerator.Output Results\ diff --git a/maracas-test.sh b/maracas-test.sh index 80c9f926..067948c3 100644 --- a/maracas-test.sh +++ b/maracas-test.sh @@ -30,7 +30,7 @@ echo Running TestGenerator echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/TestGenerator.Output" +$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" "$PWD/TestGenerator.Output" mkdir Results @@ -38,4 +38,4 @@ mv $PWD/MaracasConfiguration.xml Results/ mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/gilesi.instrumentation.log Results/ mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml Results/ mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/*.xml Results/ -mv $PWD/TestGenerator.Output Results/ \ No newline at end of file +mv $PWD/TestGenerator.Output Results/ diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 4c2ee07a..417d8739 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -49,7 +49,7 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" "%CD%\Samples\sampleclient\TestGenerator.Output" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" "%CD%\TestGenerator.Output" mkdir Results diff --git a/run-test-workflow.sh b/run-test-workflow.sh index c63ac0a6..a2e5befb 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -47,7 +47,7 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" "$PWD/Samples/sampleclient/TestGenerator.Output" +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" "$PWD/TestGenerator.Output" mkdir Results From 317502194b8b0b3994ba729b6e8221583f892f1d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 13 May 2024 13:11:04 +0200 Subject: [PATCH 097/244] Allow specifying the output location for the instrumentation tool --- .../java/com/github/gilesi/confgen/Main.java | 9 +++++-- .../models/InstrumentationParameters.java | 1 + .../github/gilesi/instrumentation/Agent.java | 19 ++++++++++++++ .../github/gilesi/instrumentation/Logger.java | 11 +++----- .../instrumentation/TraceCollector.java | 25 ++++++++++--------- .../models/InstrumentationParameters.java | 1 + maracas-test.cmd | 10 ++++---- maracas-test.sh | 10 ++++---- run-test-workflow.cmd | 10 ++++---- run-test-workflow.sh | 10 ++++---- 10 files changed, 65 insertions(+), 41 deletions(-) diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index c9b311d7..b7ccb817 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -119,12 +119,16 @@ private static void addToInstrumentationObject(InstrumentationParameters instrum public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeException, IOException { String apiReportOutputLocation = args[0]; + String traceOutputLocation = args[1]; + String libraryProjectLocation = args[2]; + String clientProjectLocation = args[3]; + Path apiReportOutputPath = Path.of(apiReportOutputLocation); System.out.println("Processing Library Project..."); Launcher libraryLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); - SpoonLauncherUtilities.applyProjectToLauncher(libraryLauncher, Path.of(args[1]), EnumSet.of(CodeType.MAIN)); + SpoonLauncherUtilities.applyProjectToLauncher(libraryLauncher, Path.of(libraryProjectLocation), EnumSet.of(CodeType.MAIN)); CtModel libraryModel = libraryLauncher.buildModel(); // API model for libraries @@ -134,6 +138,7 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); + instrumentationParameters.traceOutputLocation = traceOutputLocation; for (ClassDecl classDecl : libraryApiModel.getExportedTypes() .filter(ClassDecl.class::isInstance) @@ -165,7 +170,7 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept System.out.println("Processing Test Project..."); Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); - SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(args[2]), CodeType.ALL); + SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(clientProjectLocation), CodeType.ALL); CtModel clientModel = clientLauncher.buildModel(); System.out.println("Processing Client Project..."); diff --git a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java index 6fd63595..9c22e685 100644 --- a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java @@ -6,4 +6,5 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; public List LibraryMethods; public List ClientMethods; + public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 175216a7..ffbea03e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -11,6 +11,8 @@ import java.lang.instrument.Instrumentation; import java.nio.charset.StandardCharsets; import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; /* Our main agent class @@ -55,6 +57,23 @@ private static void installAgent(String arg, Instrumentation inst) { return; } + if (!Files.isDirectory(Paths.get(instrumentationParameters.traceOutputLocation))) { + try { + Files.createDirectory(Paths.get(instrumentationParameters.traceOutputLocation)); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create trace output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + // Add a shutdown hook to save all logs at exit + Runtime.getRuntime().addShutdownHook(new Thread(() -> Logger.SaveLogResults(instrumentationParameters))); + + // Add a shutdown hook to save all method execution traces at exit + Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(instrumentationParameters))); + CommonAdvisor.LibraryMethods = instrumentationParameters.LibraryMethods; CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index f24e51d6..39c6da12 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -1,5 +1,7 @@ package com.github.gilesi.instrumentation; +import com.github.gilesi.instrumentation.models.InstrumentationParameters; + import java.io.File; import java.nio.file.Files; import java.util.ArrayList; @@ -8,14 +10,9 @@ public class Logger { private static final ArrayList LOGGER = new ArrayList<>(); private static int LOGGERINSTANCE = 0; - static { - // Add a shutdown hook to save all logs at exit - Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); - } - - public static void SaveLogResults() { + public static void SaveLogResults(InstrumentationParameters instrumentationParameters) { try { - Files.write(new File("gilesi.instrumentation.log").toPath(), LOGGER); + Files.write(new File(instrumentationParameters.traceOutputLocation + File.separatorChar + "gilesi.instrumentation.log").toPath(), LOGGER); } catch (Exception e) { System.err.println("ERROR while saving logs"); e.printStackTrace(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index 1d56f718..b9ee8ee8 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -1,8 +1,10 @@ package com.github.gilesi.instrumentation; +import com.github.gilesi.instrumentation.models.InstrumentationParameters; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; +import java.io.File; import java.io.FileWriter; import java.nio.file.Path; import java.nio.file.Paths; @@ -13,11 +15,6 @@ public class TraceCollector { // Storage for traces collected so far private static final ArrayList TRACES = new ArrayList<>(); - static { - // Add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(TraceCollector::SaveTraceResults)); - } - public static void addMethodTrace(String currentTestMethod, Trace trace) { for (TestTraceResults testTraceResults : TRACES) { if (testTraceResults.Test.equals(currentTestMethod)) { @@ -46,15 +43,19 @@ public static Collection getMethodTraces() { /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults() { + public static void SaveTraceResults(InstrumentationParameters instrumentationParameters) { System.out.println("Saving trace results in progress..."); - System.out.printf("Output location: %s%n", Paths.get("MethodTraces.xml").toAbsolutePath()); + + String tracesFileName = instrumentationParameters.traceOutputLocation + File.separatorChar + "MethodTraces.xml"; + Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); + + System.out.printf("Output location: %s%n", tracesPath); Collection results = TraceCollector.getMethodTraces(); try { String xmlOutputString = XmlUtils.getToXml(results); - FileWriter outputFile = new FileWriter("MethodTraces.xml"); + FileWriter outputFile = new FileWriter(tracesFileName); outputFile.write(xmlOutputString); outputFile.close(); } catch (Exception e) { @@ -63,14 +64,14 @@ public static void SaveTraceResults() { } for (TestTraceResults testTraceResults : results) { - String tracesFileName = testTraceResults.Test + ".xml"; - Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); + String traceFileName = instrumentationParameters.traceOutputLocation + File.separatorChar + testTraceResults.Test + ".xml"; + Path tracePath = Paths.get(traceFileName).toAbsolutePath(); - System.out.printf("Test Output location: %s%n", tracesPath); + System.out.printf("Test Output location: %s%n", tracePath); try { String xmlOutputString = XmlUtils.getToXml(testTraceResults.Traces); - FileWriter outputFile = new FileWriter(tracesFileName); + FileWriter outputFile = new FileWriter(traceFileName); outputFile.write(xmlOutputString); outputFile.close(); } catch (Exception e) { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java index 1dc63771..d508c849 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java @@ -4,4 +4,5 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; public String[] LibraryMethods; public String[] ClientMethods; + public String traceOutputLocation; } diff --git a/maracas-test.cmd b/maracas-test.cmd index 59bd1470..ef258560 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -13,7 +13,7 @@ echo Running ConfGen echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" +%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "%CD%\Traces.Output" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" echo. echo =========================================================== @@ -33,12 +33,12 @@ echo Running TestGenerator echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml" "%CD%\TestGenerator.Output" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.xml" "%CD%\TestGenerator.Output" mkdir Results move %CD%\MaracasConfiguration.xml Results\ -move C:\Users\Gus\Documents\GitHub\maracas\forges\gilesi.instrumentation.log Results\ -move C:\Users\Gus\Documents\GitHub\maracas\forges\MethodTraces.xml Results\ -move C:\Users\Gus\Documents\GitHub\maracas\forges\*.xml Results\ +move %CD%\Traces.Output\gilesi.instrumentation.log Results\ +move %CD%\Traces.Output\MethodTraces.xml Results\ +move %CD%\Traces.Output\*.xml Results\ move %CD%\TestGenerator.Output Results\ diff --git a/maracas-test.sh b/maracas-test.sh index 067948c3..fb033178 100644 --- a/maracas-test.sh +++ b/maracas-test.sh @@ -10,7 +10,7 @@ echo Running ConfGen echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.xml" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" +$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.xml" "$PWD/Traces.Output" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" echo echo =========================================================== @@ -30,12 +30,12 @@ echo Running TestGenerator echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml" "$PWD/TestGenerator.Output" +$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.xml" "$PWD/TestGenerator.Output" mkdir Results mv $PWD/MaracasConfiguration.xml Results/ -mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/gilesi.instrumentation.log Results/ -mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/MethodTraces.xml Results/ -mv /mnt/c/Users/Gus/Documents/GitHub/maracas/forges/*.xml Results/ +mv $PWD/Traces.Output/gilesi.instrumentation.log Results/ +mv $PWD/Traces.Output/MethodTraces.xml Results/ +mv $PWD/Traces.Output/*.xml Results/ mv $PWD/TestGenerator.Output Results/ diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 417d8739..19e08858 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -24,7 +24,7 @@ echo Running ConfGen echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Traces.Output" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" echo. @@ -49,12 +49,12 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Samples\sampleclient\MethodTraces.xml" "%CD%\TestGenerator.Output" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.xml" "%CD%\TestGenerator.Output" mkdir Results move %CD%\TestWorkflowConfiguration.xml Results\ -move %CD%\Samples\sampleclient\gilesi.instrumentation.log Results\ -move %CD%\Samples\sampleclient\MethodTraces.xml Results\ -move %CD%\Samples\sampleclient\*.xml Results\ +move %CD%\Traces.Output\gilesi.instrumentation.log Results\ +move %CD%\Traces.Output\MethodTraces.xml Results\ +move %CD%\Traces.Output\*.xml Results\ move %CD%\TestGenerator.Output Results\ diff --git a/run-test-workflow.sh b/run-test-workflow.sh index a2e5befb..336eb8e0 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -22,7 +22,7 @@ echo Running ConfGen echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Samples/samplelibrary" "$PWD/Samples/sampleclient" +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Traces.Output" "$PWD/Samples/samplelibrary" "$PWD/Samples/sampleclient" echo @@ -47,12 +47,12 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Samples/sampleclient/MethodTraces.xml" "$PWD/TestGenerator.Output" +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.xml" "$PWD/TestGenerator.Output" mkdir Results mv $PWD/TestWorkflowConfiguration.xml Results/ -mv $PWD/Samples/sampleclient/gilesi.instrumentation.log Results/ -mv $PWD/Samples/sampleclient/MethodTraces.xml Results/ -mv $PWD/Samples/sampleclient/*.xml Results/ +mv $PWD/Traces.Output/gilesi.instrumentation.log Results/ +mv $PWD/Traces.Output/MethodTraces.xml Results/ +mv $PWD/Traces.Output/*.xml Results/ mv $PWD/TestGenerator.Output Results/ From bc10d6131395f86d583c98429b813a2ecef918a9 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 14 May 2024 13:42:11 +0200 Subject: [PATCH 098/244] Improvements + Collect J(a)son(s) a well --- .idea/compiler.xml | 9 +++++++++ .../java/com/github/gilesi/confgen/Main.java | 6 +++--- .../models/Class.java | 2 +- .../models/InstrumentationParameters.java | 2 +- .../models/Method.java | 2 +- Instrumentation/build.gradle | 1 + .../models/Class.java | 2 +- .../models/InstrumentationParameters.java | 2 +- .../models/Method.java | 2 +- .../github/gilesi/instrumentation/Agent.java | 5 ++--- .../github/gilesi/instrumentation/Logger.java | 2 +- .../instrumentation/TraceCollector.java | 2 +- .../instrumentation/TraceDataFactory.java | 20 +++++++++++++++++++ .../instrumentation/models/TraceData.java | 1 + .../visitors/CommonAdvisor.java | 5 ++++- .../visitors/MethodInstrumentor.java | 4 ++-- .../instrumentation/models/TraceData.java | 1 + 17 files changed, 51 insertions(+), 17 deletions(-) create mode 100644 .idea/compiler.xml rename ConfGen/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/Class.java (75%) rename ConfGen/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/InstrumentationParameters.java (82%) rename ConfGen/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/Method.java (70%) rename Instrumentation/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/Class.java (71%) rename Instrumentation/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/InstrumentationParameters.java (79%) rename Instrumentation/src/main/java/com/github/gilesi/{instrumentation => confgen}/models/Method.java (65%) diff --git a/.idea/compiler.xml b/.idea/compiler.xml new file mode 100644 index 00000000..e8218821 --- /dev/null +++ b/.idea/compiler.xml @@ -0,0 +1,9 @@ + + + + + + + + + \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index b7ccb817..16a2b7cf 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -2,9 +2,9 @@ import com.github.gilesi.confgen.exceptions.UnsupportedJavaPrimitiveTypeException; import com.github.gilesi.confgen.spoon.SpoonLauncherUtilities; -import com.github.gilesi.instrumentation.models.Class; -import com.github.gilesi.instrumentation.models.InstrumentationParameters; -import com.github.gilesi.instrumentation.models.Method; +import com.github.gilesi.confgen.models.Class; +import com.github.gilesi.confgen.models.InstrumentationParameters; +import com.github.gilesi.confgen.models.Method; import com.github.maracas.roseau.api.SpoonAPIExtractor; import com.github.maracas.roseau.api.model.API; import com.github.maracas.roseau.api.model.ClassDecl; diff --git a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/Class.java similarity index 75% rename from ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/models/Class.java index f1f91237..939d7380 100644 --- a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Class.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/Class.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; import java.util.List; diff --git a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java similarity index 82% rename from ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 9c22e685..e167fcd0 100644 --- a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; import java.util.List; diff --git a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/Method.java similarity index 70% rename from ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java rename to ConfGen/src/main/java/com/github/gilesi/confgen/models/Method.java index 815720fe..52202bb9 100644 --- a/ConfGen/src/main/java/com/github/gilesi/instrumentation/models/Method.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/Method.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; import java.util.List; diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 9889462d..0a4f445e 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -19,6 +19,7 @@ dependencies { implementation 'net.bytebuddy:byte-buddy:1.14.15' implementation 'net.bytebuddy:byte-buddy-agent:1.14.13' implementation 'com.thoughtworks.xstream:xstream:1.4.20' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' } jar { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/Class.java similarity index 71% rename from Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java rename to Instrumentation/src/main/java/com/github/gilesi/confgen/models/Class.java index a3ad9d76..d8e63389 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Class.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/Class.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; public class Class { public String ClassName; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java similarity index 79% rename from Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java rename to Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index d508c849..08a3f31e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/Method.java similarity index 65% rename from Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java rename to Instrumentation/src/main/java/com/github/gilesi/confgen/models/Method.java index 144a81da..8ef6c1e1 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Method.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/Method.java @@ -1,4 +1,4 @@ -package com.github.gilesi.instrumentation.models; +package com.github.gilesi.confgen.models; public class Method { public String MethodName; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index ffbea03e..9ebe71de 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -1,7 +1,7 @@ package com.github.gilesi.instrumentation; -import com.github.gilesi.instrumentation.models.Class; -import com.github.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.gilesi.confgen.models.Class; +import com.github.gilesi.confgen.models.InstrumentationParameters; import com.github.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.gilesi.instrumentation.visitors.MethodInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; @@ -11,7 +11,6 @@ import java.lang.instrument.Instrumentation; import java.nio.charset.StandardCharsets; import java.nio.file.Files; -import java.nio.file.Path; import java.nio.file.Paths; /* diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index 39c6da12..6e6fb2af 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -1,6 +1,6 @@ package com.github.gilesi.instrumentation; -import com.github.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.gilesi.confgen.models.InstrumentationParameters; import java.io.File; import java.nio.file.Files; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index b9ee8ee8..c3636b33 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -1,6 +1,6 @@ package com.github.gilesi.instrumentation; -import com.github.gilesi.instrumentation.models.InstrumentationParameters; +import com.github.gilesi.confgen.models.InstrumentationParameters; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index 7be07190..21f17a21 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -1,14 +1,24 @@ package com.github.gilesi.instrumentation; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TraceData; +import com.fasterxml.jackson.databind.ObjectMapper; public class TraceDataFactory { + private static ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + public static TraceData valueOf(Object object, int nullInstanceId) { TraceData traceData = new TraceData(); if (object == null) { traceData.fullyQualifiedTypeName = "Object"; traceData.dataAsXml = "null"; + traceData.dataAsJson = "null"; traceData.instanceId = nullInstanceId; return traceData; } @@ -36,8 +46,18 @@ public static TraceData valueOf(Object object, int nullInstanceId) { Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); } + String serializedJsonString = null; + + try { + serializedJsonString = objectMapper.writeValueAsString(object); + } catch (Exception e) { + int loggerInstance = Logger.GetInstance(); + Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); + } + traceData.fullyQualifiedTypeName = objectClassName; traceData.dataAsXml = serializedString; + traceData.dataAsJson = serializedJsonString; traceData.instanceId = instanceId; return traceData; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index 7b459ec2..05e1d05c 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -3,5 +3,6 @@ public class TraceData { public String fullyQualifiedTypeName; public String dataAsXml; + public String dataAsJson; public int instanceId; } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index 57b951c9..ad1bb8b9 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -47,6 +47,9 @@ public static void commonExit( // Need to fetch this asap to not be off on the measurements! long exitMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; + //List stackTraceElements = StackWalker.getInstance().walk(stackFrameStream -> stackFrameStream.collect(Collectors.toList())); + //String[] stackTrace = stackTraceElements.stream().skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); @@ -70,7 +73,7 @@ public static void commonExit( } private static String getTestMethodName(String[] stackTrace) { - for (int i = 0; i < stackTrace.length; i++) { + for (int i = 3; i < stackTrace.length; i++) { String methodName = stackTrace[i]; if (methodName.equals(JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN)) { return stackTrace[i - 3]; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java index 8a152b97..ccc7654e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -1,7 +1,7 @@ package com.github.gilesi.instrumentation.visitors; -import com.github.gilesi.instrumentation.models.Class; -import com.github.gilesi.instrumentation.models.Method; +import com.github.gilesi.confgen.models.Class; +import com.github.gilesi.confgen.models.Method; import net.bytebuddy.agent.builder.AgentBuilder; import net.bytebuddy.asm.Advice; import net.bytebuddy.description.method.MethodDescription; diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index 7b459ec2..05e1d05c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -3,5 +3,6 @@ public class TraceData { public String fullyQualifiedTypeName; public String dataAsXml; + public String dataAsJson; public int instanceId; } \ No newline at end of file From 17cb56cf1e0d49bcdc611c2f987f2bc1a4174506 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 13:47:37 +0200 Subject: [PATCH 099/244] Add maven sample project --- Samples2/pom.xml | 49 +++++ Samples2/sampleclient/pom.xml | 52 ++++++ .../gilesi/samples/sampleclient/C1.java | 11 ++ .../gilesi/samples/sampleclient/C2.java | 9 + .../gilesi/samples/sampleclient/Main.java | 15 ++ .../gilesi/samples/sampleclient/Main2.java | 174 ++++++++++++++++++ .../sampleclient/src/test/java/CTest.java | 22 +++ .../sampleclient/src/test/java/FooTest.java | 144 +++++++++++++++ Samples2/samplelibrary/pom.xml | 35 ++++ .../gilesi/samples/samplelibrary/A.java | 22 +++ .../gilesi/samples/samplelibrary/A2.java | 21 +++ .../gilesi/samples/samplelibrary/Foo.java | 60 ++++++ .../gilesi/samples/samplelibrary/Foo2.java | 60 ++++++ .../samples/samplelibrary/IDoSomething.java | 5 + .../samplelibrary/src/test/java/ATest.java | 23 +++ 15 files changed, 702 insertions(+) create mode 100644 Samples2/pom.xml create mode 100644 Samples2/sampleclient/pom.xml create mode 100644 Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java create mode 100644 Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java create mode 100644 Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java create mode 100644 Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java create mode 100644 Samples2/sampleclient/src/test/java/CTest.java create mode 100644 Samples2/sampleclient/src/test/java/FooTest.java create mode 100644 Samples2/samplelibrary/pom.xml create mode 100644 Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java create mode 100644 Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java create mode 100644 Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java create mode 100644 Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java create mode 100644 Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java create mode 100644 Samples2/samplelibrary/src/test/java/ATest.java diff --git a/Samples2/pom.xml b/Samples2/pom.xml new file mode 100644 index 00000000..75e15923 --- /dev/null +++ b/Samples2/pom.xml @@ -0,0 +1,49 @@ + + + 4.0.0 + com.github.gilesi.samples + sample2 + pom + Sample + Sample project + 1.0-SNAPSHOT + + + junit + junit + 4.13.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.11.0-M2 + test + + + + 11 + 11 + + + samplelibrary + sampleclient + + \ No newline at end of file diff --git a/Samples2/sampleclient/pom.xml b/Samples2/sampleclient/pom.xml new file mode 100644 index 00000000..e0b4512b --- /dev/null +++ b/Samples2/sampleclient/pom.xml @@ -0,0 +1,52 @@ + + + 4.0.0 + + sampleclient + 1.0-SNAPSHOT + + + + org.apache.maven.plugins + maven-compiler-plugin + + 16 + 16 + + + + + + + com.github.gilesi.samples + sample2 + 1.0-SNAPSHOT + + jar + + + 11 + 11 + + + + junit + junit + 4.13.2 + test + + + com.github.gilesi.samples + samplelibrary + 1.0-SNAPSHOT + + + org.junit.jupiter + junit-jupiter-engine + 5.11.0-M2 + test + + + \ No newline at end of file diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java new file mode 100644 index 00000000..d9d039c3 --- /dev/null +++ b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java @@ -0,0 +1,11 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.A2; + +public class C1 { + public static int Do(int i) { + A2 a = new A2(5); + a.sideEffect(); + return C2.bar(a); + } +} diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java new file mode 100644 index 00000000..8867bcc0 --- /dev/null +++ b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java @@ -0,0 +1,9 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.A2; + +public class C2 { + public static int bar(A2 a) { + return a.foo(1); + } +} diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java new file mode 100644 index 00000000..19cfb299 --- /dev/null +++ b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java @@ -0,0 +1,15 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.A; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + DoWork(); + } + + public static void DoWork() { + System.out.println("Is the answer of life the universe and everything nice? " + new A(42).foo(42)); + System.out.println("What about 5 and 1? " + new A(5).foo(1)); + } +} \ No newline at end of file diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java new file mode 100644 index 00000000..3beeb9eb --- /dev/null +++ b/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java @@ -0,0 +1,174 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.Foo; +import com.github.gilesi.samples.samplelibrary.Foo2; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; + +public class Main2 { + + public static void main(String[] args) { + Foo f = new Foo("yo"); + System.out.println(f.sayHelloFoo()); + + System.out.println("[Foo] Constructing now"); + Foo f2 = new Foo("yo2"); + System.out.println("[Foo] End of constructor"); + + System.out.println(); + + System.out.println("[hello] Calling now"); + String result = f2.hello(); + System.out.println("[hello] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[sayHelloFoo] Calling now"); + result = f.sayHelloFoo(); + System.out.println("[sayHelloFoo] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hello] Calling now"); + result = f.hello(); + System.out.println("[hello] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hellow] Calling now"); + result = f.hellow("testestest"); + System.out.println("[hellow] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hellow] Calling now"); + result = f.hellow("testestest696969696"); + System.out.println("[hellow] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[TESTING(STATIC)] Calling now"); + result = Foo.TESTING("YO"); + System.out.println("[TESTING(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[TESTING(STATIC)] Calling now"); + result = Foo.TESTING("testestest696969696"); + System.out.println("[TESTING(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + String[] people = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; + + System.out.println("[HelloEveryone(STATIC)] Calling now"); + result = Foo.HelloEveryone(people); + System.out.println("[HelloEveryone(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + List peopleList = new ArrayList<>(Arrays.asList(people)); + + System.out.println("People List Right now:"); + for (String pe : peopleList) { + System.out.println(pe); + } + + System.out.println("[HelloEveryone2(STATIC)] Calling now"); + result = Foo.HelloEveryone2(peopleList); + System.out.println("[HelloEveryone2(STATIC)] End of call: [" + result + "]"); + + System.out.println("People List Right now:"); + for (String pe : peopleList) { + System.out.println(pe); + } + + System.out.println(Foo.meaningof(42)); + System.out.println(); + + Foo.SomeValueStoredHere = Foo.SomeValueStoredHere + Foo.SomeValueStoredHere; + + + Foo2 ff = new Foo2("yo"); + System.out.println(ff.sayHelloFoo()); + + System.out.println("[Foo2] Constructing now"); + Foo2 ff2 = new Foo2("yo2"); + System.out.println("[Foo2] End of constructor"); + + System.out.println(); + + System.out.println("[hello] Calling now"); + result = ff2.hello(); + System.out.println("[hello] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[sayHelloFoo2] Calling now"); + result = ff.sayHelloFoo(); + System.out.println("[sayHelloFoo2] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hello] Calling now"); + result = ff.hello(); + System.out.println("[hello] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hellow] Calling now"); + result = ff.hellow("testestest"); + System.out.println("[hellow] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[hellow] Calling now"); + result = ff.hellow("testestest696969696"); + System.out.println("[hellow] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[TESTING(STATIC)] Calling now"); + result = Foo2.TESTING("YO"); + System.out.println("[TESTING(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + System.out.println("[TESTING(STATIC)] Calling now"); + result = Foo2.TESTING("testestest696969696"); + System.out.println("[TESTING(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + people = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; + + System.out.println("[HelloEveryone(STATIC)] Calling now"); + result = Foo2.jhgbjtjbh(people); + System.out.println("[HelloEveryone(STATIC)] End of call: [" + result + "]"); + + System.out.println(); + + peopleList = new ArrayList<>(Arrays.asList(people)); + + System.out.println("People List Right now:"); + for (String pe : peopleList) { + System.out.println(pe); + } + + System.out.println("[HelloEveryone2(STATIC)] Calling now"); + result = Foo2.njrhbgtujhu(peopleList); + System.out.println("[HelloEveryone2(STATIC)] End of call: [" + result + "]"); + + System.out.println("People List Right now:"); + for (String pe : peopleList) { + System.out.println(pe); + } + + System.out.println(Foo2.triuetyg(42)); + System.out.println(); + + Foo2.SomeValueStoredHere = Foo2.SomeValueStoredHere + Foo2.SomeValueStoredHere; + } +} \ No newline at end of file diff --git a/Samples2/sampleclient/src/test/java/CTest.java b/Samples2/sampleclient/src/test/java/CTest.java new file mode 100644 index 00000000..ee219cca --- /dev/null +++ b/Samples2/sampleclient/src/test/java/CTest.java @@ -0,0 +1,22 @@ +import com.github.gilesi.samples.sampleclient.C1; +import com.github.gilesi.samples.samplelibrary.A2; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class CTest { + @Test + public void Test() { + C1 c1 = new C1(); + int s = C1.Do(3); + assertEquals(s, 21); + } + + @Test + public void ClientATest() { + com.github.gilesi.samples.samplelibrary.A2 a = new A2(5); + a = a.getOurselves(); + int r = a.foo(1); + assertEquals(r, 11); + } +} diff --git a/Samples2/sampleclient/src/test/java/FooTest.java b/Samples2/sampleclient/src/test/java/FooTest.java new file mode 100644 index 00000000..e34b122b --- /dev/null +++ b/Samples2/sampleclient/src/test/java/FooTest.java @@ -0,0 +1,144 @@ +import com.github.gilesi.samples.samplelibrary.A; +import com.github.gilesi.samples.samplelibrary.Foo; +import com.github.gilesi.samples.samplelibrary.Foo2; +import org.junit.jupiter.api.Test; + +import java.util.ArrayList; +import java.util.Arrays; + +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class FooTest { + @Test + public void mainTest() { + java.lang.String var2 = "yo"; + Foo var1 = new Foo(var2); + assertEquals(var2, "yo"); + + java.lang.String var3 = var1.sayHelloFoo(); + assertEquals(var3, "Hello in Foo!"); + + java.lang.String var5 = "yo2"; + Foo var4 = new Foo(var5); + assertEquals(var5, "yo2"); + + java.lang.String var6 = var4.hello(); + assertEquals(var6, "Hello yo2"); + + var3 = var1.sayHelloFoo(); + assertEquals(var3, "Hello in Foo!"); + + java.lang.String var7 = var1.hello(); + assertEquals(var7, "Hello yo"); + + java.lang.String var9 = "testestest"; + java.lang.String var8 = var1.hellow(var9); + assertEquals(var8, "Hello: testestest"); + assertEquals(var9, "testestest"); + + java.lang.String var11 = "testestest696969696"; + java.lang.String var10 = var1.hellow(var11); + assertEquals(var10, "420"); + assertEquals(var11, "testestest696969696"); + + java.lang.String var13 = "YO"; + java.lang.String var12 = Foo.TESTING(var13); + assertEquals(var12, "HELLO: YO"); + assertEquals(var13, "YO"); + + var11 = "testestest696969696"; + var10 = Foo.TESTING(var11); + assertEquals(var10, "420"); + assertEquals(var11, "testestest696969696"); + + java.lang.String[] var15 = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; + java.lang.String var14 = Foo.HelloEveryone(var15); + assertEquals(var14, "Hello [Toto, Tata, Titi, JP, PA, JR]"); + assertArrayEquals(var15, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); + + ArrayList var17 = new ArrayList(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); + ArrayList var171 = new ArrayList(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); + java.lang.String var16 = Foo.HelloEveryone2(var17); + assertEquals(var16, "Hello TotoTataTitiJPPAJR"); + assertEquals(var17, var171); + + java.lang.Integer var19 = 42; + java.lang.String var18 = Foo.meaningof(var19); + assertEquals(var18, "the life the universe and everything"); + assertEquals(var19, 42); + + var2 = "yo"; + Foo2 var20 = new Foo2(var2); + assertEquals(var2, "yo"); + + var3 = var20.sayHelloFoo(); + assertEquals(var3, "Hello in Foo!"); + + var5 = "yo2"; + Foo2 var21 = new Foo2(var5); + assertEquals(var5, "yo2"); + + java.lang.String var22 = var21.hello(); + assertEquals(var22, "Hello yo2"); + + var3 = var20.sayHelloFoo(); + assertEquals(var3, "Hello in Foo!"); + + java.lang.String var23 = var20.hello(); + assertEquals(var23, "Hello yo"); + + var9 = "testestest"; + java.lang.String var24 = var20.hellow(var9); + assertEquals(var24, "Hello: testestest"); + assertEquals(var9, "testestest"); + + var11 = "testestest696969696"; + var10 = var20.hellow(var11); + assertEquals(var10, "420"); + assertEquals(var11, "testestest696969696"); + + var13 = "YO"; + java.lang.String var25 = Foo2.TESTING(var13); + assertEquals(var25, "HELLO: YO"); + assertEquals(var13, "YO"); + + var11 = "testestest696969696"; + var10 = Foo2.TESTING(var11); + assertEquals(var10, "420"); + assertEquals(var11, "testestest696969696"); + + java.lang.String[] var27 = new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}; + java.lang.String var26 = Foo2.jhgbjtjbh(var27); + assertEquals(var26, "Hello [Toto, Tata, Titi, JP, PA, JR]"); + assertArrayEquals(var27, new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}); + + ArrayList var29 = new ArrayList(Arrays.stream(new String[]{"Toto", "Tata", "Titi", "JP", "PA", "JR"}).toList()); + ArrayList var291 = new ArrayList(Arrays.stream(new String[]{"NewPersonA", "NewPersonB", "NewPersonC", "NewPersonD"}).toList()); + java.lang.String var28 = Foo2.njrhbgtujhu(var29); + assertEquals(var28, "Hello TotoTataTitiJPPAJR"); + assertEquals(var29, var291); + + var19 = 42; + var18 = Foo2.triuetyg(var19); + assertEquals(var18, "the life the universe and everything"); + assertEquals(var19, 42); + } + + @Test + public void TestFoo() { + A a = new A(5); + int result = a.foo(1); + assertEquals(result, 7); + } + + @Test + public void TestFooIsLifeNice() { + A a = new A(42); + int result = a.foo(1); + + a.CallBack(this::TestFoo); + + assertEquals(result, 69); + } +} \ No newline at end of file diff --git a/Samples2/samplelibrary/pom.xml b/Samples2/samplelibrary/pom.xml new file mode 100644 index 00000000..7494d3f1 --- /dev/null +++ b/Samples2/samplelibrary/pom.xml @@ -0,0 +1,35 @@ + + + 4.0.0 + + samplelibrary + 1.0-SNAPSHOT + + + com.github.gilesi.samples + sample2 + 1.0-SNAPSHOT + + jar + + + 11 + 11 + + + + junit + junit + 4.13.2 + test + + + org.junit.jupiter + junit-jupiter-engine + 5.11.0-M2 + test + + + \ No newline at end of file diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java new file mode 100644 index 00000000..b9751faa --- /dev/null +++ b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java @@ -0,0 +1,22 @@ +package com.github.gilesi.samples.samplelibrary; + +public class A { + private final int j; + + public A(int j) { + this.j = j; + } + + public int foo(int i) { + if (j == 42) { + return 69; + } + + return j + (i * 2); + } + + public void CallBack(IDoSomething doSomething) { + doSomething.Do(); + foo(2); + } +} diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java new file mode 100644 index 00000000..cf025104 --- /dev/null +++ b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java @@ -0,0 +1,21 @@ +package com.github.gilesi.samples.samplelibrary; + +public class A2 { + private int i; + + public A2(int i) { + this.i = i; + } + + public int foo(int i) { + return i + 2 * this.i; + } + + public void sideEffect() { + this.i *= 2; + } + + public A2 getOurselves() { + return this; + } +} diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java new file mode 100644 index 00000000..4109500d --- /dev/null +++ b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java @@ -0,0 +1,60 @@ +package com.github.gilesi.samples.samplelibrary; + +import java.util.Arrays; +import java.util.Collection; + +public class Foo { + public static String SomeValueStoredHere = "ha"; + private final String value; + + public Foo(String value) { + this.value = value; + } + + public static String TESTING(String WHY) { + if (WHY.equals("testestest696969696")) { + return "420"; + } + return "HELLO: " + WHY; + } + + public static String HelloEveryone(String[] familly) { + return "Hello " + Arrays.toString(familly); + } + + public static String HelloEveryone2(Collection familly) { + String fam = String.join("", familly); + familly.clear(); + familly.add("NewPersonA"); + familly.add("NewPersonB"); + familly.add("NewPersonC"); + familly.add("NewPersonD"); + return "Hello " + fam; + } + + public static String meaningof(int value) { + if (value == 42) { + return "the life the universe and everything"; + } + return String.valueOf(value); + } + + public String sayHelloFoo() { + return "Hello in Foo!"; + } + + public void hello(String a) { + System.out.println("Hello: " + a); + } + + public String hello() { + return "Hello " + value; + } + + public String hellow(String a) { + if (a.equals("testestest696969696")) { + return "420"; + } + return "Hello: " + a; + } +} diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java new file mode 100644 index 00000000..34b98d84 --- /dev/null +++ b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java @@ -0,0 +1,60 @@ +package com.github.gilesi.samples.samplelibrary; + +import java.util.Arrays; +import java.util.Collection; + +public class Foo2 { + public static String SomeValueStoredHere = "ha"; + private final String value; + + public Foo2(String value) { + this.value = value; + } + + public static String TESTING(String WHY) { + if (WHY.equals("testestest696969696")) { + return "420"; + } + return "HELLO: " + WHY; + } + + public static String jhgbjtjbh(String[] familly) { + return "Hello " + Arrays.toString(familly); + } + + public static String njrhbgtujhu(Collection familly) { + String fam = String.join("", familly); + familly.clear(); + familly.add("NewPersonA"); + familly.add("NewPersonB"); + familly.add("NewPersonC"); + familly.add("NewPersonD"); + return "Hello " + fam; + } + + public static String triuetyg(int value) { + if (value == 42) { + return "the life the universe and everything"; + } + return String.valueOf(value); + } + + public String sayHelloFoo() { + return "Hello in Foo!"; + } + + public void hello(String a) { + System.out.println("Hello: " + a); + } + + public String hello() { + return "Hello " + value; + } + + public String hellow(String a) { + if (a.equals("testestest696969696")) { + return "420"; + } + return "Hello: " + a; + } +} diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java new file mode 100644 index 00000000..fff02e20 --- /dev/null +++ b/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java @@ -0,0 +1,5 @@ +package com.github.gilesi.samples.samplelibrary; + +public interface IDoSomething { + void Do(); +} diff --git a/Samples2/samplelibrary/src/test/java/ATest.java b/Samples2/samplelibrary/src/test/java/ATest.java new file mode 100644 index 00000000..b86dd475 --- /dev/null +++ b/Samples2/samplelibrary/src/test/java/ATest.java @@ -0,0 +1,23 @@ +import com.github.gilesi.samples.samplelibrary.A; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +public class ATest { + @Test + public void TestFoo() { + A a = new A(5); + int result = a.foo(1); + assertEquals(result, 7); + } + + @Test + public void TestFooIsLifeNice() { + A a = new A(42); + int result = a.foo(1); + + a.CallBack(this::TestFoo); + + assertEquals(result, 69); + } +} From d3f7a609d2f45e793bf67ec125fc1bd66e4c9776 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 13:51:17 +0200 Subject: [PATCH 100/244] Move samples around --- .idea/compiler.xml | 9 +++++ .idea/jarRepositories.xml | 34 +++++++++++------- .idea/misc.xml | 9 +++++ .../instrumentation/TraceDataFactory.java | 2 +- Samples/{ => Gradle}/.gitignore | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 Samples/{ => Gradle}/gradlew | 0 Samples/{ => Gradle}/gradlew.bat | 0 Samples/{ => Gradle}/sampleclient/.gitignore | 0 .../{ => Gradle}/sampleclient/build.gradle | 0 .../gilesi/samples/sampleclient/C1.java | 0 .../gilesi/samples/sampleclient/C2.java | 0 .../gilesi/samples/sampleclient/Main.java | 0 .../gilesi/samples/sampleclient/Main2.java | 0 .../sampleclient/src/test/java/CTest.java | 0 .../sampleclient/src/test/java/FooTest.java | 0 Samples/{ => Gradle}/samplelibrary/.gitignore | 0 .../{ => Gradle}/samplelibrary/build.gradle | 0 .../gilesi/samples/samplelibrary/A.java | 0 .../gilesi/samples/samplelibrary/A2.java | 0 .../gilesi/samples/samplelibrary/Foo.java | 0 .../gilesi/samples/samplelibrary/Foo2.java | 0 .../samples/samplelibrary/IDoSomething.java | 0 .../samplelibrary/src/test/java/ATest.java | 0 Samples/{ => Gradle}/settings.gradle | 0 {Samples2 => Samples/Maven}/pom.xml | 0 .../Maven}/sampleclient/pom.xml | 0 .../gilesi/samples/sampleclient/C1.java | 0 .../gilesi/samples/sampleclient/C2.java | 0 .../gilesi/samples/sampleclient/Main.java | 0 .../gilesi/samples/sampleclient/Main2.java | 0 .../sampleclient/src/test/java/CTest.java | 0 .../sampleclient/src/test/java/FooTest.java | 0 .../Maven}/samplelibrary/pom.xml | 0 .../gilesi/samples/samplelibrary/A.java | 0 .../gilesi/samples/samplelibrary/A2.java | 0 .../gilesi/samples/samplelibrary/Foo.java | 0 .../gilesi/samples/samplelibrary/Foo2.java | 0 .../samples/samplelibrary/IDoSomething.java | 0 .../samplelibrary/src/test/java/ATest.java | 0 41 files changed, 41 insertions(+), 13 deletions(-) rename Samples/{ => Gradle}/.gitignore (100%) rename Samples/{ => Gradle}/gradle/wrapper/gradle-wrapper.jar (100%) rename Samples/{ => Gradle}/gradle/wrapper/gradle-wrapper.properties (100%) rename Samples/{ => Gradle}/gradlew (100%) rename Samples/{ => Gradle}/gradlew.bat (100%) rename Samples/{ => Gradle}/sampleclient/.gitignore (100%) rename Samples/{ => Gradle}/sampleclient/build.gradle (100%) rename Samples/{ => Gradle}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java (100%) rename Samples/{ => Gradle}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java (100%) rename Samples/{ => Gradle}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java (100%) rename Samples/{ => Gradle}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java (100%) rename Samples/{ => Gradle}/sampleclient/src/test/java/CTest.java (100%) rename Samples/{ => Gradle}/sampleclient/src/test/java/FooTest.java (100%) rename Samples/{ => Gradle}/samplelibrary/.gitignore (100%) rename Samples/{ => Gradle}/samplelibrary/build.gradle (100%) rename Samples/{ => Gradle}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java (100%) rename Samples/{ => Gradle}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java (100%) rename Samples/{ => Gradle}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java (100%) rename Samples/{ => Gradle}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java (100%) rename Samples/{ => Gradle}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java (100%) rename Samples/{ => Gradle}/samplelibrary/src/test/java/ATest.java (100%) rename Samples/{ => Gradle}/settings.gradle (100%) rename {Samples2 => Samples/Maven}/pom.xml (100%) rename {Samples2 => Samples/Maven}/sampleclient/pom.xml (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/test/java/CTest.java (100%) rename {Samples2 => Samples/Maven}/sampleclient/src/test/java/FooTest.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/pom.xml (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java (100%) rename {Samples2 => Samples/Maven}/samplelibrary/src/test/java/ATest.java (100%) diff --git a/.idea/compiler.xml b/.idea/compiler.xml index e8218821..11fb55ae 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -1,6 +1,15 @@ + + + + + + + + + diff --git a/.idea/jarRepositories.xml b/.idea/jarRepositories.xml index bdd6c10e..d1fda739 100644 --- a/.idea/jarRepositories.xml +++ b/.idea/jarRepositories.xml @@ -3,13 +3,18 @@ - + + - - + + \ No newline at end of file diff --git a/.idea/misc.xml b/.idea/misc.xml index 962a3af7..ffb079cd 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -7,6 +7,15 @@ + + + diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index 21f17a21..a21b7f4a 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -1,8 +1,8 @@ package com.github.gilesi.instrumentation; +import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TraceData; -import com.fasterxml.jackson.databind.ObjectMapper; public class TraceDataFactory { private static ObjectMapper objectMapper = new ObjectMapper() diff --git a/Samples/.gitignore b/Samples/Gradle/.gitignore similarity index 100% rename from Samples/.gitignore rename to Samples/Gradle/.gitignore diff --git a/Samples/gradle/wrapper/gradle-wrapper.jar b/Samples/Gradle/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from Samples/gradle/wrapper/gradle-wrapper.jar rename to Samples/Gradle/gradle/wrapper/gradle-wrapper.jar diff --git a/Samples/gradle/wrapper/gradle-wrapper.properties b/Samples/Gradle/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from Samples/gradle/wrapper/gradle-wrapper.properties rename to Samples/Gradle/gradle/wrapper/gradle-wrapper.properties diff --git a/Samples/gradlew b/Samples/Gradle/gradlew similarity index 100% rename from Samples/gradlew rename to Samples/Gradle/gradlew diff --git a/Samples/gradlew.bat b/Samples/Gradle/gradlew.bat similarity index 100% rename from Samples/gradlew.bat rename to Samples/Gradle/gradlew.bat diff --git a/Samples/sampleclient/.gitignore b/Samples/Gradle/sampleclient/.gitignore similarity index 100% rename from Samples/sampleclient/.gitignore rename to Samples/Gradle/sampleclient/.gitignore diff --git a/Samples/sampleclient/build.gradle b/Samples/Gradle/sampleclient/build.gradle similarity index 100% rename from Samples/sampleclient/build.gradle rename to Samples/Gradle/sampleclient/build.gradle diff --git a/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java similarity index 100% rename from Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java rename to Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java diff --git a/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java similarity index 100% rename from Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java rename to Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java diff --git a/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java similarity index 100% rename from Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java rename to Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java diff --git a/Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java similarity index 100% rename from Samples/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java rename to Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java diff --git a/Samples/sampleclient/src/test/java/CTest.java b/Samples/Gradle/sampleclient/src/test/java/CTest.java similarity index 100% rename from Samples/sampleclient/src/test/java/CTest.java rename to Samples/Gradle/sampleclient/src/test/java/CTest.java diff --git a/Samples/sampleclient/src/test/java/FooTest.java b/Samples/Gradle/sampleclient/src/test/java/FooTest.java similarity index 100% rename from Samples/sampleclient/src/test/java/FooTest.java rename to Samples/Gradle/sampleclient/src/test/java/FooTest.java diff --git a/Samples/samplelibrary/.gitignore b/Samples/Gradle/samplelibrary/.gitignore similarity index 100% rename from Samples/samplelibrary/.gitignore rename to Samples/Gradle/samplelibrary/.gitignore diff --git a/Samples/samplelibrary/build.gradle b/Samples/Gradle/samplelibrary/build.gradle similarity index 100% rename from Samples/samplelibrary/build.gradle rename to Samples/Gradle/samplelibrary/build.gradle diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java similarity index 100% rename from Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java rename to Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java similarity index 100% rename from Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java rename to Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java similarity index 100% rename from Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java rename to Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java similarity index 100% rename from Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java rename to Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java diff --git a/Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java similarity index 100% rename from Samples/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java rename to Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java diff --git a/Samples/samplelibrary/src/test/java/ATest.java b/Samples/Gradle/samplelibrary/src/test/java/ATest.java similarity index 100% rename from Samples/samplelibrary/src/test/java/ATest.java rename to Samples/Gradle/samplelibrary/src/test/java/ATest.java diff --git a/Samples/settings.gradle b/Samples/Gradle/settings.gradle similarity index 100% rename from Samples/settings.gradle rename to Samples/Gradle/settings.gradle diff --git a/Samples2/pom.xml b/Samples/Maven/pom.xml similarity index 100% rename from Samples2/pom.xml rename to Samples/Maven/pom.xml diff --git a/Samples2/sampleclient/pom.xml b/Samples/Maven/sampleclient/pom.xml similarity index 100% rename from Samples2/sampleclient/pom.xml rename to Samples/Maven/sampleclient/pom.xml diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java b/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java similarity index 100% rename from Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java rename to Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java b/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java similarity index 100% rename from Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java rename to Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java b/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java similarity index 100% rename from Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java rename to Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java diff --git a/Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java b/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java similarity index 100% rename from Samples2/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java rename to Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java diff --git a/Samples2/sampleclient/src/test/java/CTest.java b/Samples/Maven/sampleclient/src/test/java/CTest.java similarity index 100% rename from Samples2/sampleclient/src/test/java/CTest.java rename to Samples/Maven/sampleclient/src/test/java/CTest.java diff --git a/Samples2/sampleclient/src/test/java/FooTest.java b/Samples/Maven/sampleclient/src/test/java/FooTest.java similarity index 100% rename from Samples2/sampleclient/src/test/java/FooTest.java rename to Samples/Maven/sampleclient/src/test/java/FooTest.java diff --git a/Samples2/samplelibrary/pom.xml b/Samples/Maven/samplelibrary/pom.xml similarity index 100% rename from Samples2/samplelibrary/pom.xml rename to Samples/Maven/samplelibrary/pom.xml diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java b/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java similarity index 100% rename from Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java rename to Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java b/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java similarity index 100% rename from Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java rename to Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java b/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java similarity index 100% rename from Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java rename to Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java b/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java similarity index 100% rename from Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java rename to Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java diff --git a/Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java b/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java similarity index 100% rename from Samples2/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java rename to Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java diff --git a/Samples2/samplelibrary/src/test/java/ATest.java b/Samples/Maven/samplelibrary/src/test/java/ATest.java similarity index 100% rename from Samples2/samplelibrary/src/test/java/ATest.java rename to Samples/Maven/samplelibrary/src/test/java/ATest.java From 34ceb9e30da6088c040ff8db46c7e7f86bcc8bfb Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 13:53:16 +0200 Subject: [PATCH 101/244] Fix scripts --- run-test-workflow.cmd | 10 +++++----- run-test-workflow.sh | 10 +++++----- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 19e08858..19e3879a 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -24,7 +24,7 @@ echo Running ConfGen echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Traces.Output" "%CD%\Samples\samplelibrary" "%CD%\Samples\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Traces.Output" "%CD%\Samples\Gradle\samplelibrary" "%CD%\Samples\Gradle\sampleclient" echo. @@ -33,15 +33,15 @@ echo Running Sample's Client Test Suite with Agent echo =========================================================== echo. -copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\sampleclient\" -copy "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\sampleclient\" +copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\Gradle\sampleclient\" +copy "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\Gradle\sampleclient\" cd Samples call .\gradlew.bat sampleclient:test --warning-mode all cd .. -del "%CD%\Samples\sampleclient\com.github.gilesi.instrumentation.jar" -del "%CD%\Samples\sampleclient\TestWorkflowConfiguration.xml" +del "%CD%\Samples\Gradle\sampleclient\com.github.gilesi.instrumentation.jar" +del "%CD%\Samples\Gradle\sampleclient\TestWorkflowConfiguration.xml" echo. echo =========================================================== diff --git a/run-test-workflow.sh b/run-test-workflow.sh index 336eb8e0..6b088c9c 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -22,7 +22,7 @@ echo Running ConfGen echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Traces.Output" "$PWD/Samples/samplelibrary" "$PWD/Samples/sampleclient" +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Traces.Output" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" echo @@ -31,15 +31,15 @@ echo $'Running Sample\'s Client Test Suite with Agent' echo =========================================================== echo -cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/sampleclient/ -cp $PWD/TestWorkflowConfiguration.xml $PWD/Samples/sampleclient/ +cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/Gradle/sampleclient/ +cp $PWD/TestWorkflowConfiguration.xml $PWD/Samples/Gradle/sampleclient/ cd Samples sh ./gradlew sampleclient:test --warning-mode all cd .. -rm $PWD/Samples/sampleclient/com.github.gilesi.instrumentation.jar -rm $PWD/Samples/sampleclient/TestWorkflowConfiguration.xml +rm $PWD/Samples/Gradle/sampleclient/com.github.gilesi.instrumentation.jar +rm $PWD/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml echo echo =========================================================== From 0a29d96261393445d061d4293b2a32c8aba0c081 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 13:55:33 +0200 Subject: [PATCH 102/244] Fix scripts --- run-clean-workflow.sh | 4 ++-- run-test-workflow.cmd | 4 ++-- run-test-workflow.sh | 8 ++++---- 3 files changed, 8 insertions(+), 8 deletions(-) diff --git a/run-clean-workflow.sh b/run-clean-workflow.sh index 54f2aab3..44ed09af 100644 --- a/run-clean-workflow.sh +++ b/run-clean-workflow.sh @@ -1,9 +1,9 @@ #!/bin/bash -cd Samples +cd Samples/Gradle rm -rf ./sampleclient/build rm -rf ./samplelibrary/build -cd .. +cd ../.. cd ConfGen rm -rf ./build diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index 19e3879a..bd95e8f5 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -36,9 +36,9 @@ echo. copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\Gradle\sampleclient\" copy "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\Gradle\sampleclient\" -cd Samples +cd Samples\Gradle call .\gradlew.bat sampleclient:test --warning-mode all -cd .. +cd ..\.. del "%CD%\Samples\Gradle\sampleclient\com.github.gilesi.instrumentation.jar" del "%CD%\Samples\Gradle\sampleclient\TestWorkflowConfiguration.xml" diff --git a/run-test-workflow.sh b/run-test-workflow.sh index 6b088c9c..32440b52 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -11,9 +11,9 @@ echo =========================================================== echo # build samples -cd Samples +cd Samples/Gradle sh ./gradlew jar --warning-mode all -cd .. +cd ../.. echo @@ -34,9 +34,9 @@ echo cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/Gradle/sampleclient/ cp $PWD/TestWorkflowConfiguration.xml $PWD/Samples/Gradle/sampleclient/ -cd Samples +cd Samples/Gradle sh ./gradlew sampleclient:test --warning-mode all -cd .. +cd ../.. rm $PWD/Samples/Gradle/sampleclient/com.github.gilesi.instrumentation.jar rm $PWD/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml From cb343cff52b0126824b116cfd0fc17365a101b70 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 14:28:47 +0200 Subject: [PATCH 103/244] Add orchestrator project --- .idea/misc.xml | 1 + Maestro/.gradle/8.5/checksums/checksums.lock | Bin 0 -> 17 bytes .../dependencies-accessors.lock | Bin 0 -> 17 bytes .../8.5/dependencies-accessors/gc.properties | 0 .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.5/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.5/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes Maestro/.gradle/8.5/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + Maestro/.gradle/vcs-1/gc.properties | 0 Maestro/build.gradle | 19 ++ .../gradle/wrapper/gradle-wrapper.properties | 6 + Maestro/gradlew | 234 ++++++++++++++++++ Maestro/gradlew.bat | 89 +++++++ Maestro/settings.gradle | 2 + .../src/main/java/com/github/gilesi/Main.java | 7 + .../com/github/gilesi/testgenerator/Main.java | 1 - 18 files changed, 360 insertions(+), 1 deletion(-) create mode 100644 Maestro/.gradle/8.5/checksums/checksums.lock create mode 100644 Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock create mode 100644 Maestro/.gradle/8.5/dependencies-accessors/gc.properties create mode 100644 Maestro/.gradle/8.5/executionHistory/executionHistory.lock create mode 100644 Maestro/.gradle/8.5/fileChanges/last-build.bin create mode 100644 Maestro/.gradle/8.5/fileHashes/fileHashes.lock create mode 100644 Maestro/.gradle/8.5/gc.properties create mode 100644 Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 Maestro/.gradle/buildOutputCleanup/cache.properties create mode 100644 Maestro/.gradle/vcs-1/gc.properties create mode 100644 Maestro/build.gradle create mode 100644 Maestro/gradle/wrapper/gradle-wrapper.properties create mode 100755 Maestro/gradlew create mode 100644 Maestro/gradlew.bat create mode 100644 Maestro/settings.gradle create mode 100644 Maestro/src/main/java/com/github/gilesi/Main.java diff --git a/.idea/misc.xml b/.idea/misc.xml index ffb079cd..c7cf370a 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -4,6 +4,7 @@ + diff --git a/Maestro/.gradle/8.5/checksums/checksums.lock b/Maestro/.gradle/8.5/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..cb07be94411beb44440d78de4dbc9fa9dd315546 GIT binary patch literal 17 TcmZQh-E`bBYlY5X1}FdkGxP)` literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock b/Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock new file mode 100644 index 0000000000000000000000000000000000000000..0273e60edc90a23dc4fd14acab933bc28ecdae61 GIT binary patch literal 17 TcmZSXID0eb=9#J+3{U_7L>mQr literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/dependencies-accessors/gc.properties b/Maestro/.gradle/8.5/dependencies-accessors/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/Maestro/.gradle/8.5/executionHistory/executionHistory.lock b/Maestro/.gradle/8.5/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..044da0eeefaa6722ac7bbc8042c8393b0894a21e GIT binary patch literal 17 TcmZQxyrIuLApFon1}FdkHcbR( literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/fileChanges/last-build.bin b/Maestro/.gradle/8.5/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/fileHashes/fileHashes.lock b/Maestro/.gradle/8.5/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..c87f56190c54a26a63b0b3c315e18c1baa480b47 GIT binary patch literal 17 TcmZSn{AkUZf={a_FhBtSN;(D3 literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/gc.properties b/Maestro/.gradle/8.5/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..43d9fea3d70f0b43ed19e5652e072790a4a7c1e1 GIT binary patch literal 17 UcmZQxu*C4{oAawI86bcW06qEy?EnA( literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/buildOutputCleanup/cache.properties b/Maestro/.gradle/buildOutputCleanup/cache.properties new file mode 100644 index 00000000..2ad95a8e --- /dev/null +++ b/Maestro/.gradle/buildOutputCleanup/cache.properties @@ -0,0 +1,2 @@ +#Mon May 27 14:15:12 CEST 2024 +gradle.version=8.5 diff --git a/Maestro/.gradle/vcs-1/gc.properties b/Maestro/.gradle/vcs-1/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/Maestro/build.gradle b/Maestro/build.gradle new file mode 100644 index 00000000..82528ce9 --- /dev/null +++ b/Maestro/build.gradle @@ -0,0 +1,19 @@ +plugins { + id 'java' +} + +group = 'com.github.gilesi' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/Maestro/gradle/wrapper/gradle-wrapper.properties b/Maestro/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..5c07b32a --- /dev/null +++ b/Maestro/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +#Mon May 27 14:15:06 CEST 2024 +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/Maestro/gradlew b/Maestro/gradlew new file mode 100755 index 00000000..1b6c7873 --- /dev/null +++ b/Maestro/gradlew @@ -0,0 +1,234 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/Maestro/gradlew.bat b/Maestro/gradlew.bat new file mode 100644 index 00000000..ac1b06f9 --- /dev/null +++ b/Maestro/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Maestro/settings.gradle b/Maestro/settings.gradle new file mode 100644 index 00000000..ac900376 --- /dev/null +++ b/Maestro/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'Maestro' + diff --git a/Maestro/src/main/java/com/github/gilesi/Main.java b/Maestro/src/main/java/com/github/gilesi/Main.java new file mode 100644 index 00000000..1c2ec9f4 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/Main.java @@ -0,0 +1,7 @@ +package com.github.gilesi; + +public class Main { + public static void main(String[] args) { + System.out.println("Hello world!"); + } +} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index f86cb144..08944d2c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -9,7 +9,6 @@ import com.thoughtworks.xstream.security.AnyTypePermission; import java.io.IOException; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; From bce31cc6179398be24835ebc63e92a77f53f622f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 15:29:40 +0200 Subject: [PATCH 104/244] Add harness backbone code --- .../instrumentation/TraceDataFactory.java | 2 +- Maestro/.gradle/8.5/checksums/checksums.lock | Bin 17 -> 17 bytes .../.gradle/8.5/checksums/md5-checksums.bin | Bin 0 -> 21647 bytes .../.gradle/8.5/checksums/sha1-checksums.bin | Bin 0 -> 28163 bytes .../8.5/executionHistory/executionHistory.bin | Bin 0 -> 39978 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 17 bytes Maestro/.gradle/8.5/fileHashes/fileHashes.bin | Bin 0 -> 20247 bytes .../.gradle/8.5/fileHashes/fileHashes.lock | Bin 17 -> 17 bytes .../8.5/fileHashes/resourceHashesCache.bin | Bin 0 -> 19075 bytes .../buildOutputCleanup.lock | Bin 17 -> 17 bytes .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18875 bytes Maestro/build.gradle | 7 + .../compileJava/previous-compilation-data.bin | Bin 0 -> 27144 bytes .../maven/ConfigurationUtils.java | 31 +++ .../maven/IPluginConfiguration.java | 7 + .../configuration/maven/PomHelper.java | 157 +++++++++++ .../maven/SureFirePluginConfiguration.java | 103 ++++++++ .../gilesi/runners/maven/ConsoleLogger.java | 247 ++++++++++++++++++ .../gilesi/runners/maven/ProjectRunner.java | 57 ++++ .../github/gilesi/testing/surefire/Error.java | 17 ++ .../gilesi/testing/surefire/FileUtils.java | 87 ++++++ .../gilesi/testing/surefire/Properties.java | 13 + .../gilesi/testing/surefire/Property.java | 22 ++ .../gilesi/testing/surefire/ReportItem.java | 62 +++++ .../testing/surefire/SurefireHarness.java | 49 ++++ .../gilesi/testing/surefire/Testcase.java | 23 ++ .../gilesi/testing/surefire/Testsuite.java | 103 ++++++++ .../gilesi/testing/surefire/Testsuites.java | 13 + .../gilesi/testing/surefire/XmlParser.java | 31 +++ 29 files changed, 1030 insertions(+), 1 deletion(-) create mode 100644 Maestro/.gradle/8.5/checksums/md5-checksums.bin create mode 100644 Maestro/.gradle/8.5/checksums/sha1-checksums.bin create mode 100644 Maestro/.gradle/8.5/executionHistory/executionHistory.bin create mode 100644 Maestro/.gradle/8.5/fileHashes/fileHashes.bin create mode 100644 Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin create mode 100644 Maestro/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 Maestro/build/tmp/compileJava/previous-compilation-data.bin create mode 100644 Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java create mode 100644 Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java create mode 100644 Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java create mode 100644 Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java create mode 100644 Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java create mode 100644 Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java create mode 100644 Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index a21b7f4a..08d93039 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -5,7 +5,7 @@ import com.github.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - private static ObjectMapper objectMapper = new ObjectMapper() + private static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) diff --git a/Maestro/.gradle/8.5/checksums/checksums.lock b/Maestro/.gradle/8.5/checksums/checksums.lock index cb07be94411beb44440d78de4dbc9fa9dd315546..93c42fe2fd7bdde7d4087406c67cf8579785a002 100644 GIT binary patch literal 17 VcmZQh-E`bBYlY5X1~6b`1OPMl1SS9g literal 17 TcmZQh-E`bBYlY5X1}FdkGxP)` diff --git a/Maestro/.gradle/8.5/checksums/md5-checksums.bin b/Maestro/.gradle/8.5/checksums/md5-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..6402e132f9db7c139d785f9f13a64480d3441ca1 GIT binary patch literal 21647 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 b>+P#xJ1(z}(A>ix+YF5=p+K819Ql6%M#(9{ literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/checksums/sha1-checksums.bin b/Maestro/.gradle/8.5/checksums/sha1-checksums.bin new file mode 100644 index 0000000000000000000000000000000000000000..9a4e427ee161a3130804f4dc4784b82e15c9d568 GIT binary patch literal 28163 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 b{rtFmkPU literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/executionHistory/executionHistory.bin b/Maestro/.gradle/8.5/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..d7dd66727aefd4935057c0fb699e33fa9fc4a34d GIT binary patch literal 39978 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 BS&;w$ literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/executionHistory/executionHistory.lock b/Maestro/.gradle/8.5/executionHistory/executionHistory.lock index 044da0eeefaa6722ac7bbc8042c8393b0894a21e..8cd3b33efec3baed309aad2c042899bcd9bdf7b2 100644 GIT binary patch literal 17 UcmZQxyrIuLApFon1_)pQ05(wsY5)KL literal 17 TcmZQxyrIuLApFon1}FdkHcbR( diff --git a/Maestro/.gradle/8.5/fileHashes/fileHashes.bin b/Maestro/.gradle/8.5/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..276369a0c6c6de5feed740468747f46fab4e518e GIT binary patch literal 20247 zcmeI3do)ye9Kf%^c#CS79!`m^ydR;1$|}mxP^??Tcn1wHEKQf&i(y5J;!y=XXf+!-TRq){bPPE6vfvX z#~bx|<9$AaBPaj`pa2wr0#E=7KmjNK1)u;FfC5ke3P1rU00p1`6o3Ly;Qvy+OwRBJO#S@J63@Qxoebx|ehls1V+wcsC*8MKl>dobU%u$@Yd?H-pjp-J%Is zNqn1L;IU^f;z9$$)kQwTi3$2uhzqt7KK&&(rB3TqG2$K;gzNh|-U;;#s6^b;i*VB! zYbH9HX&=VpCw<~?`zvhoBa{($b0*wue(kiCPC59xJk}BJp}Dcw*2@cb5Hu4mjBTmB zn>qUko>!0Xm7SP?8Sv57<6J(uuryiFZbW#5`n6?WAF5l0 zxX_pI=&XTI*NT#Bh`T-f#E*|go^2ZvBksAM@Eyvc2@N4OoACI9gp=PCB_D`hgFO_0 z0#E=7KmjNK1)u;FfC5ke3P1rU00p1`6o3Ly017|>C;$bZ02F`%Pyh-*0Vn_kpa2wr z0#E=7KmjNK1)u;FfC5n9zbi109@>ch(U<;csfij5)C20MUln6xCT+R(B}K`lUz<=f zNWVyL3QOpn`M-_q>jQbMReFZcGkn+pV@HK@0V8p zoz`uPp~ZWG461@{Y*#&-tLwf{qcF>Q?LnJ~m(W=Sze0xQLAJ5KzG&~*vD5r`?x>w> zd_*T>%=5$Ftf#(b8!=PlG5LR%ht*r(3DyUO|SkbajP{q3`=DTfMTa`SFa|W&v_xQyIf$8_K8{~&Kr*Vz!-XSMj3&UqwgA7!|!xvu2+9iU+tQ@Ez=fO zbTEdlCcbhxF53{_OpD_#d2QHKm-|&q-#4|$SalE2k;pdgvWN@SfWLo__t{)s?^kr1W(i)$m8+p61u^JiLci4v6vF_C9j3ItpPEk!$N(jB) zg#OI!Vpk$V%aUz~+A3p9oy7B2S4$qXD|Oz-2EG$HrEJ6F#-h8)VXe#7O8mC1*_uSJ z?P2DyL3411*v6l|_tOsT7F(4{GUgj_d2}1ba6yK05ZhSsc4_3Znb{@xRDKdJiQRt! z8?Jbc^K3&eySy|vcBb+yr}f6hMKJ`AHgGF7Q?{|yQQ_icjbZuxBR_Yhe0Zmb4e8TLZ<<@^ zoy=!GQqk!m^dFemkseWPDw?B<4HHJ7bm+5`HTZ53j_IPyl{=JzB^3cm^c$pgV@8mn zaf5AiE0i6$6qLd1?r7v|SBdG*m@)d1!9U72PTD)xjNe+^wRz5cXZhCTeb^8ogDZVb zWUeE;>%GIi>4{=X?f!xrPYYA9F@OxJk8O-8*8X)hTlhs+l(~DBd_4U(gt<%bbIzH| jHs&Wk)Nx!Pu^s9+)ZT5JO0PbX8gcv39Gj%8p3MIN!I^L4 literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/8.5/fileHashes/fileHashes.lock b/Maestro/.gradle/8.5/fileHashes/fileHashes.lock index c87f56190c54a26a63b0b3c315e18c1baa480b47..349867a70a2c3901cfee32d7387004bdd44d39e0 100644 GIT binary patch literal 17 UcmZSn{AkUZf={a_FhGC>07`NO1^@s6 literal 17 TcmZSn{AkUZf={a_FhBtSN;(D3 diff --git a/Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin b/Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin new file mode 100644 index 0000000000000000000000000000000000000000..f398a14225580a627a2bf133335f312501c70512 GIT binary patch literal 19075 zcmeI(`%6<{90u?+(IiW}fTiRm&GM3x*CI1VrKDC^x`iecrmf7zyySiAFw88}Fr8&y zE3qQPAepIU8A)DdUS?i?sAguy(uhza9k#LaCVBb`;yG}3UY_&t<-DI?$LmW`riM%O zMJ-<@%S)^v009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5cppNxT=llX*Of(q@`XM zBvX{jTGhhnn)cn;GIC{C^-WakReC#;(=m{y8MC6vgsNU#_#F``buf&sWH+ z!u@JAd0+&|oA`C?-EJcsdQKh5d*#ECUyqtr()k{ePgrE^O$q9lpywa?lPf30uZ65{ zbYDU8+5V-Tram7Rx}QMupAN>^dED;{biP1xEsOoD`gO)mYw|z~k~`EKDCBfH-=^nB zlHA#)Ro;F6^EBOOlib(HtVJd-+Dp$LC3)~O?GaI!cL+VFljOXpfz=|X5h2~zCwWqI z*OrD?wgNgYAvt+c6zjg`9eyDI0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=8Uc6J!%TG>sc*xRUoLLE9^Vos&Q&~j zw(*v#Ld(A!ha1JA+}R|>OlYk1xYfOGW+VMa;#B*F^n;=A+_yg6<@SNucp-c*^=wWF zi`gd{s!vVMWHyXrWR?0?$_JX}j)mBdEp;&)JFN#L1^n$<7v^+h1g`$!%*LaN^~0AZ zqs#*&v$uxg%X*j%%eL|PHj~NGyuwSKZ*Bb4XCqeZw(ri>TC+Dp%J@Y|rucDc8MD#- z(Ll1P%vQWO7=C8>NqZKv5l78Pm0asQ55wkszOUpVv%#8|?_e3+EUmWh()F-otzkBF zc*Vw5yvHz@oa;RG4>3R2#!rpWQx6X1j`tP>PZz0Y{03xEg=qi) literal 0 HcmV?d00001 diff --git a/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock index 43d9fea3d70f0b43ed19e5652e072790a4a7c1e1..ab83b02f9cda0bf83446def7af9b5ba62b873440 100644 GIT binary patch literal 17 UcmZQxu*C4{oAawI86ZFc06q}~1ONa4 literal 17 UcmZQxu*C4{oAawI86bcW06qEy?EnA( diff --git a/Maestro/.gradle/buildOutputCleanup/outputFiles.bin b/Maestro/.gradle/buildOutputCleanup/outputFiles.bin new file mode 100644 index 0000000000000000000000000000000000000000..dfccc0d777fb7fd330bf472c7156fb88c6c688c7 GIT binary patch literal 18875 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 literal 0 HcmV?d00001 diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java new file mode 100644 index 00000000..b6e6e255 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java @@ -0,0 +1,31 @@ +package com.github.gilesi.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class ConfigurationUtils { + public static Xpp3Dom getDomValueObject(String name, String value) { + Xpp3Dom domValue = new Xpp3Dom(name); + domValue.setValue(value); + return domValue; + } + + public static Xpp3Dom getDomArrayObject(String arrayName, String name, String[] values) { + Xpp3Dom valuesDom = new Xpp3Dom(arrayName); + for (String val : values) { + addStringValueIfNotEmpty(valuesDom, name, val); + } + return valuesDom; + } + + public static void addStringValueIfNotEmpty(Xpp3Dom config, String name, String value) { + if (value != null && !value.isEmpty()) { + config.addChild(getDomValueObject(name, value)); + } + } + + public static void addStringArrayValueIfNotEmpty(Xpp3Dom config, String arrayName, String name, String[] values) { + if (values != null && values.length > 0) { + config.addChild(getDomArrayObject(arrayName, name, values)); + } + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java new file mode 100644 index 00000000..cb34d36e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java @@ -0,0 +1,7 @@ +package com.github.gilesi.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public interface IPluginConfiguration { + Xpp3Dom serialize(); +} diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java new file mode 100644 index 00000000..5c234dc7 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java @@ -0,0 +1,157 @@ +package com.github.gilesi.buildsystem.configuration.maven; + +import org.apache.maven.model.Build; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PomHelper { + + private static final String SUREFIRE_VERSION = "3.0.0-M5"; + private static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; + private static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; + + public static Model readPomFile(String pomFilePath) throws IOException, XmlPullParserException { + MavenXpp3Reader pomReader = new MavenXpp3Reader(); + Path pomPath = Path.of(pomFilePath); + InputStream pomStream = Files.newInputStream(pomPath); + Model pomModel = pomReader.read(pomStream); + pomModel.setPomFile(new File(pomFilePath)); + pomStream.close(); + return pomModel; + } + + private static void writePomFile(Model pomModel, String pomFilePath) throws IOException { + MavenXpp3Writer pomWriter = new MavenXpp3Writer(); + FileWriter pomWriteStream = new FileWriter(pomFilePath); + pomWriter.write(pomWriteStream, pomModel); + pomWriteStream.close(); + } + + private static boolean doesBuildContainPluginGroupId(Build bld, String groupId) { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static boolean doesModelContainDependencyGroupId(Model pomModel, String groupId) { + for (Dependency plg : pomModel.getDependencies()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static Plugin getPluginByGroupId(Build bld, String groupId) throws FileNotFoundException { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return plg; + } + } + throw new FileNotFoundException(); + } + + private static Xpp3Dom buildSureFireConfiguration() { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + return sureFireConfiguration.serialize(); + } + + private static Xpp3Dom buildSureFireConfiguration(String argLine) { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + sureFireConfiguration.setArgLine(argLine); + return sureFireConfiguration.serialize(); + } + + private static Plugin getSureFirePlugin() { + return buildPlugin(SUREFIRE_GROUPID, SUREFIRE_ARTIFACTID, SUREFIRE_VERSION); + } + + private static Dependency buildDependency(String groupId, String artifactId, String version) { + Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + return dependency; + } + + private static Plugin buildPlugin(String groupId, String artifactId, String version) { + Plugin plugin = new Plugin(); + plugin.setGroupId(groupId); + plugin.setArtifactId(artifactId); + plugin.setVersion(version); + return plugin; + } + + private static Plugin buildSureFirePlugin() { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static Plugin buildSureFirePlugin(String argLine) { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(argLine); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static void removeExistingPlugin(Build bld, String groupId) throws FileNotFoundException { + // Get rid of all previous instances of the plugin in case one already exists + while (doesBuildContainPluginGroupId(bld, groupId)) { + bld.removePlugin(getPluginByGroupId(bld, groupId)); + } + } + + private static void removeExistingSureFirePlugins(Build bld) throws FileNotFoundException { + removeExistingPlugin(bld, SUREFIRE_GROUPID); + } + + public static void addSureFire(String pomFilePath) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } + + public static void addSureFire(String pomFilePath, String argLine) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(argLine); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java new file mode 100644 index 00000000..05d24c23 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java @@ -0,0 +1,103 @@ +package com.github.gilesi.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class SureFirePluginConfiguration implements IPluginConfiguration { + private int forkCount = 1; + private boolean reuseForks = false; + private String argLine = "-Xmx2G -XX:MaxMetaspaceSize=2G"; + private String parallel = "methods"; + private int threadCount = 1; + private String forkedProcessTimeoutInSeconds = "40"; + private String forkedProcessExitTimeoutInSeconds = "40"; + private String parallelTestsTimeoutInSeconds = "30"; + private String parallelTestsTimeoutForcedInSeconds = "30"; + + public int getForkCount() { + return forkCount; + } + + public void setForkCount(int forkCount) { + this.forkCount = forkCount; + } + + public int getThreadCount() { + return threadCount; + } + + public void setThreadCount(int threadCount) { + this.threadCount = threadCount; + } + + public String getArgLine() { + return argLine; + } + + public void setArgLine(String argLine) { + this.argLine = argLine; + } + + public String getForkedProcessExitTimeoutInSeconds() { + return forkedProcessExitTimeoutInSeconds; + } + + public void setForkedProcessExitTimeoutInSeconds(String forkedProcessExitTimeoutInSeconds) { + this.forkedProcessExitTimeoutInSeconds = forkedProcessExitTimeoutInSeconds; + } + + public String getForkedProcessTimeoutInSeconds() { + return forkedProcessTimeoutInSeconds; + } + + public void setForkedProcessTimeoutInSeconds(String forkedProcessTimeoutInSeconds) { + this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds; + } + + public String getParallelTestsTimeoutForcedInSeconds() { + return parallelTestsTimeoutForcedInSeconds; + } + + public void setParallelTestsTimeoutForcedInSeconds(String parallelTestsTimeoutForcedInSeconds) { + this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds; + } + + public String getParallelTestsTimeoutInSeconds() { + return parallelTestsTimeoutInSeconds; + } + + public void setParallelTestsTimeoutInSeconds(String parallelTestsTimeoutInSeconds) { + this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds; + } + + public String getParallel() { + return parallel; + } + + public void setParallel(String parallel) { + this.parallel = parallel; + } + + public boolean getReuseForks() { + return reuseForks; + } + + public void setReuseForks(boolean reuseForks) { + this.reuseForks = reuseForks; + } + + public Xpp3Dom serialize() { + Xpp3Dom config = new Xpp3Dom("configuration"); + + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkCount", Integer.toString(forkCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "reuseForks", Boolean.toString(reuseForks)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "argLine", argLine); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallel", parallel); + ConfigurationUtils.addStringValueIfNotEmpty(config, "threadCount", Integer.toString(threadCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessTimeoutInSeconds", forkedProcessTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessExitTimeoutInSeconds", forkedProcessExitTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutInSeconds", parallelTestsTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutForcedInSeconds", parallelTestsTimeoutForcedInSeconds); + + return config; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java b/Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java new file mode 100644 index 00000000..84f98ee5 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java @@ -0,0 +1,247 @@ +package com.github.gilesi.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class ConsoleLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The threshold used to filter messages. + */ + private int threshold; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public ConsoleLogger() { + this(INFO); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param threshold The threshold for the logger. + */ + public ConsoleLogger(int threshold) { + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + String logLevel = "INFO"; + + switch (level) { + case (DEBUG) -> logLevel = "DEBUG"; + case (INFO) -> logLevel = "INFO"; + case (WARN) -> logLevel = "WARN"; + case (ERROR) -> logLevel = "ERROR"; + case (FATAL) -> logLevel = "FATAL"; + default -> { + } + } + + buffer.append("[Maven] "); + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + System.out.printf("[%s] %s%n", logLevel, buffer); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java b/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java new file mode 100644 index 00000000..89f9b27c --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java @@ -0,0 +1,57 @@ +package com.github.gilesi.runners.maven; + +import org.apache.maven.shared.invoker.*; + +import java.io.File; +import java.io.InputStream; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +public class ProjectRunner { + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath) throws MavenInvocationException { + File pomFile = new File(pomFilePath); + + File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); + + ConsoleLogger logger = new ConsoleLogger(); + + Properties properties = new Properties(); + pomProperties.forEach(p -> properties.put(p, true)); + + InvocationRequest request = new DefaultInvocationRequest(); + request.setShellEnvironmentInherited(false); + request.setPomFile(pomFile); + request.setGoals(pomGoals); + request.setProperties(properties); + request.setBatchMode(batchMode); + request.setBaseDirectory(projectDirectory); + request.setOutputHandler(logger); + request.setInputStream(InputStream.nullInputStream()); + request.setErrorHandler(logger); + + if (userSettingsFilePath != null && !userSettingsFilePath.isEmpty() && !userSettingsFilePath.isBlank()) { + Path pa = Path.of(userSettingsFilePath); + if (Files.exists(pa) && Files.isRegularFile(pa)) { + request.setUserSettingsFile(new File(userSettingsFilePath)); + } + } + + Invoker invoker = new DefaultInvoker(); + invoker.setLogger(logger); + invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); + InvocationResult result = invoker.execute(request); + return result.getExitCode(); + } + + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath) throws MavenInvocationException { + String pomFilePath = repositoryDirectory + File.separator + "pom.xml"; + ArrayList goals = new ArrayList<>(); + goals.add(goal); + + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath) == 0; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java new file mode 100644 index 00000000..1231b0e0 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java @@ -0,0 +1,17 @@ +package com.github.gilesi.testing.surefire; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; + +public class Error { + @JacksonXmlProperty(isAttribute = true, localName = "message") + public String Message; + + @JacksonXmlProperty(isAttribute = true, localName = "type") + public String Type; + + @JacksonXmlText + @JacksonXmlCData + private String Data; +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java new file mode 100644 index 00000000..cf6e273b --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java @@ -0,0 +1,87 @@ +package com.github.gilesi.testing.surefire; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Objects; +import java.util.regex.Pattern; + +public class FileUtils { + public static void deleteDirectory(File fi) { + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + file.delete(); + } + fi.delete(); + } + + public static void deleteDirectoryIfExists(String path) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + deleteDirectory(new File(path)); + } + } + + public static ArrayList enumerateDirectory(File fi, String wildcard, boolean recursive) { + ArrayList files = new ArrayList<>(); + Pattern pattern = Pattern.compile(wildcard); + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory() && recursive) { + files.addAll(enumerateDirectory(file, wildcard, true)); + } else { + if (pattern.matcher(file.getName()).matches()) { + files.add(file.getPath()); + } + } + } + return files; + } + + public static ArrayList enumerateFiles(String path, String wildcard, boolean recursive) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + return enumerateDirectory(new File(path), wildcard, recursive); + } + return new ArrayList<>(); + } + + public static void ensureDirectoryExistsAndIsEmpty(String path) throws IOException { + Path pa = Path.of(path); + deleteDirectoryIfExists(path); + Files.createDirectory(pa); + } + + public static void backupFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(filePath)) { + return; + } + + if (Files.exists(backupFilePath)) { + Files.delete(backupFilePath); + } + + Files.copy(filePath, backupFilePath); + } + + public static void restoreFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(backupFilePath)) { + return; + } + + if (Files.exists(filePath)) { + Files.delete(filePath); + } + + Files.move(backupFilePath, filePath); + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java new file mode 100644 index 00000000..ccc3a875 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java @@ -0,0 +1,13 @@ +package com.github.gilesi.testing.surefire; + +public class Properties { + private Property[] property; + + public Property[] getProperty() { + return property; + } + + public void setProperty(Property[] value) { + this.property = value; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java new file mode 100644 index 00000000..8108f616 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java @@ -0,0 +1,22 @@ +package com.github.gilesi.testing.surefire; + +public class Property { + private String name; + private String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java new file mode 100644 index 00000000..e2d98671 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java @@ -0,0 +1,62 @@ +package com.github.gilesi.testing.surefire; + +public class ReportItem { + public String Name; + public String Version; + private String TestName; + private String TestResult; + private String ErrorDetails; + + public ReportItem(String projectName, String projectCommit, Testcase testcase) { + this.TestName = testcase.ClassName + "." + testcase.Name; + this.TestResult = (testcase.Error != null || testcase.Failure != null) ? "Red" : "Green"; + this.ErrorDetails = testcase.Error != null ? testcase.Error.Message : ""; + this.Name = projectName; + this.Version = projectCommit; + } + + public String getName() { + return Name; + } + + public void setName(String name) { + Name = name; + } + + public String getVersion() { + return Version; + } + + public void setVersion(String version) { + Version = version; + } + + public String getTestName() { + return TestName; + } + + public void setTestName(String testName) { + TestName = testName; + } + + public String getTestResult() { + return TestResult; + } + + public void setTestResult(String testResult) { + TestResult = testResult; + } + + public String getErrorDetails() { + return ErrorDetails; + } + + public void setErrorDetails(String errorDetails) { + ErrorDetails = errorDetails; + } + + @Override + public String toString() { + return "\"" + Name + "\",\"" + Version + "\",\"" + TestName + "\",\"" + TestResult + "\",\"" + ErrorDetails + "\""; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java new file mode 100644 index 00000000..a8383785 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java @@ -0,0 +1,49 @@ +package com.github.gilesi.testing.surefire; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class SurefireHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { + String sureFireReportsLocation = targetLocation + File.separator + "surefire-reports"; + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + System.out.println("Report XML Count: " + reportXmls.size()); + System.out.println("Report XML Location: " + sureFireReportsLocation); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, String pomFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path pomFilePath = Path.of(pomFileLocation); + String targetLocation = "%s%starget".formatted(pomFilePath.getParent().toAbsolutePath(), File.separator); + + if (!Files.isDirectory(Path.of(targetLocation))) { + System.out.printf("Skipping %s because it does not appear to be a maven project. Issue in data set?%n", targetLocation); + } else { + System.out.printf("Handling %s...%n", targetLocation); + + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + System.out.println(e); + } + } + + return reportItems; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java new file mode 100644 index 00000000..bc798f1e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java @@ -0,0 +1,23 @@ +package com.github.gilesi.testing.surefire; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + +public class Testcase { + @JacksonXmlElementWrapper(localName = "error") + public Error Error; + + @JacksonXmlElementWrapper(localName = "failure") + public Error Failure; + + @JacksonXmlElementWrapper(localName = "name") + public String Name; + + @JacksonXmlElementWrapper(localName = "classname") + public String ClassName; + + @JacksonXmlElementWrapper(localName = "time") + public String Time; + + @JacksonXmlElementWrapper(localName = "system-out") + public String SystemOut; +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java new file mode 100644 index 00000000..7772be96 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java @@ -0,0 +1,103 @@ +package com.github.gilesi.testing.surefire; + +public class Testsuite { + private Properties properties; + private Testcase[] testcase; + private String xmlnsXsi; + private String xsiNoNamespaceSchemaLocation; + private String version; + private String name; + private String time; + private String tests; + private String errors; + private String skipped; + private String failures; + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties value) { + this.properties = value; + } + + public Testcase[] getTestcase() { + return testcase; + } + + public void setTestcase(Testcase[] value) { + this.testcase = value; + } + + public String getXmlnsXsi() { + return xmlnsXsi; + } + + public void setXmlnsXsi(String value) { + this.xmlnsXsi = value; + } + + public String getXsiNoNamespaceSchemaLocation() { + return xsiNoNamespaceSchemaLocation; + } + + public void setXsiNoNamespaceSchemaLocation(String value) { + this.xsiNoNamespaceSchemaLocation = value; + } + + public String getVersion() { + return version; + } + + public void setVersion(String value) { + this.version = value; + } + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getTime() { + return time; + } + + public void setTime(String value) { + this.time = value; + } + + public String getTests() { + return tests; + } + + public void setTests(String value) { + this.tests = value; + } + + public String getErrors() { + return errors; + } + + public void setErrors(String value) { + this.errors = value; + } + + public String getSkipped() { + return skipped; + } + + public void setSkipped(String value) { + this.skipped = value; + } + + public String getFailures() { + return failures; + } + + public void setFailures(String value) { + this.failures = value; + } +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java new file mode 100644 index 00000000..673fc2a6 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java @@ -0,0 +1,13 @@ +package com.github.gilesi.testing.surefire; + +public class Testsuites { + private Testsuite[] testsuites; + + public Testsuite[] getTestsuites() { + return testsuites; + } + + public void setTestsuites(Testsuite[] value) { + this.testsuites = value; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java new file mode 100644 index 00000000..517b23dc --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java @@ -0,0 +1,31 @@ +package com.github.gilesi.testing.surefire; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; + +import java.io.File; +import java.io.IOException; + +public class XmlParser { + + private static final XmlMapper mapper = XmlMapper + .builder() + .defaultUseWrapper(false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + public static Testsuite deserializeTestsuite(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuite.class); + } + + public static Testsuites deserializeTestsuites(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuites.class); + } + + public static void serialize(String XmlPath, Object obj) throws IOException { + File fi = new File(XmlPath); + mapper.writeValue(fi, obj); + } +} From 0b0fbccf57c6e2f62df7ee12ae25df29cefd8e55 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 15:30:57 +0200 Subject: [PATCH 105/244] Git ignore for Maestro --- Maestro/.gitignore | 39 ++++++++++++++++++++++ Maestro/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes 2 files changed, 39 insertions(+) create mode 100644 Maestro/.gitignore create mode 100644 Maestro/gradle/wrapper/gradle-wrapper.jar diff --git a/Maestro/.gitignore b/Maestro/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/Maestro/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/Maestro/gradle/wrapper/gradle-wrapper.jar b/Maestro/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 Date: Mon, 27 May 2024 15:32:09 +0200 Subject: [PATCH 106/244] Drop files from .gitignore --- Maestro/.gradle/8.5/checksums/checksums.lock | Bin 17 -> 0 bytes Maestro/.gradle/8.5/checksums/md5-checksums.bin | Bin 21647 -> 0 bytes .../.gradle/8.5/checksums/sha1-checksums.bin | Bin 28163 -> 0 bytes .../dependencies-accessors.lock | Bin 17 -> 0 bytes .../8.5/dependencies-accessors/gc.properties | 0 .../8.5/executionHistory/executionHistory.bin | Bin 39978 -> 0 bytes .../8.5/executionHistory/executionHistory.lock | Bin 17 -> 0 bytes Maestro/.gradle/8.5/fileChanges/last-build.bin | Bin 1 -> 0 bytes Maestro/.gradle/8.5/fileHashes/fileHashes.bin | Bin 20247 -> 0 bytes Maestro/.gradle/8.5/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes .../8.5/fileHashes/resourceHashesCache.bin | Bin 19075 -> 0 bytes Maestro/.gradle/8.5/gc.properties | 0 .../buildOutputCleanup/buildOutputCleanup.lock | Bin 17 -> 0 bytes .../.gradle/buildOutputCleanup/cache.properties | 2 -- .../.gradle/buildOutputCleanup/outputFiles.bin | Bin 18875 -> 0 bytes Maestro/.gradle/vcs-1/gc.properties | 0 .../compileJava/previous-compilation-data.bin | Bin 27144 -> 0 bytes 17 files changed, 2 deletions(-) delete mode 100644 Maestro/.gradle/8.5/checksums/checksums.lock delete mode 100644 Maestro/.gradle/8.5/checksums/md5-checksums.bin delete mode 100644 Maestro/.gradle/8.5/checksums/sha1-checksums.bin delete mode 100644 Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock delete mode 100644 Maestro/.gradle/8.5/dependencies-accessors/gc.properties delete mode 100644 Maestro/.gradle/8.5/executionHistory/executionHistory.bin delete mode 100644 Maestro/.gradle/8.5/executionHistory/executionHistory.lock delete mode 100644 Maestro/.gradle/8.5/fileChanges/last-build.bin delete mode 100644 Maestro/.gradle/8.5/fileHashes/fileHashes.bin delete mode 100644 Maestro/.gradle/8.5/fileHashes/fileHashes.lock delete mode 100644 Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin delete mode 100644 Maestro/.gradle/8.5/gc.properties delete mode 100644 Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 Maestro/.gradle/buildOutputCleanup/cache.properties delete mode 100644 Maestro/.gradle/buildOutputCleanup/outputFiles.bin delete mode 100644 Maestro/.gradle/vcs-1/gc.properties delete mode 100644 Maestro/build/tmp/compileJava/previous-compilation-data.bin diff --git a/Maestro/.gradle/8.5/checksums/checksums.lock b/Maestro/.gradle/8.5/checksums/checksums.lock deleted file mode 100644 index 93c42fe2fd7bdde7d4087406c67cf8579785a002..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 VcmZQh-E`bBYlY5X1~6b`1OPMl1SS9g diff --git a/Maestro/.gradle/8.5/checksums/md5-checksums.bin b/Maestro/.gradle/8.5/checksums/md5-checksums.bin deleted file mode 100644 index 6402e132f9db7c139d785f9f13a64480d3441ca1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 21647 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 b>+P#xJ1(z}(A>ix+YF5=p+K819Ql6%M#(9{ diff --git a/Maestro/.gradle/8.5/checksums/sha1-checksums.bin b/Maestro/.gradle/8.5/checksums/sha1-checksums.bin deleted file mode 100644 index 9a4e427ee161a3130804f4dc4784b82e15c9d568..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 28163 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 b{rtFmkPU diff --git a/Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock b/Maestro/.gradle/8.5/dependencies-accessors/dependencies-accessors.lock deleted file mode 100644 index 0273e60edc90a23dc4fd14acab933bc28ecdae61..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZSXID0eb=9#J+3{U_7L>mQr diff --git a/Maestro/.gradle/8.5/dependencies-accessors/gc.properties b/Maestro/.gradle/8.5/dependencies-accessors/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/Maestro/.gradle/8.5/executionHistory/executionHistory.bin b/Maestro/.gradle/8.5/executionHistory/executionHistory.bin deleted file mode 100644 index d7dd66727aefd4935057c0fb699e33fa9fc4a34d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 39978 zcmeHP2YeLO*5BPEfFQcyLqhQh0uK;&cX|OHJgQU^Y0@N24I8$EErC!1DAIcgB27Sw z^xhOAsHi|ddXXBWR}lz;$aiLTHrbF+0^z;z{f3_=li7RE{O|vsd(OG%?41S%L!|kE z_Ro;{uSDjhex);@GoUk|GoUk|GoUk|GoUk|GoUk|GoUk|GoUk|GoUk|GoUk|GoUk| zGw}a~fi^IZ!hyj=RyQdZulFz*kXPZtXzFtM#^k}_5rK~z*A3PWg1_N@)xc-^Pn`js z0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz z0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mz0i6Mzf&9P#ZZNbu3I88b{-2T< z>&Cb^d#`SBVqC9yN$4h!a!-4l-zNpIhKYuiZcnT=*29So$;!pstv=4%&1)6h&UicA zY04#V^#j*24J5(s;e3*4ZfJ5vtTXMrNBArKcx1~@(Z)QHQg&oq=F>dI3@IVV;u4%z zpWE#ax^i}x)$a019vA1ZHjre_@9?z_ei8!LlMQ8ZsCcVW@^K>PD20 z6FfIZ!Bz+7iuH4`Qd`O6wYyyVR=EQr&F7{zF0{&I zFg7t1Ob9%zXFN=BiJ3VAQ>M6yE8g$(7Bj4V@}sj1UhS7{Aj_WgAgkRO?~t65%g6bE zi?A^Xl1p@ZEM8DbyKEPhKT*K{p3V7B#26S<*g(#eI6`Tx&3vILAtWnntZC+F!`n7& z*{Vs@`!N_g-02qm4$fouB^EQR3+a-f?#e3A6rn{%+g3nf$l9#<$Ij@~ip$=6yUh>x z-ac8o+>}hIux@0@qxO`dIbT=f5O=&X8=wYjLLQgh3TPG}D$qLQVGkREiJHKm{qWTF z#CnU23f>hZ-XCksXr%tB2`y$=@K^{9l&)IaZ0h$#mIr99tg86tQi9|#j14xBT!LG) zyJ8K=8Fza6B$u*28`wQw!-U{%nX@~hTn#-Qx5qd#${)!3`_;@qgD6{Ef z*qagh98I!S>M03+AICc+!_=HU2c1w!&fviA5+fUKmAB zr^6b@3EjMI7burUvT1)<6dTUlU7`)z6IR4VqBze894<>7f|HmaNxVde2+vCrM`AR` z;{+}WD3?uu@<0#(Pw|AAn>WKwr+Vjg!teCGzGiIlJ=3K;2hO=%?tnG)2C>UL&B;72 zumU4-IE8a?0avVma5PHOf{e+$h*N9^_7E9a;HMt_?q8N848X=LP&u|36$k9nPGUE$7oq#5kVAbS&}gt!wH5)Gl!8?N|uq_ zsnBNd%~ztQwclU)?>2w`S;}-QFGi9@gVaAX?IBnZLs^tYMT(Ot0+$d9l~@VoIS&5j zC=Q`$7G=Z?0+h~K0B=6s4|tpjiRO>8zarEp!f`jh>v?YtYzsBjygDe>5)!ODTBK=~rg&P&+S#IZ4uJi8htE0C6Sad~ zS|_pfw3rp9UvdXlnS1b0QdiFJwFV*DygsfcW&y8kBY+pw2DXjHVa7=e164p70pmFg zP@@Pg-~tJJqXZ%_cxFe7+A)A}Xv~IdAJ?f@yZYF#hs<6!xpZy`eT06-JN&VBmx?l= zr6>-|osuYl5M`QV5Q>yg38!dSO%%f693@Z~Cege$^_l%cb+yNZ2A%OD$Hu)LPWET_ z40&KWmwQ5USWF(t>vlk-Y>D@{6YQd@uFA?{QJKJSjvzsAFD#dL^F^qC)RO#PTS~%Myc1G|WB^tBM0cSsq77juv==XJs7YLAf=w4@(K< zc8dF_-X%L7ADnKE`QUctGi6Ns^Mu>rBZKr(pt&T^Av}#U1i?V`BT@vzLI6a=PXgmn zRFoO{VZb2_yDAm$(67epi5qtHtDp4dfsUrrc>+|^Sc}&mAMf_~G`uVUPKyMm#c?Q) zp*TUJ2-pN%pir7*0jm_45lV}Mh41!d%f{e>DE|C-|N}|YMI4U5dOb7x`@enmo7)o*sra{j^P$>LaWxidq zwN7&7oei4&bI9k1mgSLpa2}ss=7b>K1cBo+iGUS@y%D5NBoQG=oEH&Dk9+e?ldla&9>o{_wO$LF5@8%m)F!j{_Txij0WTK?{-r9VCPzpVevy zHLKqdanwZNKYg}~x1QGzK9Y66&mLr*7Dkc=Bm~ravqRN(p|$C>$eM%8uLR+ghO$PWMvk`z)}kcib9G2+#@BUIE}#O3O3XfPScQB zflg|?k6B#q7|tCZU=|k(q)c0}zuZZzZqkocWBQxYatBY*fsCz*HvfTN7Ox~&M7xsT zflaFiasUWuGAob>1pSKPhS-CG9V^RFD8rH>56%)c)C6P!Xj_gVU_Y(x{??nm8t~xD zg|$vQF#g{UN?tSV$urb~JwAvQEVRTipuPl+QV`b3G73o-M8;WgI213jB%}jKlnM8^$gB>mOoG%#eybsILpxpfhfB?5x`(5 z2hj!(Q8bH^42>zVeP}Oo=JaO@-J^21wi{?%{ zw!w5V&v2@##~yBvLsYVCl#-JG#v}%j1s(^F0Fg2Rfe<4?xJmG^geYF-L<*veAleWK zFy$a2fVtG+NMDPElLsD{H@WHZankTSTu^GhKi=(7OC{jbFv^CJJPWB3iXwQ(La?MD zh!P@+5(yDL0)#_MK|sDOV?kvR0qTHJ0n|4PSGL)sHk}>Q;@mI&*BAc7bTjXmhJ3Kw z1r;7kNLEtG2mQaW?g* znqWb#v=zr}f+&D@#aRNj&=3GafQj=00j3KuBfLby<_f}30rEgff2AiVg3>df3d=^^ zdgbFO;@}DiYhQhB;e4yyrEHu*$5ik zJ0y5T9(Ha7j^Q{0X-XMVJ`!xBQ3{t)a9ISEqXcD51$Z2{xyNUNldkT$8|@r0v1Ny_ z+**Hd(VW9!=Um|IL$B3!gTrQ?0p|`b2xDMg1r+BPnUy$T5EVEQtSc@tq5S}uW}zy5 zvmtI^*FAF+Bd(@yZW}Siv^&=m9E?byj-9|kY@z(bNGl3UT=cl@qKy|hj%Nu9pl~7v z4hkm`NI%m!8(?qd$iFV`x{$cI-lTf-`RT)xa+@v>37eGg z#41B62r7kMTb$Pec^X*9h!q3O66hhrE0`FLp=m(Iiv*>(PS8t|0zw%XfwaEb3l=c+ z3IJ@F>KpVxzB;>Q*%PJCyBc(QmV5}rMFJ$nWe?|+z!!D1X*VGItklpf-TjA^ib41YAT=lHe$e7er+XMzK5#Tlbtqs1b=a`FBg)r{8MfoOE8SwkV~@ z^s1)I&pi2(QUrxesY|k{moe&fOy-JG>sPQ(hjuy+<+bTtfUc_N;K2ER&er0h^C zrj!WA6%xYW6d>dJNI?pGZOhm(@smM=KR=O_lzM65xu`+IOfN~H*1Vv z90ghP-jte6H(fZphpO6e;@uN=fBr1Tntz;hfopc;m6Jjp%UPqeE&gRF#+t1a4mKXK z_tgj0@b-n<{*uxTIbu1dxp$7RO*cm&8od9!t=NQYi|7h zlrHtgtnT#Yz2o%w>zBxvqWo%(u(kSZ_sY>bwv1R5wtd#670;k1p|#fRrNyWLD|(@b@9mh1){0x<_C+uXw+e4Y(6Zynpa=BF!IXEKf6C@+IiPc zg%f|yA0=0F&(d#o8EUK4sPTKl7xCleiTSeNY96t8*X)UuaZB}1G4Wg5v|N(!%dO_E zF~u*FH}-C7Q>Cr7_wBS>dAE$RR7&%**lO<7Eb3ON>&T>iec!mhX?OWuFJ-CK9M-UP zjde?p4*uuzGIx2~xqHtZ4{HU(jH+K=7Fx}BFZHiBKPPRu{C%Rukx$C3<_KTUps!GS*IJ` zslEcvHSt|eD)Wf{i@V!xhLbq zZe}Gt+T#`^uh;E~hQqRkDZ!JsyxZ;b`aE2`dRSLENNX4${48)7SG_k1PKv=f;a2ML zTyL>k#>}&}@7aB}Smju)-PVGWK$hF)^(bE?w!74?w&LeGq4(M-Ut@;KeF7I|j=Atjx$&N_+b0jc^sVKcTB*iu#ypdr z{$j_}Bw9VjmSt$#sG?UVw`+4N;nLN1@u?rZJ%77#$1{xTk@7FU*l|U>osA_&yyVda z)B6wq`7LF7H*a?wuePx!cG9@{83vP8=-)4P1g+o*dn3C?dh`Ts?sFoQ+|aXqxBC6} zFG=i?WZe4f5PR+hZGMXQMzQ=m} zE*HEPBy-`y85^m&J2o~$A=vVJ*N$>h{d~6zc5|bRI~rGJNAn~pc?uFNq4GujmMU_M zvgOlC9vpI3EZb!5tttCGpYM1w$m~)MKOd7mu$^#F(B=holtCSB>Kh_7eE&>IOHV0r z_VCcrgUAE#GnLT_?sa^Z;d;VIRl)NhObK{DqfR|Os zb53!#!NdH3QS#ZPpzqjz`t`LHKChVk*WQk?2iI@um(vtKNy^bY=1~KgsLgVB!`0OL zZORWN%o|2J8?0SqT>ca^W|5KCEVhJ0iXLARaMT(^WBMuD`1<5YUsTyvkf>}d@>DE7 zB;|A-v#3~BWyLh+JT3@vG^7#ogyJ*gN;4*mOMQ21jn=J<>z;zloJ8gIq_>8JF2LJP zG@MJ8mA%JRKDG0kI$g2CQM>(5HR)Mo!S&h{7H&b6i`-R_g@zUz+rna|OH`yRHi4@t>u9@{w`(VWMd;Rzd} ztIw>qpI^{oaN5pMEw7AwDju^6F)n=iz}wtqT$$=89oHr-ZZ;yJNgw{Kxpjx%o5uZG zWZl;4=iN1%rTD`qiYg^)>0;MF=xT&~9YhJmoW41)uK zzVchy5g0~*|AocYl#>rVi;(%9Cr5nuC*qSL1zOQ$@TjiZ~!}bpCzb*an z?tAE+qQ)sXM!QR&5mhdDOXO) zquXAy?m2za54YC+*>HV_)TTR6%)6IXaq{Y-aO-f{qRlJpU(vo-QkhC=V@jPd4p*Zx zP5j>xn{Td9Zc*uYcWcv$VW0eaz#V1q^TQ28v}h?v-~=ErBn@EvzVOtn zJ8%5^SXKFl(QwO^Qik|tYpqXPJCGq`VmnVQ4UXF^&ktFPi+tg~#nO)H>2~ z_=pYOeS?l#m#gx3M;OOsh5=er%V%jLy<=}gCQX{1^2>0c-)^<(vU0|;AwFGeyKVpS zKJ)5a$2)wJe)vGaqdQlsZRbT8M`yT2t!1-~wSO8a?|m;Oy{+dX=V13LwdIWn4h!&bA9%A5pI zM-A(B9i5jxmab5s#HsJqroWnDTE|se*Lh3xpV}2fk4KgdrxdlF@ZlQUZ-(@?1=qF~ zs=XR>1a8eKIIDZvZS5B85uX2X}KOQVzcyJ};PQh?QUyp}hYwkYI@N``{IVnFeX^ z;{%3(Maqz23*;@l@cs1QYp_5W0?Cg|dj)u+_NN?ZhmSAzX(4<$*>LR0@aaK3T_q0Q zf$}hnC+yH31tTCV#8l?==+ELkQi9#>_tuAV8}`8Yyaw=6EaUE{8N1IJucTR&_i8p( z402GIdJ067roPV13hy&BnCYPh->ey(PTsgwu~@HnN0R;TE2d@0K4Z8M-tBqj{{RRm BS&;w$ diff --git a/Maestro/.gradle/8.5/executionHistory/executionHistory.lock b/Maestro/.gradle/8.5/executionHistory/executionHistory.lock deleted file mode 100644 index 8cd3b33efec3baed309aad2c042899bcd9bdf7b2..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQxyrIuLApFon1_)pQ05(wsY5)KL diff --git a/Maestro/.gradle/8.5/fileChanges/last-build.bin b/Maestro/.gradle/8.5/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/Maestro/.gradle/8.5/fileHashes/fileHashes.bin b/Maestro/.gradle/8.5/fileHashes/fileHashes.bin deleted file mode 100644 index 276369a0c6c6de5feed740468747f46fab4e518e..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 20247 zcmeI3do)ye9Kf%^c#CS79!`m^ydR;1$|}mxP^??Tcn1wHEKQf&i(y5J;!y=XXf+!-TRq){bPPE6vfvX z#~bx|<9$AaBPaj`pa2wr0#E=7KmjNK1)u;FfC5ke3P1rU00p1`6o3Ly;Qvy+OwRBJO#S@J63@Qxoebx|ehls1V+wcsC*8MKl>dobU%u$@Yd?H-pjp-J%Is zNqn1L;IU^f;z9$$)kQwTi3$2uhzqt7KK&&(rB3TqG2$K;gzNh|-U;;#s6^b;i*VB! zYbH9HX&=VpCw<~?`zvhoBa{($b0*wue(kiCPC59xJk}BJp}Dcw*2@cb5Hu4mjBTmB zn>qUko>!0Xm7SP?8Sv57<6J(uuryiFZbW#5`n6?WAF5l0 zxX_pI=&XTI*NT#Bh`T-f#E*|go^2ZvBksAM@Eyvc2@N4OoACI9gp=PCB_D`hgFO_0 z0#E=7KmjNK1)u;FfC5ke3P1rU00p1`6o3Ly017|>C;$bZ02F`%Pyh-*0Vn_kpa2wr z0#E=7KmjNK1)u;FfC5n9zbi109@>ch(U<;csfij5)C20MUln6xCT+R(B}K`lUz<=f zNWVyL3QOpn`M-_q>jQbMReFZcGkn+pV@HK@0V8p zoz`uPp~ZWG461@{Y*#&-tLwf{qcF>Q?LnJ~m(W=Sze0xQLAJ5KzG&~*vD5r`?x>w> zd_*T>%=5$Ftf#(b8!=PlG5LR%ht*r(3DyUO|SkbajP{q3`=DTfMTa`SFa|W&v_xQyIf$8_K8{~&Kr*Vz!-XSMj3&UqwgA7!|!xvu2+9iU+tQ@Ez=fO zbTEdlCcbhxF53{_OpD_#d2QHKm-|&q-#4|$SalE2k;pdgvWN@SfWLo__t{)s?^kr1W(i)$m8+p61u^JiLci4v6vF_C9j3ItpPEk!$N(jB) zg#OI!Vpk$V%aUz~+A3p9oy7B2S4$qXD|Oz-2EG$HrEJ6F#-h8)VXe#7O8mC1*_uSJ z?P2DyL3411*v6l|_tOsT7F(4{GUgj_d2}1ba6yK05ZhSsc4_3Znb{@xRDKdJiQRt! z8?Jbc^K3&eySy|vcBb+yr}f6hMKJ`AHgGF7Q?{|yQQ_icjbZuxBR_Yhe0Zmb4e8TLZ<<@^ zoy=!GQqk!m^dFemkseWPDw?B<4HHJ7bm+5`HTZ53j_IPyl{=JzB^3cm^c$pgV@8mn zaf5AiE0i6$6qLd1?r7v|SBdG*m@)d1!9U72PTD)xjNe+^wRz5cXZhCTeb^8ogDZVb zWUeE;>%GIi>4{=X?f!xrPYYA9F@OxJk8O-8*8X)hTlhs+l(~DBd_4U(gt<%bbIzH| jHs&Wk)Nx!Pu^s9+)ZT5JO0PbX8gcv39Gj%8p3MIN!I^L4 diff --git a/Maestro/.gradle/8.5/fileHashes/fileHashes.lock b/Maestro/.gradle/8.5/fileHashes/fileHashes.lock deleted file mode 100644 index 349867a70a2c3901cfee32d7387004bdd44d39e0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZSn{AkUZf={a_FhGC>07`NO1^@s6 diff --git a/Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin b/Maestro/.gradle/8.5/fileHashes/resourceHashesCache.bin deleted file mode 100644 index f398a14225580a627a2bf133335f312501c70512..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19075 zcmeI(`%6<{90u?+(IiW}fTiRm&GM3x*CI1VrKDC^x`iecrmf7zyySiAFw88}Fr8&y zE3qQPAepIU8A)DdUS?i?sAguy(uhza9k#LaCVBb`;yG}3UY_&t<-DI?$LmW`riM%O zMJ-<@%S)^v009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=5cppNxT=llX*Of(q@`XM zBvX{jTGhhnn)cn;GIC{C^-WakReC#;(=m{y8MC6vgsNU#_#F``buf&sWH+ z!u@JAd0+&|oA`C?-EJcsdQKh5d*#ECUyqtr()k{ePgrE^O$q9lpywa?lPf30uZ65{ zbYDU8+5V-Tram7Rx}QMupAN>^dED;{biP1xEsOoD`gO)mYw|z~k~`EKDCBfH-=^nB zlHA#)Ro;F6^EBOOlib(HtVJd-+Dp$LC3)~O?GaI!cL+VFljOXpfz=|X5h2~zCwWqI z*OrD?wgNgYAvt+c6zjg`9eyDI0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_ z009U<00Izz00bZa0SG_<0uX=z1Rwwb2tWV=8Uc6J!%TG>sc*xRUoLLE9^Vos&Q&~j zw(*v#Ld(A!ha1JA+}R|>OlYk1xYfOGW+VMa;#B*F^n;=A+_yg6<@SNucp-c*^=wWF zi`gd{s!vVMWHyXrWR?0?$_JX}j)mBdEp;&)JFN#L1^n$<7v^+h1g`$!%*LaN^~0AZ zqs#*&v$uxg%X*j%%eL|PHj~NGyuwSKZ*Bb4XCqeZw(ri>TC+Dp%J@Y|rucDc8MD#- z(Ll1P%vQWO7=C8>NqZKv5l78Pm0asQ55wkszOUpVv%#8|?_e3+EUmWh()F-otzkBF zc*Vw5yvHz@oa;RG4>3R2#!rpWQx6X1j`tP>PZz0Y{03xEg=qi) diff --git a/Maestro/.gradle/8.5/gc.properties b/Maestro/.gradle/8.5/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/Maestro/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index ab83b02f9cda0bf83446def7af9b5ba62b873440..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQxu*C4{oAawI86ZFc06q}~1ONa4 diff --git a/Maestro/.gradle/buildOutputCleanup/cache.properties b/Maestro/.gradle/buildOutputCleanup/cache.properties deleted file mode 100644 index 2ad95a8e..00000000 --- a/Maestro/.gradle/buildOutputCleanup/cache.properties +++ /dev/null @@ -1,2 +0,0 @@ -#Mon May 27 14:15:12 CEST 2024 -gradle.version=8.5 diff --git a/Maestro/.gradle/buildOutputCleanup/outputFiles.bin b/Maestro/.gradle/buildOutputCleanup/outputFiles.bin deleted file mode 100644 index dfccc0d777fb7fd330bf472c7156fb88c6c688c7..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 18875 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 From 56a140c48028f94046d88b5fff3847d0daeb6a17 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 15:49:15 +0200 Subject: [PATCH 107/244] Cleanup of deps for confgen --- ConfGen/build.gradle | 3 --- 1 file changed, 3 deletions(-) diff --git a/ConfGen/build.gradle b/ConfGen/build.gradle index 159cd1b2..7804bbaa 100644 --- a/ConfGen/build.gradle +++ b/ConfGen/build.gradle @@ -33,9 +33,6 @@ repositories { } dependencies { - implementation 'com.google.guava:guava:33.2.0-jre' - implementation 'fr.inria.gforge.spoon:spoon-core:11.0.1-beta-6' - implementation 'info.picocli:picocli:4.7.6' implementation 'com.github.maracas:roseau:0.0.2-SNAPSHOT' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } From b2e4805adb1d2b0d29b18bddf16b13f4df52001f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 15:53:38 +0200 Subject: [PATCH 108/244] Cleanup --- run-clean-workflow.sh | 0 run-test-workflow.cmd | 15 ++++----------- run-test-workflow.sh | 15 ++++----------- 3 files changed, 8 insertions(+), 22 deletions(-) mode change 100644 => 100755 run-clean-workflow.sh diff --git a/run-clean-workflow.sh b/run-clean-workflow.sh old mode 100644 new mode 100755 diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index bd95e8f5..e3a7a1cd 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -5,6 +5,7 @@ call compile.cmd set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 +mkdir Results\ echo. echo =========================================================== @@ -24,7 +25,7 @@ echo Running ConfGen echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\TestWorkflowConfiguration.xml" "%CD%\Traces.Output" "%CD%\Samples\Gradle\samplelibrary" "%CD%\Samples\Gradle\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\Results\TestWorkflowConfiguration.xml" "%CD%\Results" "%CD%\Samples\Gradle\samplelibrary" "%CD%\Samples\Gradle\sampleclient" echo. @@ -34,7 +35,7 @@ echo =========================================================== echo. copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\Gradle\sampleclient\" -copy "%CD%\TestWorkflowConfiguration.xml" "%CD%\Samples\Gradle\sampleclient\" +copy "%CD%\Results\TestWorkflowConfiguration.xml" "%CD%\Samples\Gradle\sampleclient\" cd Samples\Gradle call .\gradlew.bat sampleclient:test --warning-mode all @@ -49,12 +50,4 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.xml" "%CD%\TestGenerator.Output" - -mkdir Results - -move %CD%\TestWorkflowConfiguration.xml Results\ -move %CD%\Traces.Output\gilesi.instrumentation.log Results\ -move %CD%\Traces.Output\MethodTraces.xml Results\ -move %CD%\Traces.Output\*.xml Results\ -move %CD%\TestGenerator.Output Results\ +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Results\MethodTraces.xml" "%CD%\Results\TestGenerator.Output" \ No newline at end of file diff --git a/run-test-workflow.sh b/run-test-workflow.sh index 32440b52..b5a1fc68 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -3,6 +3,7 @@ sh ./run-clean-workflow.sh sh ./compile.sh +mkdir Results/ echo echo =========================================================== @@ -22,7 +23,7 @@ echo Running ConfGen echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/TestWorkflowConfiguration.xml" "$PWD/Traces.Output" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/Results/TestWorkflowConfiguration.xml" "$PWD/Results" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" echo @@ -32,7 +33,7 @@ echo =========================================================== echo cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/Gradle/sampleclient/ -cp $PWD/TestWorkflowConfiguration.xml $PWD/Samples/Gradle/sampleclient/ +cp $PWD/Results/TestWorkflowConfiguration.xml $PWD/Samples/Gradle/sampleclient/ cd Samples/Gradle sh ./gradlew sampleclient:test --warning-mode all @@ -47,12 +48,4 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.xml" "$PWD/TestGenerator.Output" - -mkdir Results - -mv $PWD/TestWorkflowConfiguration.xml Results/ -mv $PWD/Traces.Output/gilesi.instrumentation.log Results/ -mv $PWD/Traces.Output/MethodTraces.xml Results/ -mv $PWD/Traces.Output/*.xml Results/ -mv $PWD/TestGenerator.Output Results/ +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Results/MethodTraces.xml" "$PWD/Results/TestGenerator.Output" From 4cc7fabe998ea54f149d176f79e37d8e0924b2cd Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 27 May 2024 16:09:58 +0200 Subject: [PATCH 109/244] Update Project Runner for Maven --- .../src/main/java/com/github/gilesi/Main.java | 18 ++++- .../gilesi/runners/maven/Constants.java | 17 +++++ .../gilesi/runners/maven/ProjectRunner.java | 65 +++++++++++++++++-- 3 files changed, 94 insertions(+), 6 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java diff --git a/Maestro/src/main/java/com/github/gilesi/Main.java b/Maestro/src/main/java/com/github/gilesi/Main.java index 1c2ec9f4..7f258ce0 100644 --- a/Maestro/src/main/java/com/github/gilesi/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/Main.java @@ -1,7 +1,23 @@ package com.github.gilesi; +import com.github.gilesi.runners.maven.ProjectRunner; +import org.apache.maven.shared.invoker.MavenInvocationException; + +import java.nio.file.Files; +import java.nio.file.Path; + public class Main { - public static void main(String[] args) { + public static void main(String[] args) throws MavenInvocationException { + if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { + System.out.println("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); + return; + } + System.out.println("Hello world!"); + + String projectLocation = "/home/gus/Datasets/compsuite/repos/AthenaX"; + String pomFile = projectLocation + "/pom.xml"; + + ProjectRunner.runMavenGoalOnRepository(projectLocation, "test", null, "1.8"); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java b/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java new file mode 100644 index 00000000..2e4ddc77 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java @@ -0,0 +1,17 @@ +package com.github.gilesi.runners.maven; + +import java.util.Hashtable; +import java.util.Map; + +public class Constants { + public static final Map JAVA_VERSIONS = new Hashtable<>() { + { + put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); + put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); + } + }; +} diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java b/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java index 89f9b27c..e277c968 100644 --- a/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java +++ b/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java @@ -1,18 +1,55 @@ package com.github.gilesi.runners.maven; +import org.apache.maven.model.*; import org.apache.maven.shared.invoker.*; -import java.io.File; -import java.io.InputStream; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; import java.util.List; import java.util.Properties; +import static com.github.gilesi.buildsystem.configuration.maven.PomHelper.readPomFile; + public class ProjectRunner { public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath) throws MavenInvocationException { + + String javaVersion = "8"; + + try { + Model pomModel = readPomFile(pomFilePath); + Properties props = pomModel.getProperties(); + if (props.stringPropertyNames().contains("java.compiler.version")) { + javaVersion = props.getProperty("java.compiler.version"); + System.out.println("Debug: Using java.compiler.version=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.source")) { + javaVersion = props.getProperty("maven.compiler.source"); + System.out.println("Debug: Using maven.compiler.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.target")) { + javaVersion = props.getProperty("maven.compiler.target"); + System.out.println("Debug: Using maven.compiler.target=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.source")) { + javaVersion = props.getProperty("maven.compile.source"); + System.out.println("Debug: Using maven.compile.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.target")) { + javaVersion = props.getProperty("maven.compile.target"); + System.out.println("Debug: Using maven.compile.target=" + javaVersion); + } + } catch (Exception ignored) { + System.out.println("Debug: Getting java specific version unfortunately failed."); + } + + return runPomGoals(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaVersion); + } + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion) throws MavenInvocationException { + String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion); + } + + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion) throws MavenInvocationException { File pomFile = new File(pomFilePath); File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); @@ -21,6 +58,16 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List properties.put(p, true)); + properties.put("maven.compiler.source", JavaVersion); + properties.put("maven.compiler.target", JavaVersion); + properties.put("maven.compile.source", JavaVersion); + properties.put("maven.compile.target", JavaVersion); + + String javacLocation = JavaHome + File.separator + "bin" + File.separator + "javac"; + pomGoals.add("-Dmaven.compiler.fork=true"); + if (Files.exists(Path.of(javacLocation))) { + pomGoals.add("-Dmaven.compiler.executable=" + javacLocation); + } InvocationRequest request = new DefaultInvocationRequest(); request.setShellEnvironmentInherited(false); @@ -28,6 +75,7 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List pomGoals, List pomGoals, List goals = new ArrayList<>(); goals.add(goal); - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath) == 0; + if (javaVersion != null && !javaVersion.isBlank()) { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion) == 0; + } else { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath) == 0; + } } -} +} \ No newline at end of file From a545a8cf807534fb86a3bae79e83b06c4ddbea11 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 28 May 2024 10:54:35 +0200 Subject: [PATCH 110/244] Update Maestro POC --- .../src/main/java/com/github/gilesi/Main.java | 91 ++++++++++++++++++- .../configuration/maven/PomHelper.java | 2 +- .../testing/surefire/SurefireHarness.java | 9 +- 3 files changed, 88 insertions(+), 14 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/Main.java b/Maestro/src/main/java/com/github/gilesi/Main.java index 7f258ce0..51fa69ce 100644 --- a/Maestro/src/main/java/com/github/gilesi/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/Main.java @@ -1,23 +1,104 @@ package com.github.gilesi; +import com.github.gilesi.buildsystem.configuration.maven.PomHelper; import com.github.gilesi.runners.maven.ProjectRunner; +import com.github.gilesi.testing.surefire.FileUtils; +import com.github.gilesi.testing.surefire.ReportItem; +import com.github.gilesi.testing.surefire.SurefireHarness; import org.apache.maven.shared.invoker.MavenInvocationException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; public class Main { - public static void main(String[] args) throws MavenInvocationException { + public static void main(String[] args) throws MavenInvocationException, XmlPullParserException, IOException, InterruptedException { if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { System.out.println("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); return; } - System.out.println("Hello world!"); + handleProject("/home/gus/Datasets/compsuite/repos/AthenaX", "/home/gus/.m2/repository/org/apache/flink/flink-core/1.5.0/sources"); + } + + private static void handleProject(String clientLocation, String libraryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + // Run ConfGen on Library first + String confGenLocation = "/home/gus/Git/gilesi/ConfGen/build/libs/com.github.gilesi.confgen.jar"; + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve("TestWorkflowConfiguration.xml"); + + String[] command = new String[] { + "/usr/lib/jvm/java-21-openjdk-amd64/bin/java", + "-jar", + confGenLocation, + libraryConfig.toString(), + "/home/gus/Git/gilesi/Results", + libraryLocation, + clientLocation + }; + ProcessBuilder pb = new ProcessBuilder(command); + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + + String line; + + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + + p.waitFor(); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml"; + + var agentDest = clientProjectLocationPath.resolve("com.github.gilesi.instrumentation.jar"); + if (Files.exists(agentDest)) { + Files.delete(agentDest); + } + Files.copy(Path.of("/home/gus/Git/gilesi/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"), agentDest); + var workflowDest = clientProjectLocationPath.resolve("TestWorkflowConfiguration.xml"); + if (Files.exists(workflowDest)) { + Files.delete(workflowDest); + } + Files.copy(libraryConfig, workflowDest); + + PomHelper.addSureFire(clientPomFile, clientSurefireArgLine); + } + + // Run the client tests + ProjectRunner.runMavenGoalOnRepository(clientLocation, "test", null, "1.8"); + + // Collect test results of the client test runs + for (String pomFile : clientProjectPomFiles) { + ArrayList testReports = SurefireHarness.getProjectTestReports("testName", "testCommit", pomFile); + int success = 0; + int failure = 0; + for (ReportItem testReport : testReports) { + if (testReport.getTestResult().equals("Green")) { + success++; + } + if (testReport.getTestResult().equals("Red")) { + failure++; + } + } + + System.out.printf("Project: %s%n", pomFile); + System.out.printf("Total number of tests: %d%n", testReports.size()); + System.out.printf("Total number of greens: %d%n", success); + System.out.printf("Total number of reds: %d%n", failure); + } - String projectLocation = "/home/gus/Datasets/compsuite/repos/AthenaX"; - String pomFile = projectLocation + "/pom.xml"; + // Turn traces into Java files - ProjectRunner.runMavenGoalOnRepository(projectLocation, "test", null, "1.8"); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java index 5c234dc7..de206bdb 100644 --- a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java +++ b/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java @@ -15,7 +15,7 @@ public class PomHelper { - private static final String SUREFIRE_VERSION = "3.0.0-M5"; + private static final String SUREFIRE_VERSION = "3.2.5"; private static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; private static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java index a8383785..89b5771f 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java @@ -11,9 +11,6 @@ private static void buildReportXml(String projectName, String projectCommit, Str String sureFireReportsLocation = targetLocation + File.separator + "surefire-reports"; ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); - System.out.println("Report XML Count: " + reportXmls.size()); - System.out.println("Report XML Location: " + sureFireReportsLocation); - for (String xml : reportXmls) { Testsuite testsuite = XmlParser.deserializeTestsuite(xml); Testcase[] list = testsuite.getTestcase(); @@ -32,11 +29,7 @@ public static ArrayList getProjectTestReports(String projectPathFrie Path pomFilePath = Path.of(pomFileLocation); String targetLocation = "%s%starget".formatted(pomFilePath.getParent().toAbsolutePath(), File.separator); - if (!Files.isDirectory(Path.of(targetLocation))) { - System.out.printf("Skipping %s because it does not appear to be a maven project. Issue in data set?%n", targetLocation); - } else { - System.out.printf("Handling %s...%n", targetLocation); - + if (Files.isDirectory(Path.of(targetLocation))) { try { buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); } catch (Exception e) { From 6a5f4c7c177896410eaa49f965e747900426f31c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 28 May 2024 11:42:28 +0200 Subject: [PATCH 111/244] Maestro: Cleanup --- .../com/github/gilesi/maestro/Constants.java | 35 ++++++++ .../com/github/gilesi/{ => maestro}/Main.java | 89 +++++++++++++------ .../maven/ConfigurationUtils.java | 2 +- .../maven/IPluginConfiguration.java | 2 +- .../configuration/maven/PomHelper.java | 11 +-- .../maven/SureFirePluginConfiguration.java | 2 +- .../runners/maven/ConsoleLogger.java | 5 +- .../runners/maven/ProjectRunner.java | 13 +-- .../{ => maestro}/testing/surefire/Error.java | 2 +- .../testing/surefire/FileUtils.java | 2 +- .../testing/surefire/Properties.java | 2 +- .../testing/surefire/Property.java | 2 +- .../testing/surefire/ReportItem.java | 12 +-- .../testing/surefire/SurefireHarness.java | 4 +- .../testing/surefire/Testcase.java | 2 +- .../testing/surefire/Testsuite.java | 2 +- .../testing/surefire/Testsuites.java | 2 +- .../testing/surefire/XmlParser.java | 2 +- .../gilesi/runners/maven/Constants.java | 17 ---- 19 files changed, 129 insertions(+), 79 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/Constants.java rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/Main.java (58%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/buildsystem/configuration/maven/ConfigurationUtils.java (93%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/buildsystem/configuration/maven/IPluginConfiguration.java (62%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/buildsystem/configuration/maven/PomHelper.java (92%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/buildsystem/configuration/maven/SureFirePluginConfiguration.java (98%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/runners/maven/ConsoleLogger.java (97%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/runners/maven/ProjectRunner.java (90%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Error.java (90%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/FileUtils.java (98%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Properties.java (80%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Property.java (86%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/ReportItem.java (69%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/SurefireHarness.java (90%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Testcase.java (91%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Testsuite.java (97%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/Testsuites.java (81%) rename Maestro/src/main/java/com/github/gilesi/{ => maestro}/testing/surefire/XmlParser.java (94%) delete mode 100644 Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java new file mode 100644 index 00000000..1e0dc447 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -0,0 +1,35 @@ +package com.github.gilesi.maestro; + +import java.util.Hashtable; +import java.util.Map; + +public class Constants { + // These paths should already exist on the end user machine for now and never change + public static final String CONF_GEN_LOCATION = "/home/gus/Git/gilesi/ConfGen/build/libs/com.github.gilesi.confgen.jar"; + public static final String INSTRUMENTATION_LOCATION = "/home/gus/Git/gilesi/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"; + + // These paths are dynamically created by the tool but must stay consistent within methods + public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; + public static final String targetConfigurationName = "TestWorkflowConfiguration.xml"; + public static final String traceResultsLocation = "/home/gus/Git/gilesi/Results"; + + public static final Map JAVA_VERSIONS = new Hashtable<>() { + { + put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); + put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); + put("21", JAVA_21_BINARY_LOCATION); + } + }; + + public static final String GREEN_TEST = "Green"; + public static final String RED_TEST = "Red"; + + public static final String SUREFIRE_VERSION = "3.2.5"; + public static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; + public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; +} diff --git a/Maestro/src/main/java/com/github/gilesi/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java similarity index 58% rename from Maestro/src/main/java/com/github/gilesi/Main.java rename to Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 51fa69ce..eeee9ec1 100644 --- a/Maestro/src/main/java/com/github/gilesi/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -1,14 +1,15 @@ -package com.github.gilesi; +package com.github.gilesi.maestro; -import com.github.gilesi.buildsystem.configuration.maven.PomHelper; -import com.github.gilesi.runners.maven.ProjectRunner; -import com.github.gilesi.testing.surefire.FileUtils; -import com.github.gilesi.testing.surefire.ReportItem; -import com.github.gilesi.testing.surefire.SurefireHarness; +import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; +import com.github.gilesi.maestro.runners.maven.ProjectRunner; +import com.github.gilesi.maestro.testing.surefire.FileUtils; +import com.github.gilesi.maestro.testing.surefire.ReportItem; +import com.github.gilesi.maestro.testing.surefire.SurefireHarness; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.BufferedReader; +import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.file.Files; @@ -25,21 +26,7 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP handleProject("/home/gus/Datasets/compsuite/repos/AthenaX", "/home/gus/.m2/repository/org/apache/flink/flink-core/1.5.0/sources"); } - private static void handleProject(String clientLocation, String libraryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { - // Run ConfGen on Library first - String confGenLocation = "/home/gus/Git/gilesi/ConfGen/build/libs/com.github.gilesi.confgen.jar"; - Path libraryLocationPath = Path.of(libraryLocation); - Path libraryConfig = libraryLocationPath.resolve("TestWorkflowConfiguration.xml"); - - String[] command = new String[] { - "/usr/lib/jvm/java-21-openjdk-amd64/bin/java", - "-jar", - confGenLocation, - libraryConfig.toString(), - "/home/gus/Git/gilesi/Results", - libraryLocation, - clientLocation - }; + private static void runExternalCommand(String[] command) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(command); pb.redirectErrorStream(true); Process p = pb.start(); @@ -52,24 +39,66 @@ private static void handleProject(String clientLocation, String libraryLocation) } p.waitFor(); + } + + private static void cleanup(String clientLocation) throws IOException { + Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); + + if (Files.exists(traceResultsLocationPath)) { + FileUtils.deleteDirectory(new File(Constants.traceResultsLocation)); + } - // Modify Client Build System to use the instrumentation agent ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml"; - - var agentDest = clientProjectLocationPath.resolve("com.github.gilesi.instrumentation.jar"); if (Files.exists(agentDest)) { Files.delete(agentDest); } - Files.copy(Path.of("/home/gus/Git/gilesi/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"), agentDest); - var workflowDest = clientProjectLocationPath.resolve("TestWorkflowConfiguration.xml"); + if (Files.exists(workflowDest)) { Files.delete(workflowDest); } + } + } + + private static void handleProject(String clientLocation, String libraryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); + + // First, perform some preliminary cleanup in case we already ran previously + cleanup(clientLocation); + + // Create the results directory + Files.createDirectories(traceResultsLocationPath); + + // Run ConfGen on Library first + runExternalCommand(new String[]{ + Constants.JAVA_21_BINARY_LOCATION, + "-jar", + Constants.CONF_GEN_LOCATION, + libraryConfig.toString(), + Constants.traceResultsLocation, + libraryLocation, + clientLocation + }); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + + Files.copy(Path.of(Constants.INSTRUMENTATION_LOCATION), agentDest); Files.copy(libraryConfig, workflowDest); PomHelper.addSureFire(clientPomFile, clientSurefireArgLine); @@ -83,11 +112,13 @@ private static void handleProject(String clientLocation, String libraryLocation) ArrayList testReports = SurefireHarness.getProjectTestReports("testName", "testCommit", pomFile); int success = 0; int failure = 0; + for (ReportItem testReport : testReports) { - if (testReport.getTestResult().equals("Green")) { + if (testReport.getTestResult().equals(Constants.GREEN_TEST)) { success++; } - if (testReport.getTestResult().equals("Red")) { + + if (testReport.getTestResult().equals(Constants.RED_TEST)) { failure++; } } diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/ConfigurationUtils.java similarity index 93% rename from Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java rename to Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/ConfigurationUtils.java index b6e6e255..b7b92a36 100644 --- a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/ConfigurationUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/ConfigurationUtils.java @@ -1,4 +1,4 @@ -package com.github.gilesi.buildsystem.configuration.maven; +package com.github.gilesi.maestro.buildsystem.configuration.maven; import org.codehaus.plexus.util.xml.Xpp3Dom; diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/IPluginConfiguration.java similarity index 62% rename from Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java rename to Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/IPluginConfiguration.java index cb34d36e..0fbe2835 100644 --- a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/IPluginConfiguration.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/IPluginConfiguration.java @@ -1,4 +1,4 @@ -package com.github.gilesi.buildsystem.configuration.maven; +package com.github.gilesi.maestro.buildsystem.configuration.maven; import org.codehaus.plexus.util.xml.Xpp3Dom; diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/PomHelper.java similarity index 92% rename from Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java rename to Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/PomHelper.java index de206bdb..673039e2 100644 --- a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/PomHelper.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/PomHelper.java @@ -1,5 +1,6 @@ -package com.github.gilesi.buildsystem.configuration.maven; +package com.github.gilesi.maestro.buildsystem.configuration.maven; +import com.github.gilesi.maestro.Constants; import org.apache.maven.model.Build; import org.apache.maven.model.Dependency; import org.apache.maven.model.Model; @@ -15,10 +16,6 @@ public class PomHelper { - private static final String SUREFIRE_VERSION = "3.2.5"; - private static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; - private static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; - public static Model readPomFile(String pomFilePath) throws IOException, XmlPullParserException { MavenXpp3Reader pomReader = new MavenXpp3Reader(); Path pomPath = Path.of(pomFilePath); @@ -75,7 +72,7 @@ private static Xpp3Dom buildSureFireConfiguration(String argLine) { } private static Plugin getSureFirePlugin() { - return buildPlugin(SUREFIRE_GROUPID, SUREFIRE_ARTIFACTID, SUREFIRE_VERSION); + return buildPlugin(Constants.SUREFIRE_GROUPID, Constants.SUREFIRE_ARTIFACTID, Constants.SUREFIRE_VERSION); } private static Dependency buildDependency(String groupId, String artifactId, String version) { @@ -116,7 +113,7 @@ private static void removeExistingPlugin(Build bld, String groupId) throws FileN } private static void removeExistingSureFirePlugins(Build bld) throws FileNotFoundException { - removeExistingPlugin(bld, SUREFIRE_GROUPID); + removeExistingPlugin(bld, Constants.SUREFIRE_GROUPID); } public static void addSureFire(String pomFilePath) throws XmlPullParserException, IOException { diff --git a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/SureFirePluginConfiguration.java similarity index 98% rename from Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java rename to Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/SureFirePluginConfiguration.java index 05d24c23..afc70c5b 100644 --- a/Maestro/src/main/java/com/github/gilesi/buildsystem/configuration/maven/SureFirePluginConfiguration.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/buildsystem/configuration/maven/SureFirePluginConfiguration.java @@ -1,4 +1,4 @@ -package com.github.gilesi.buildsystem.configuration.maven; +package com.github.gilesi.maestro.buildsystem.configuration.maven; import org.codehaus.plexus.util.xml.Xpp3Dom; diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ConsoleLogger.java similarity index 97% rename from Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java rename to Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ConsoleLogger.java index 84f98ee5..59fd4e85 100644 --- a/Maestro/src/main/java/com/github/gilesi/runners/maven/ConsoleLogger.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ConsoleLogger.java @@ -1,4 +1,4 @@ -package com.github.gilesi.runners.maven; +package com.github.gilesi.maestro.runners.maven; /* * Licensed to the Apache Software Foundation (ASF) under one @@ -24,6 +24,7 @@ import java.io.PrintWriter; import java.io.StringWriter; +import java.util.Date; /** * Offers a logger that writes to a print stream like {@link java.lang.System#out}. @@ -104,7 +105,7 @@ private void log(int level, String message, Throwable error) { buffer.append(writer); } - System.out.printf("[%s] %s%n", logLevel, buffer); + System.out.printf("[%s] [%s] %s%n", new Date(), logLevel, buffer); } /** diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java similarity index 90% rename from Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java rename to Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java index e277c968..54322d18 100644 --- a/Maestro/src/main/java/com/github/gilesi/runners/maven/ProjectRunner.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java @@ -1,5 +1,6 @@ -package com.github.gilesi.runners.maven; +package com.github.gilesi.maestro.runners.maven; +import com.github.gilesi.maestro.Constants; import org.apache.maven.model.*; import org.apache.maven.shared.invoker.*; @@ -10,7 +11,7 @@ import java.util.List; import java.util.Properties; -import static com.github.gilesi.buildsystem.configuration.maven.PomHelper.readPomFile; +import static com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper.readPomFile; public class ProjectRunner { @@ -63,10 +64,10 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, properties.put("maven.compile.source", JavaVersion); properties.put("maven.compile.target", JavaVersion); - String javacLocation = JavaHome + File.separator + "bin" + File.separator + "javac"; + String javacLocation = "%s%sbin%sjavac".formatted(JavaHome, File.separator, File.separator); pomGoals.add("-Dmaven.compiler.fork=true"); if (Files.exists(Path.of(javacLocation))) { - pomGoals.add("-Dmaven.compiler.executable=" + javacLocation); + pomGoals.add("-Dmaven.compiler.executable=%s".formatted(javacLocation)); } InvocationRequest request = new DefaultInvocationRequest(); @@ -88,7 +89,7 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, } } - System.out.println("Building with pom=" + pomFilePath + " goals=" + pomGoals + " properties=" + properties); + System.out.printf("Building with pom=%s goals=%s properties=%s%n", pomFilePath, pomGoals, properties); Invoker invoker = new DefaultInvoker(); invoker.setLogger(logger); @@ -99,7 +100,7 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion) throws MavenInvocationException { System.out.println("ExecuteMavenGoalOnDuetsRepository Entry"); - String pomFilePath = repositoryDirectory + File.separator + "pom.xml"; + String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); ArrayList goals = new ArrayList<>(); goals.add(goal); diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java similarity index 90% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java index 1231b0e0..07daea4b 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Error.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java similarity index 98% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java index cf6e273b..b552f315 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/FileUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; import java.io.File; import java.io.IOException; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java similarity index 80% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java index ccc3a875..6ad465bc 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Properties.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; public class Properties { private Property[] property; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java similarity index 86% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java index 8108f616..170d6864 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Property.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; public class Property { private String name; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java similarity index 69% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java index e2d98671..226d1e93 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/ReportItem.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java @@ -1,4 +1,6 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; + +import com.github.gilesi.maestro.Constants; public class ReportItem { public String Name; @@ -8,9 +10,9 @@ public class ReportItem { private String ErrorDetails; public ReportItem(String projectName, String projectCommit, Testcase testcase) { - this.TestName = testcase.ClassName + "." + testcase.Name; - this.TestResult = (testcase.Error != null || testcase.Failure != null) ? "Red" : "Green"; - this.ErrorDetails = testcase.Error != null ? testcase.Error.Message : ""; + this.TestName = "%s.%s".formatted(testcase.ClassName, testcase.Name); + this.TestResult = ((testcase.Error != null) || (testcase.Failure != null)) ? Constants.RED_TEST : Constants.GREEN_TEST; + this.ErrorDetails = (testcase.Error != null) ? testcase.Error.Message : ""; this.Name = projectName; this.Version = projectCommit; } @@ -57,6 +59,6 @@ public void setErrorDetails(String errorDetails) { @Override public String toString() { - return "\"" + Name + "\",\"" + Version + "\",\"" + TestName + "\",\"" + TestResult + "\",\"" + ErrorDetails + "\""; + return "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"".formatted(Name, Version, TestName, TestResult, ErrorDetails); } } diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java similarity index 90% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java index 89b5771f..acbbde06 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/SurefireHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; import java.io.File; import java.io.IOException; @@ -8,7 +8,7 @@ public class SurefireHarness { private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { - String sureFireReportsLocation = targetLocation + File.separator + "surefire-reports"; + String sureFireReportsLocation = "%s%ssurefire-reports".formatted(targetLocation, File.separator); ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); for (String xml : reportXmls) { diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java similarity index 91% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java index bc798f1e..9b0f3a89 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testcase.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java similarity index 97% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java index 7772be96..691e2ccf 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; public class Testsuite { private Properties properties; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java similarity index 81% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java index 673fc2a6..2cd38e61 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/Testsuites.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; public class Testsuites { private Testsuite[] testsuites; diff --git a/Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java similarity index 94% rename from Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java index 517b23dc..19764689 100644 --- a/Maestro/src/main/java/com/github/gilesi/testing/surefire/XmlParser.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testing.surefire; +package com.github.gilesi.maestro.testing.surefire; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; diff --git a/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java b/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java deleted file mode 100644 index 2e4ddc77..00000000 --- a/Maestro/src/main/java/com/github/gilesi/runners/maven/Constants.java +++ /dev/null @@ -1,17 +0,0 @@ -package com.github.gilesi.runners.maven; - -import java.util.Hashtable; -import java.util.Map; - -public class Constants { - public static final Map JAVA_VERSIONS = new Hashtable<>() { - { - put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); - put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); - put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); - put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); - put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); - put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); - } - }; -} From 0368992d3aadaf4d5a57bc262fff0ece0fa5cf9a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 28 May 2024 15:56:28 +0200 Subject: [PATCH 112/244] Maestro: Small fixes --- .../java/com/github/gilesi/confgen/Main.java | 19 ++-- .../models/InstrumentationParameters.java | 2 + .../models/InstrumentationParameters.java | 2 + .../github/gilesi/instrumentation/Agent.java | 2 + .../github/gilesi/instrumentation/Logger.java | 34 ++++++- .../instrumentation/TraceCollector.java | 17 +++- .../instrumentation/TraceDataFactory.java | 2 +- .../visitors/CommonAdvisor.java | 95 +++++++++---------- 8 files changed, 110 insertions(+), 63 deletions(-) diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 16a2b7cf..44a2e0de 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -6,10 +6,7 @@ import com.github.gilesi.confgen.models.InstrumentationParameters; import com.github.gilesi.confgen.models.Method; import com.github.maracas.roseau.api.SpoonAPIExtractor; -import com.github.maracas.roseau.api.model.API; -import com.github.maracas.roseau.api.model.ClassDecl; -import com.github.maracas.roseau.api.model.ConstructorDecl; -import com.github.maracas.roseau.api.model.MethodDecl; +import com.github.maracas.roseau.api.model.*; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import spoon.Launcher; @@ -19,9 +16,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.StandardOpenOption; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; +import java.util.*; public class Main { private static String getClassNameFromFQN(String fullyQualifiedName) { @@ -138,6 +133,8 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); + instrumentationParameters.LibraryTypes = new ArrayList<>(); + instrumentationParameters.ClientTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; for (ClassDecl classDecl : libraryApiModel.getExportedTypes() @@ -167,6 +164,10 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept .forEach(method -> instrumentationParameters.LibraryMethods .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); + // TODO: there has to be a better way... + libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.LibraryTypes + .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); + System.out.println("Processing Test Project..."); Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); @@ -179,6 +180,10 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept .forEach(method -> instrumentationParameters.ClientMethods .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); + // TODO: there has to be a better way... + clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.ClientTypes + .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); + XStream xstream = new XStream(new DomDriver()); String apiXml = xstream.toXML(instrumentationParameters); Files.writeString(apiReportOutputPath, apiXml, StandardOpenOption.CREATE); diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index e167fcd0..6ea2ff98 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -6,5 +6,7 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; public List LibraryMethods; public List ClientMethods; + public List LibraryTypes; + public List ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 08a3f31e..cc3e4c10 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,5 +4,7 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; public String[] LibraryMethods; public String[] ClientMethods; + public String[] LibraryTypes; + public String[] ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 9ebe71de..84eac91f 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -75,6 +75,8 @@ private static void installAgent(String arg, Instrumentation inst) { CommonAdvisor.LibraryMethods = instrumentationParameters.LibraryMethods; CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; + CommonAdvisor.LibraryTypes = instrumentationParameters.LibraryTypes; + CommonAdvisor.ClientTypes = instrumentationParameters.ClientTypes; // Instrument every class for (Class instrumentationParameter : instrumentationParameters.InstrumentedAPIClasses) { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index 6e6fb2af..a4b70ffa 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -4,15 +4,36 @@ import java.io.File; import java.nio.file.Files; +import java.nio.file.Paths; import java.util.ArrayList; +import java.util.Dictionary; +import java.util.HashMap; +import java.util.Map; public class Logger { - private static final ArrayList LOGGER = new ArrayList<>(); + private static final Map> LOGGER = new HashMap<>(); private static int LOGGERINSTANCE = 0; public static void SaveLogResults(InstrumentationParameters instrumentationParameters) { + int mainPadding = 1; + String logFileName = String.format("%s%sgilesi.instrumentation_%d.log", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(logFileName))) { + logFileName = String.format("%s%sgilesi.instrumentation_%d.log", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); + } + + ArrayList logLines = new ArrayList<>(); + for (int loggerInstance = 0; loggerInstance < LOGGERINSTANCE; loggerInstance++) { + ArrayList logs = LOGGER.get(loggerInstance); + if (logs != null) { + for (String log : logs) { + logLines.add(String.format("%d: %s", loggerInstance, log)); + } + } + } + try { - Files.write(new File(instrumentationParameters.traceOutputLocation + File.separatorChar + "gilesi.instrumentation.log").toPath(), LOGGER); + Files.write(new File(logFileName).toPath(), logLines); } catch (Exception e) { System.err.println("ERROR while saving logs"); e.printStackTrace(); @@ -24,6 +45,13 @@ public static int GetInstance() { } public static void Log(int loggerInstance, String log) { - LOGGER.add(String.format("%d: %s", loggerInstance, log)); + if (LOGGER.containsKey(loggerInstance)) { + ArrayList logs = LOGGER.get(loggerInstance); + logs.add(log); + } else { + ArrayList logs = new ArrayList<>(); + logs.add(log); + LOGGER.put(loggerInstance, logs); + } } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index c3636b33..16f0e435 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -6,6 +6,7 @@ import java.io.File; import java.io.FileWriter; +import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; import java.util.ArrayList; @@ -46,7 +47,13 @@ public static Collection getMethodTraces() { public static void SaveTraceResults(InstrumentationParameters instrumentationParameters) { System.out.println("Saving trace results in progress..."); - String tracesFileName = instrumentationParameters.traceOutputLocation + File.separatorChar + "MethodTraces.xml"; + int mainPadding = 1; + String tracesFileName = String.format("%s%sMethodTraces_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sMethodTraces_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); + } + Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); System.out.printf("Output location: %s%n", tracesPath); @@ -64,7 +71,13 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar } for (TestTraceResults testTraceResults : results) { - String traceFileName = instrumentationParameters.traceOutputLocation + File.separatorChar + testTraceResults.Test + ".xml"; + int padding = 1; + String traceFileName = String.format("%s%s%s_%d_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); + + while (Files.exists(Paths.get(traceFileName))) { + traceFileName = String.format("%s%s%s_%d_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); + } + Path tracePath = Paths.get(traceFileName).toAbsolutePath(); System.out.printf("Test Output location: %s%n", tracePath); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index 08d93039..ce3f7226 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -7,7 +7,7 @@ public class TraceDataFactory { private static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) - .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index ad1bb8b9..396544bd 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -11,11 +11,13 @@ public class CommonAdvisor { private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.gilesi.instrumentation"; - private static final String JAVA_INTERNAL_REFLECT_METHOD_FQN = "jdk.internal.reflect.DirectMethodHandleAccessor.invoke"; private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; + private static final String JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL = "org.junit.runners.model.FrameworkMethod$1.runReflectiveCall"; private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; + public static String[] LibraryTypes = new String[0]; + public static String[] ClientTypes = new String[0]; public static Object commonEnter( Executable origin, @@ -80,6 +82,13 @@ private static String getTestMethodName(String[] stackTrace) { } } + for (int i = 5; i < stackTrace.length; i++) { + String methodName = stackTrace[i]; + if (methodName.equals(JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL)) { + return stackTrace[i - 5]; + } + } + return UNKNOWN_TEST_METHOD_NAME; } @@ -94,59 +103,22 @@ private static boolean isAcceptedTrace(String[] stackTrace) { Logger.Log(loggerInstance, String.format(" %s", methodName)); } - // 0: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:19) - // 1: The instrumented method: com.github.gilesi.samples.samplelibrary.Foo.TESTING(Foo.java:16) - // 2: The caller: FooTest.mainTest(FooTest.java:50) - // 3: ... - - String methodName = stackTrace[instrumentedMethodStackTraceIndex + 1]; - - // The caller is a method from the library, which we do not want to collect traces for in our case - // Because we focus on API calls here, so do not do anything. - // Note: it's also possible the tracing, is originating from us, - // so we want to also check if we are not a caller ourselves as well - if (Arrays.asList(LibraryMethods).contains(methodName) || - methodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { - Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return false; - } + // Start with the caller + for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTrace.length; i++) { + String stackTraceMethodName = stackTrace[i]; - // When we collect traces, we attempt to serialize the data transiting on the API barrier - // Unfortunately for us, some classes may return objects, that are linked to themselves - // This causes a rather unfortunate StackOverflow Exception for us, as we're trying to - // Serialize an object, and while doing so, we go into our entry/exit methods - // To fix this, we take below example, and verify the 10th item isn't us, if it is, skip as well - - // 0: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 1: The instrumented method: com.github.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 2: The caller: java.base/jdk.internal.reflect.DirectMethodHandleAccessor.invoke(DirectMethodHandleAccessor.java:103) - // 3: java.base/java.lang.reflect.Method.invoke(Method.java:580) - // 4: com.fasterxml.jackson.databind.ser.BeanPropertyWriter.serializeAsField(BeanPropertyWriter.java:688) - // 5: com.fasterxml.jackson.databind.ser.std.BeanSerializerBase.serializeFields(BeanSerializerBase.java:772) - // 6: com.fasterxml.jackson.databind.ser.BeanSerializer.serialize(BeanSerializer.java:178) - // 7: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider._serialize(DefaultSerializerProvider.java:479) - // 8: com.fasterxml.jackson.databind.ser.DefaultSerializerProvider.serializeValue(DefaultSerializerProvider.java:318) - // 9: com.fasterxml.jackson.databind.ObjectMapper._writeValueAndClose(ObjectMapper.java:4719) - // 10: com.fasterxml.jackson.databind.ObjectMapper.writeValueAsString(ObjectMapper.java:3964) - // 11: com.github.gilesi.instrumentation.TraceDataFactory.valueOf(TraceDataFactory.java:33) - // 12: com.github.gilesi.instrumentation.TraceFactory.getPartialMethodTrace(TraceFactory.java:70) - // 13: This method: com.github.gilesi.instrumentation.visitors.MethodAdvisor.enter(MethodAdvisor.java:40) - // 14: The instrumented method: com.github.gilesi.samples.samplelibrary.A2.getOurselves(A2.java:18) - // 15: The caller: ... - if (methodName.startsWith(JAVA_INTERNAL_REFLECT_METHOD_FQN) && stackTrace.length >= instrumentedMethodStackTraceIndex + 10) { - String originatingReflectMethodName = stackTrace[instrumentedMethodStackTraceIndex + 10]; - - if (originatingReflectMethodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { + if (stackTraceMethodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); return false; } - } - // Start with the caller - for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTrace.length; i++) { - String stackTraceMethodName = stackTrace[i]; + // This is our client, and we didn't find a lib method, first, we're good to go. + if (Arrays.asList(ClientMethods).contains(stackTraceMethodName)) { + Logger.Log(loggerInstance, " Accepted Trace"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return true; + } if (Arrays.asList(LibraryMethods).contains(stackTraceMethodName)) { Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); @@ -154,12 +126,35 @@ private static boolean isAcceptedTrace(String[] stackTrace) { return false; } - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(ClientMethods).contains(stackTraceMethodName)) { + if (Arrays.stream(ClientTypes).map(t -> { + if (t.contains(".")) { + String[] nameElements = t.split("\\."); + return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); + } + return t; + }).anyMatch(stackTraceMethodName::startsWith)) { Logger.Log(loggerInstance, " Accepted Trace"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); return true; } + + if (Arrays.stream(LibraryTypes).map(t -> { + if (t.contains(".")) { + String[] nameElements = t.split("\\."); + return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); + } + return t; + }).anyMatch(stackTraceMethodName::startsWith)) { + Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return false; + } + + if (!stackTraceMethodName.startsWith("org.junit.") && !stackTraceMethodName.startsWith("sun.") && !stackTraceMethodName.startsWith("jdk.") && !stackTraceMethodName.startsWith("java.")) { + Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + return false; + } } // We never found any trace of the client, something is up... From dc7479587cc3b43a863c71cfb5e56ed7522db774 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 29 May 2024 13:13:20 +0200 Subject: [PATCH 113/244] Progress on Maestro --- .../visitors/CommonAdvisor.java | 49 +++++-------------- .../com/github/gilesi/maestro/Constants.java | 1 + .../java/com/github/gilesi/maestro/Main.java | 17 +++++-- 3 files changed, 27 insertions(+), 40 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index 396544bd..542ee8b7 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -107,23 +107,16 @@ private static boolean isAcceptedTrace(String[] stackTrace) { for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTrace.length; i++) { String stackTraceMethodName = stackTrace[i]; - if (stackTraceMethodName.startsWith(String.format("%s.", GILESI_INSTRUMENTATION_NAMESPACE))) { - Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return false; + if (stackTraceMethodName.startsWith("org.junit.") || + stackTraceMethodName.startsWith("sun.") || + stackTraceMethodName.startsWith("jdk.") || + stackTraceMethodName.startsWith("java.")) { + continue; } // This is our client, and we didn't find a lib method, first, we're good to go. if (Arrays.asList(ClientMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, " Accepted Trace"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return true; - } - - if (Arrays.asList(LibraryMethods).contains(stackTraceMethodName)) { - Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return false; + break; } if (Arrays.stream(ClientTypes).map(t -> { @@ -133,34 +126,18 @@ private static boolean isAcceptedTrace(String[] stackTrace) { } return t; }).anyMatch(stackTraceMethodName::startsWith)) { - Logger.Log(loggerInstance, " Accepted Trace"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return true; + break; } - if (Arrays.stream(LibraryTypes).map(t -> { - if (t.contains(".")) { - String[] nameElements = t.split("\\."); - return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); - } - return t; - }).anyMatch(stackTraceMethodName::startsWith)) { - Logger.Log(loggerInstance, " Rejected Trace (Case 3)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return false; - } + // We never found any trace of the client, something is up... + Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - if (!stackTraceMethodName.startsWith("org.junit.") && !stackTraceMethodName.startsWith("sun.") && !stackTraceMethodName.startsWith("jdk.") && !stackTraceMethodName.startsWith("java.")) { - Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - return false; - } + return false; } - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, " Rejected Trace (Case 4)"); + Logger.Log(loggerInstance, " Accepted Trace"); Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); - - return false; + return true; } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index 1e0dc447..130f066f 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -6,6 +6,7 @@ public class Constants { // These paths should already exist on the end user machine for now and never change public static final String CONF_GEN_LOCATION = "/home/gus/Git/gilesi/ConfGen/build/libs/com.github.gilesi.confgen.jar"; + public static final String TEST_GEN_LOCATION = "/home/gus/Git/gilesi/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; public static final String INSTRUMENTATION_LOCATION = "/home/gus/Git/gilesi/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index eeee9ec1..7b6a943d 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -72,7 +72,7 @@ private static void handleProject(String clientLocation, String libraryLocation) Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); // First, perform some preliminary cleanup in case we already ran previously - cleanup(clientLocation); + /*cleanup(clientLocation); // Create the results directory Files.createDirectories(traceResultsLocationPath); @@ -105,7 +105,7 @@ private static void handleProject(String clientLocation, String libraryLocation) } // Run the client tests - ProjectRunner.runMavenGoalOnRepository(clientLocation, "test", null, "1.8"); + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "1.8"); // Collect test results of the client test runs for (String pomFile : clientProjectPomFiles) { @@ -127,9 +127,18 @@ private static void handleProject(String clientLocation, String libraryLocation) System.out.printf("Total number of tests: %d%n", testReports.size()); System.out.printf("Total number of greens: %d%n", success); System.out.printf("Total number of reds: %d%n", failure); - } + }*/ // Turn traces into Java files - + ArrayList traceFiles = FileUtils.enumerateFiles(Constants.traceResultsLocation, "MethodTraces_.*\\.xml", false); + for (String traceFile : traceFiles) { + runExternalCommand(new String[]{ + Constants.JAVA_21_BINARY_LOCATION, + "-jar", + Constants.TEST_GEN_LOCATION, + traceFile, + Constants.traceResultsLocation // output + }); + } } } \ No newline at end of file From 8507b983ba013997a6c331e1f939afd2919dda7f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 29 May 2024 13:16:15 +0200 Subject: [PATCH 114/244] Cleanup --- .../java/com/github/gilesi/maestro/Constants.java | 11 +++++++---- .../src/main/java/com/github/gilesi/maestro/Main.java | 4 ++-- 2 files changed, 9 insertions(+), 6 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index 130f066f..d85d50fd 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -4,16 +4,19 @@ import java.util.Map; public class Constants { + public static final String GILESI_REPOSITORY_LOCATION = "/home/gus/Git/gilesi"; + // These paths should already exist on the end user machine for now and never change - public static final String CONF_GEN_LOCATION = "/home/gus/Git/gilesi/ConfGen/build/libs/com.github.gilesi.confgen.jar"; - public static final String TEST_GEN_LOCATION = "/home/gus/Git/gilesi/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; - public static final String INSTRUMENTATION_LOCATION = "/home/gus/Git/gilesi/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; + public static final String CONF_GEN_LOCATION = GILESI_REPOSITORY_LOCATION + "/ConfGen/build/libs/com.github.gilesi.confgen.jar"; + public static final String TEST_GEN_LOCATION = GILESI_REPOSITORY_LOCATION + "/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; + public static final String INSTRUMENTATION_LOCATION = GILESI_REPOSITORY_LOCATION + "/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"; // These paths are dynamically created by the tool but must stay consistent within methods public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; public static final String targetConfigurationName = "TestWorkflowConfiguration.xml"; - public static final String traceResultsLocation = "/home/gus/Git/gilesi/Results"; + public static final String traceResultsLocation = GILESI_REPOSITORY_LOCATION + "/Results"; public static final Map JAVA_VERSIONS = new Hashtable<>() { { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 7b6a943d..2d4faa1a 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -72,7 +72,7 @@ private static void handleProject(String clientLocation, String libraryLocation) Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); // First, perform some preliminary cleanup in case we already ran previously - /*cleanup(clientLocation); + cleanup(clientLocation); // Create the results directory Files.createDirectories(traceResultsLocationPath); @@ -127,7 +127,7 @@ private static void handleProject(String clientLocation, String libraryLocation) System.out.printf("Total number of tests: %d%n", testReports.size()); System.out.printf("Total number of greens: %d%n", success); System.out.printf("Total number of reds: %d%n", failure); - }*/ + } // Turn traces into Java files ArrayList traceFiles = FileUtils.enumerateFiles(Constants.traceResultsLocation, "MethodTraces_.*\\.xml", false); From 8fca5999c7c1dc08a0e31fe67049f931bc2f10c7 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 29 May 2024 13:23:05 +0200 Subject: [PATCH 115/244] Cleanup --- .../main/java/com/github/gilesi/confgen/Main.java | 12 ------------ .../confgen/models/InstrumentationParameters.java | 2 -- .../confgen/models/InstrumentationParameters.java | 2 -- .../com/github/gilesi/instrumentation/Agent.java | 2 -- .../instrumentation/visitors/CommonAdvisor.java | 6 ------ 5 files changed, 24 deletions(-) diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 44a2e0de..264e9850 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -131,9 +131,7 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); - instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); - instrumentationParameters.LibraryTypes = new ArrayList<>(); instrumentationParameters.ClientTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; @@ -158,16 +156,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept } } - System.out.println("Processing Library Project..."); - - libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() - .forEach(method -> instrumentationParameters.LibraryMethods - .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); - - // TODO: there has to be a better way... - libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.LibraryTypes - .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); - System.out.println("Processing Test Project..."); Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 6ea2ff98..590c2e97 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,9 +4,7 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; - public List LibraryMethods; public List ClientMethods; - public List LibraryTypes; public List ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index cc3e4c10..a32dff2f 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -2,9 +2,7 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; - public String[] LibraryMethods; public String[] ClientMethods; - public String[] LibraryTypes; public String[] ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 84eac91f..1c667d83 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -73,9 +73,7 @@ private static void installAgent(String arg, Instrumentation inst) { // Add a shutdown hook to save all method execution traces at exit Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(instrumentationParameters))); - CommonAdvisor.LibraryMethods = instrumentationParameters.LibraryMethods; CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; - CommonAdvisor.LibraryTypes = instrumentationParameters.LibraryTypes; CommonAdvisor.ClientTypes = instrumentationParameters.ClientTypes; // Instrument every class diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index 542ee8b7..3c890da5 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -10,13 +10,10 @@ import java.util.Arrays; public class CommonAdvisor { - private static final String GILESI_INSTRUMENTATION_NAMESPACE = "com.github.gilesi.instrumentation"; private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; private static final String JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL = "org.junit.runners.model.FrameworkMethod$1.runReflectiveCall"; private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; - public static String[] LibraryMethods = new String[0]; public static String[] ClientMethods = new String[0]; - public static String[] LibraryTypes = new String[0]; public static String[] ClientTypes = new String[0]; public static Object commonEnter( @@ -49,9 +46,6 @@ public static void commonExit( // Need to fetch this asap to not be off on the measurements! long exitMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; - //List stackTraceElements = StackWalker.getInstance().walk(stackFrameStream -> stackFrameStream.collect(Collectors.toList())); - //String[] stackTrace = stackTraceElements.stream().skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); - StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); From 6d2ffa7f6c395de6c1a2b122a4bf140d6c4f97bc Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 29 May 2024 14:15:49 +0200 Subject: [PATCH 116/244] Cleanup --- .../java/com/github/gilesi/confgen/Main.java | 18 +- .../models/InstrumentationParameters.java | 2 + .../models/InstrumentationParameters.java | 2 + .../instrumentation/TraceDataFactory.java | 14 +- Maestro/build.gradle | 63 ++++- .../com/github/gilesi/maestro/Constants.java | 10 +- .../java/com/github/gilesi/maestro/Main.java | 119 ++++++--- .../TestWorkflowConfiguration.xml | 204 +++++++++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + Samples/Gradle/sampleclient/gradlew | 246 ++++++++++++++++++ Samples/Gradle/sampleclient/gradlew.bat | 91 +++++++ .../TestWorkflowConfiguration.xml | 204 +++++++++++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + Samples/Gradle/samplelibrary/gradlew | 246 ++++++++++++++++++ Samples/Gradle/samplelibrary/gradlew.bat | 91 +++++++ Samples/Maven/sampleclient/pom.xml | 102 ++++---- compile.sh | 14 +- 19 files changed, 1331 insertions(+), 109 deletions(-) create mode 100644 Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml create mode 100644 Samples/Gradle/sampleclient/gradle/wrapper/gradle-wrapper.jar create mode 100644 Samples/Gradle/sampleclient/gradle/wrapper/gradle-wrapper.properties create mode 100644 Samples/Gradle/sampleclient/gradlew create mode 100644 Samples/Gradle/sampleclient/gradlew.bat create mode 100644 Samples/Gradle/samplelibrary/TestWorkflowConfiguration.xml create mode 100644 Samples/Gradle/samplelibrary/gradle/wrapper/gradle-wrapper.jar create mode 100644 Samples/Gradle/samplelibrary/gradle/wrapper/gradle-wrapper.properties create mode 100644 Samples/Gradle/samplelibrary/gradlew create mode 100644 Samples/Gradle/samplelibrary/gradlew.bat diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 264e9850..22f82470 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -12,6 +12,7 @@ import spoon.Launcher; import spoon.reflect.CtModel; +import java.io.BufferedWriter; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; @@ -131,7 +132,9 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); + instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); + instrumentationParameters.LibraryTypes = new ArrayList<>(); instrumentationParameters.ClientTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; @@ -156,6 +159,16 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept } } + System.out.println("Processing Library Project..."); + + libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() + .forEach(method -> instrumentationParameters.LibraryMethods + .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); + + // TODO: there has to be a better way... + libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.LibraryTypes + .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); + System.out.println("Processing Test Project..."); Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); @@ -173,7 +186,8 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); XStream xstream = new XStream(new DomDriver()); - String apiXml = xstream.toXML(instrumentationParameters); - Files.writeString(apiReportOutputPath, apiXml, StandardOpenOption.CREATE); + BufferedWriter bufferedWriter = Files.newBufferedWriter(apiReportOutputPath, StandardOpenOption.CREATE); + xstream.toXML(instrumentationParameters, bufferedWriter); + bufferedWriter.close(); } } \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 590c2e97..8d5526d3 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -6,5 +6,7 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; public List ClientMethods; public List ClientTypes; + public List LibraryMethods; + public List LibraryTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index a32dff2f..584f4c39 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,5 +4,7 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; public String[] ClientMethods; public String[] ClientTypes; + public String[] LibraryMethods; + public String[] LibraryTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index ce3f7226..bedd36fb 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -1,16 +1,16 @@ package com.github.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; +//import com.fasterxml.jackson.databind.ObjectMapper; +//import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - private static final ObjectMapper objectMapper = new ObjectMapper() + /*private static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS);*/ public static TraceData valueOf(Object object, int nullInstanceId) { TraceData traceData = new TraceData(); @@ -46,18 +46,18 @@ public static TraceData valueOf(Object object, int nullInstanceId) { Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); } - String serializedJsonString = null; + /*String serializedJsonString = null; try { serializedJsonString = objectMapper.writeValueAsString(object); } catch (Exception e) { int loggerInstance = Logger.GetInstance(); Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); - } + }*/ traceData.fullyQualifiedTypeName = objectClassName; traceData.dataAsXml = serializedString; - traceData.dataAsJson = serializedJsonString; + //traceData.dataAsJson = serializedJsonString; traceData.instanceId = instanceId; return traceData; diff --git a/Maestro/build.gradle b/Maestro/build.gradle index b4a2bc7d..7de5947e 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -1,12 +1,26 @@ plugins { - id 'java' + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' } -group = 'com.github.gilesi' -version = '1.0-SNAPSHOT' +group 'com.github.gilesi.maestro' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} repositories { mavenCentral() + mavenLocal() + maven { + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } } dependencies { @@ -21,6 +35,45 @@ dependencies { testImplementation 'org.junit.jupiter:junit-jupiter' } -test { - useJUnitPlatform() +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.maestro.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.maestro.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.maestro') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.maestro' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=2G" + ] } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index d85d50fd..5410e70b 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -4,19 +4,17 @@ import java.util.Map; public class Constants { - public static final String GILESI_REPOSITORY_LOCATION = "/home/gus/Git/gilesi"; - // These paths should already exist on the end user machine for now and never change - public static final String CONF_GEN_LOCATION = GILESI_REPOSITORY_LOCATION + "/ConfGen/build/libs/com.github.gilesi.confgen.jar"; - public static final String TEST_GEN_LOCATION = GILESI_REPOSITORY_LOCATION + "/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; - public static final String INSTRUMENTATION_LOCATION = GILESI_REPOSITORY_LOCATION + "/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; + public static final String CONF_GEN_LOCATION = "/ConfGen/build/libs/com.github.gilesi.confgen.jar"; + public static final String TEST_GEN_LOCATION = "/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; + public static final String INSTRUMENTATION_LOCATION = "/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"; // These paths are dynamically created by the tool but must stay consistent within methods public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; public static final String targetConfigurationName = "TestWorkflowConfiguration.xml"; - public static final String traceResultsLocation = GILESI_REPOSITORY_LOCATION + "/Results"; + public static final String traceResultsLocation = "/Results"; public static final Map JAVA_VERSIONS = new Hashtable<>() { { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 2d4faa1a..6fd91d6c 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -3,8 +3,6 @@ import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.testing.surefire.FileUtils; -import com.github.gilesi.maestro.testing.surefire.ReportItem; -import com.github.gilesi.maestro.testing.surefire.SurefireHarness; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; @@ -23,11 +21,19 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP return; } - handleProject("/home/gus/Datasets/compsuite/repos/AthenaX", "/home/gus/.m2/repository/org/apache/flink/flink-core/1.5.0/sources"); + if (args.length != 3) { + System.out.println("Usage: "); + return; + } + + handleProject(args[0], args[1], args[2]); } - private static void runExternalCommand(String[] command) throws IOException, InterruptedException { + private static void runExternalCommand(String[] command, File directory) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(command); + if (directory != null) { + pb.directory(directory); + } pb.redirectErrorStream(true); Process p = pb.start(); BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); @@ -41,18 +47,23 @@ private static void runExternalCommand(String[] command) throws IOException, Int p.waitFor(); } - private static void cleanup(String clientLocation) throws IOException { - Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); + private static void cleanup(String clientLocation, String GilesiRepositoryLocation) throws IOException { + Path traceResultsLocationPath = Path.of(GilesiRepositoryLocation + Constants.traceResultsLocation); if (Files.exists(traceResultsLocationPath)) { - FileUtils.deleteDirectory(new File(Constants.traceResultsLocation)); + FileUtils.deleteDirectory(new File(GilesiRepositoryLocation + Constants.traceResultsLocation)); } ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - for (String clientPomFile : clientProjectPomFiles) { - Path clientPomFilePath = Path.of(clientPomFile); - Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); @@ -66,13 +77,13 @@ private static void cleanup(String clientLocation) throws IOException { } } - private static void handleProject(String clientLocation, String libraryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + private static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - Path traceResultsLocationPath = Path.of(Constants.traceResultsLocation); + Path traceResultsLocationPath = Path.of(GilesiRepositoryLocation + Constants.traceResultsLocation); // First, perform some preliminary cleanup in case we already ran previously - cleanup(clientLocation); + cleanup(clientLocation, GilesiRepositoryLocation); // Create the results directory Files.createDirectories(traceResultsLocationPath); @@ -81,16 +92,18 @@ private static void handleProject(String clientLocation, String libraryLocation) runExternalCommand(new String[]{ Constants.JAVA_21_BINARY_LOCATION, "-jar", - Constants.CONF_GEN_LOCATION, + GilesiRepositoryLocation + Constants.CONF_GEN_LOCATION, libraryConfig.toString(), - Constants.traceResultsLocation, + GilesiRepositoryLocation + Constants.traceResultsLocation, libraryLocation, clientLocation - }); + }, null); // Modify Client Build System to use the instrumentation agent ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + Path InstrumentationAgentEffectiveLocation = Path.of(GilesiRepositoryLocation + Constants.INSTRUMENTATION_LOCATION); + for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); @@ -98,47 +111,77 @@ private static void handleProject(String clientLocation, String libraryLocation) Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - Files.copy(Path.of(Constants.INSTRUMENTATION_LOCATION), agentDest); + Files.copy(InstrumentationAgentEffectiveLocation, agentDest); Files.copy(libraryConfig, workflowDest); PomHelper.addSureFire(clientPomFile, clientSurefireArgLine); } - // Run the client tests - ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "1.8"); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - // Collect test results of the client test runs - for (String pomFile : clientProjectPomFiles) { - ArrayList testReports = SurefireHarness.getProjectTestReports("testName", "testCommit", pomFile); - int success = 0; - int failure = 0; + for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { + Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); + Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - for (ReportItem testReport : testReports) { - if (testReport.getTestResult().equals(Constants.GREEN_TEST)) { - success++; - } + Files.copy(InstrumentationAgentEffectiveLocation, agentDest); + Files.copy(libraryConfig, workflowDest); + + // TODO: Edit of gradle config + } - if (testReport.getTestResult().equals(Constants.RED_TEST)) { - failure++; + // Run the client tests + // This is the maven path + if (!clientProjectPomFiles.isEmpty()) { + if (clientProjectPomFiles.stream().anyMatch(t -> t.replace(clientLocation + "//", "").replace(clientLocation, "").equals("pom.xml"))) { + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "1.8"); + } else { + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "1.8"); } } + } - System.out.printf("Project: %s%n", pomFile); - System.out.printf("Total number of tests: %d%n", testReports.size()); - System.out.printf("Total number of greens: %d%n", success); - System.out.printf("Total number of reds: %d%n", failure); + // This is the gradle path + if (!clientProjectGradleBuildFiles.isEmpty()) { + if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace(clientLocation + "//", "").replace(clientLocation, "").equals("build.gradle"))) { + runExternalCommand(new String[]{ + "/bin/sh", + clientLocation + "/gradlew", + "test", + "--warning-mode", + "all" + }, new File(clientLocation)); + } else { + for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { + Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); + Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); + + runExternalCommand(new String[]{ + "/bin/sh", + clientProjectLocationPath + "/gradlew", + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString())); + } + } } // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles(Constants.traceResultsLocation, "MethodTraces_.*\\.xml", false); + ArrayList traceFiles = FileUtils.enumerateFiles(GilesiRepositoryLocation + Constants.traceResultsLocation, "MethodTraces_.*\\.xml", false); for (String traceFile : traceFiles) { runExternalCommand(new String[]{ Constants.JAVA_21_BINARY_LOCATION, "-jar", - Constants.TEST_GEN_LOCATION, + GilesiRepositoryLocation + Constants.TEST_GEN_LOCATION, traceFile, - Constants.traceResultsLocation // output - }); + GilesiRepositoryLocation + Constants.traceResultsLocation // output + }, null); } } } \ No newline at end of file diff --git a/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml b/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml new file mode 100644 index 00000000..718e18af --- /dev/null +++ b/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml @@ -0,0 +1,204 @@ + + + + com.github.gilesi.samples.samplelibrary.Foo2 + + + triuetyg + + (I)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + njrhbgtujhu + + (Ljava/util/Collection;)Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + jhgbjtjbh + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A2 + + + getOurselves + + ()Lcom/github/gilesi/samples/samplelibrary/A2; + + + + foo + + (I)I + + + + sideEffect + + ()V + + + + + (I)V + + + + com.github.gilesi.samples.samplelibrary.Foo + + + HelloEveryone2 + + (Ljava/util/Collection;)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + meaningof + + (I)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + HelloEveryone + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A + + + CallBack + + (Lcom/github/gilesi/samples/samplelibrary/IDoSomething;)V + + + + foo + + (I)I + + + + + (I)V + + + + + CTest.ClientATest + CTest.Test + FooTest.TestFoo + FooTest.TestFooIsLifeNice + FooTest.mainTest + com.github.gilesi.samples.sampleclient.C1.Do + com.github.gilesi.samples.sampleclient.C2.bar + com.github.gilesi.samples.sampleclient.Main.DoWork + com.github.gilesi.samples.sampleclient.Main.main + com.github.gilesi.samples.sampleclient.Main2.main + + + CTest.CTest + FooTest.FooTest + com.github.gilesi.samples.sampleclient.C1.C1 + com.github.gilesi.samples.sampleclient.C2.C2 + com.github.gilesi.samples.sampleclient.Main.Main + com.github.gilesi.samples.sampleclient.Main2.Main2 + + + com.github.gilesi.samples.samplelibrary.A.CallBack + com.github.gilesi.samples.samplelibrary.A.foo + com.github.gilesi.samples.samplelibrary.A2.foo + com.github.gilesi.samples.samplelibrary.A2.getOurselves + com.github.gilesi.samples.samplelibrary.A2.sideEffect + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone2 + com.github.gilesi.samples.samplelibrary.Foo.TESTING + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hellow + com.github.gilesi.samples.samplelibrary.Foo.meaningof + com.github.gilesi.samples.samplelibrary.Foo.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.TESTING + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hellow + com.github.gilesi.samples.samplelibrary.Foo2.jhgbjtjbh + com.github.gilesi.samples.samplelibrary.Foo2.njrhbgtujhu + com.github.gilesi.samples.samplelibrary.Foo2.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.triuetyg + com.github.gilesi.samples.samplelibrary.IDoSomething.Do + + + com.github.gilesi.samples.samplelibrary.A.A + com.github.gilesi.samples.samplelibrary.A2.A2 + com.github.gilesi.samples.samplelibrary.Foo.Foo + com.github.gilesi.samples.samplelibrary.Foo2.Foo2 + com.github.gilesi.samples.samplelibrary.IDoSomething.IDoSomething + + /home/gus/Git/gilesi/Results + \ No newline at end of file diff --git a/Samples/Gradle/sampleclient/gradle/wrapper/gradle-wrapper.jar b/Samples/Gradle/sampleclient/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/Samples/Gradle/sampleclient/gradlew.bat b/Samples/Gradle/sampleclient/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/Samples/Gradle/sampleclient/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Samples/Gradle/samplelibrary/TestWorkflowConfiguration.xml b/Samples/Gradle/samplelibrary/TestWorkflowConfiguration.xml new file mode 100644 index 00000000..718e18af --- /dev/null +++ b/Samples/Gradle/samplelibrary/TestWorkflowConfiguration.xml @@ -0,0 +1,204 @@ + + + + com.github.gilesi.samples.samplelibrary.Foo2 + + + triuetyg + + (I)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + njrhbgtujhu + + (Ljava/util/Collection;)Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + jhgbjtjbh + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A2 + + + getOurselves + + ()Lcom/github/gilesi/samples/samplelibrary/A2; + + + + foo + + (I)I + + + + sideEffect + + ()V + + + + + (I)V + + + + com.github.gilesi.samples.samplelibrary.Foo + + + HelloEveryone2 + + (Ljava/util/Collection;)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + meaningof + + (I)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + HelloEveryone + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A + + + CallBack + + (Lcom/github/gilesi/samples/samplelibrary/IDoSomething;)V + + + + foo + + (I)I + + + + + (I)V + + + + + CTest.ClientATest + CTest.Test + FooTest.TestFoo + FooTest.TestFooIsLifeNice + FooTest.mainTest + com.github.gilesi.samples.sampleclient.C1.Do + com.github.gilesi.samples.sampleclient.C2.bar + com.github.gilesi.samples.sampleclient.Main.DoWork + com.github.gilesi.samples.sampleclient.Main.main + com.github.gilesi.samples.sampleclient.Main2.main + + + CTest.CTest + FooTest.FooTest + com.github.gilesi.samples.sampleclient.C1.C1 + com.github.gilesi.samples.sampleclient.C2.C2 + com.github.gilesi.samples.sampleclient.Main.Main + com.github.gilesi.samples.sampleclient.Main2.Main2 + + + com.github.gilesi.samples.samplelibrary.A.CallBack + com.github.gilesi.samples.samplelibrary.A.foo + com.github.gilesi.samples.samplelibrary.A2.foo + com.github.gilesi.samples.samplelibrary.A2.getOurselves + com.github.gilesi.samples.samplelibrary.A2.sideEffect + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone2 + com.github.gilesi.samples.samplelibrary.Foo.TESTING + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hellow + com.github.gilesi.samples.samplelibrary.Foo.meaningof + com.github.gilesi.samples.samplelibrary.Foo.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.TESTING + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hellow + com.github.gilesi.samples.samplelibrary.Foo2.jhgbjtjbh + com.github.gilesi.samples.samplelibrary.Foo2.njrhbgtujhu + com.github.gilesi.samples.samplelibrary.Foo2.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.triuetyg + com.github.gilesi.samples.samplelibrary.IDoSomething.Do + + + com.github.gilesi.samples.samplelibrary.A.A + com.github.gilesi.samples.samplelibrary.A2.A2 + com.github.gilesi.samples.samplelibrary.Foo.Foo + com.github.gilesi.samples.samplelibrary.Foo2.Foo2 + com.github.gilesi.samples.samplelibrary.IDoSomething.IDoSomething + + /home/gus/Git/gilesi/Results + \ No newline at end of file diff --git a/Samples/Gradle/samplelibrary/gradle/wrapper/gradle-wrapper.jar b/Samples/Gradle/samplelibrary/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/Samples/Gradle/samplelibrary/gradlew.bat b/Samples/Gradle/samplelibrary/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/Samples/Gradle/samplelibrary/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Samples/Maven/sampleclient/pom.xml b/Samples/Maven/sampleclient/pom.xml index e0b4512b..f9e7e276 100644 --- a/Samples/Maven/sampleclient/pom.xml +++ b/Samples/Maven/sampleclient/pom.xml @@ -1,52 +1,54 @@ - - 4.0.0 - - sampleclient + + 4.0.0 + + com.github.gilesi.samples + sample2 1.0-SNAPSHOT - - - - org.apache.maven.plugins - maven-compiler-plugin - - 16 - 16 - - - - - - - com.github.gilesi.samples - sample2 - 1.0-SNAPSHOT - - jar - - - 11 - 11 - - - - junit - junit - 4.13.2 - test - - - com.github.gilesi.samples - samplelibrary - 1.0-SNAPSHOT - - - org.junit.jupiter - junit-jupiter-engine - 5.11.0-M2 - test - - - \ No newline at end of file + + sampleclient + 1.0-SNAPSHOT + + 11 + 11 + + + + junit + junit + 4.13.2 + test + + + com.github.gilesi.samples + samplelibrary + 1.0-SNAPSHOT + + + org.junit.jupiter + junit-jupiter-engine + 5.11.0-M2 + test + + + + + + maven-surefire-plugin + 3.2.5 + + 1 + false + -Dnet.bytebuddy.experimental=true -javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml + methods + 1 + 40 + 40 + 30 + 30 + + + + + diff --git a/compile.sh b/compile.sh index 862f27b4..02f7a5c3 100644 --- a/compile.sh +++ b/compile.sh @@ -32,4 +32,16 @@ echo # build tool cd Instrumentation sh ./gradlew shadowJar --warning-mode all -cd .. \ No newline at end of file +cd .. + +echo +echo =========================================================== +echo Building Maestro +echo =========================================================== +echo + +# build maestro +cd Maestro +sh ./gradlew shadowJar --warning-mode all +cd .. + From 42e3bad88127b7fea422ad1d2cda2518c39ecbbc Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 29 May 2024 15:21:48 +0200 Subject: [PATCH 117/244] Cleanup --- .../java/com/github/gilesi/maestro/Main.java | 26 +++++++++---------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 6fd91d6c..a11adfe7 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -48,10 +48,10 @@ private static void runExternalCommand(String[] command, File directory) throws } private static void cleanup(String clientLocation, String GilesiRepositoryLocation) throws IOException { - Path traceResultsLocationPath = Path.of(GilesiRepositoryLocation + Constants.traceResultsLocation); + Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); if (Files.exists(traceResultsLocationPath)) { - FileUtils.deleteDirectory(new File(GilesiRepositoryLocation + Constants.traceResultsLocation)); + FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); } ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); @@ -80,7 +80,7 @@ private static void cleanup(String clientLocation, String GilesiRepositoryLocati private static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - Path traceResultsLocationPath = Path.of(GilesiRepositoryLocation + Constants.traceResultsLocation); + Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); // First, perform some preliminary cleanup in case we already ran previously cleanup(clientLocation, GilesiRepositoryLocation); @@ -92,9 +92,9 @@ private static void handleProject(String clientLocation, String libraryLocation, runExternalCommand(new String[]{ Constants.JAVA_21_BINARY_LOCATION, "-jar", - GilesiRepositoryLocation + Constants.CONF_GEN_LOCATION, + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), libraryConfig.toString(), - GilesiRepositoryLocation + Constants.traceResultsLocation, + "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), libraryLocation, clientLocation }, null); @@ -102,7 +102,7 @@ private static void handleProject(String clientLocation, String libraryLocation, // Modify Client Build System to use the instrumentation agent ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); - Path InstrumentationAgentEffectiveLocation = Path.of(GilesiRepositoryLocation + Constants.INSTRUMENTATION_LOCATION); + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); @@ -134,7 +134,7 @@ private static void handleProject(String clientLocation, String libraryLocation, // Run the client tests // This is the maven path if (!clientProjectPomFiles.isEmpty()) { - if (clientProjectPomFiles.stream().anyMatch(t -> t.replace(clientLocation + "//", "").replace(clientLocation, "").equals("pom.xml"))) { + if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "1.8"); } else { for (String clientPomFile : clientProjectPomFiles) { @@ -148,10 +148,10 @@ private static void handleProject(String clientLocation, String libraryLocation, // This is the gradle path if (!clientProjectGradleBuildFiles.isEmpty()) { - if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace(clientLocation + "//", "").replace(clientLocation, "").equals("build.gradle"))) { + if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("build.gradle"))) { runExternalCommand(new String[]{ "/bin/sh", - clientLocation + "/gradlew", + "%s/gradlew".formatted(clientLocation), "test", "--warning-mode", "all" @@ -163,7 +163,7 @@ private static void handleProject(String clientLocation, String libraryLocation, runExternalCommand(new String[]{ "/bin/sh", - clientProjectLocationPath + "/gradlew", + "%s/gradlew".formatted(clientProjectLocationPath), "test", "--warning-mode", "all" @@ -173,14 +173,14 @@ private static void handleProject(String clientLocation, String libraryLocation, } // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles(GilesiRepositoryLocation + Constants.traceResultsLocation, "MethodTraces_.*\\.xml", false); + ArrayList traceFiles = FileUtils.enumerateFiles("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), "MethodTraces_.*\\.xml", false); for (String traceFile : traceFiles) { runExternalCommand(new String[]{ Constants.JAVA_21_BINARY_LOCATION, "-jar", - GilesiRepositoryLocation + Constants.TEST_GEN_LOCATION, + "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), traceFile, - GilesiRepositoryLocation + Constants.traceResultsLocation // output + "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation) // output }, null); } } From 45e3ae5b6dc1848668ed6f7ed5eae6681f880ac6 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 10:36:56 +0200 Subject: [PATCH 118/244] Enable support for gradle projects --- .../java/com/github/gilesi/maestro/Main.java | 98 ++++++++++--------- 1 file changed, 52 insertions(+), 46 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index a11adfe7..c8d8c6f8 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -47,43 +47,15 @@ private static void runExternalCommand(String[] command, File directory) throws p.waitFor(); } - private static void cleanup(String clientLocation, String GilesiRepositoryLocation) throws IOException { - Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); - - if (Files.exists(traceResultsLocationPath)) { - FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); - } - - ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); - ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - - ArrayList allProjectFiles = new ArrayList<>(); - allProjectFiles.addAll(clientProjectPomFiles); - allProjectFiles.addAll(clientProjectGradleBuildFiles); - - for (String clientBuildFile : allProjectFiles) { - Path clientBuildFilePath = Path.of(clientBuildFile); - Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); - Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); - Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - - if (Files.exists(agentDest)) { - Files.delete(agentDest); - } - - if (Files.exists(workflowDest)) { - Files.delete(workflowDest); - } - } - } - private static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); // First, perform some preliminary cleanup in case we already ran previously - cleanup(clientLocation, GilesiRepositoryLocation); + if (Files.exists(traceResultsLocationPath)) { + FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); + } // Create the results directory Files.createDirectories(traceResultsLocationPath); @@ -99,36 +71,70 @@ private static void handleProject(String clientLocation, String libraryLocation, clientLocation }, null); + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + // Modify Client Build System to use the instrumentation agent ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); - for (String clientPomFile : clientProjectPomFiles) { - Path clientPomFilePath = Path.of(clientPomFile); - Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.delete(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); Files.copy(InstrumentationAgentEffectiveLocation, agentDest); Files.copy(libraryConfig, workflowDest); + } - PomHelper.addSureFire(clientPomFile, clientSurefireArgLine); + for (String clientBuildFile : clientProjectPomFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); } - ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + for (String clientBuildFile : clientProjectGradleBuildFiles) { + String clientTestingBlock = """ + testing { + \tsuites { + \t\ttest { + \t\t\tuseJUnitJupiter() + \t\t\ttargets { + \t\t\t\tall { + \t\t\t\t\ttestTask.configure { + \t\t\t\t\t\tsystemProperty 'net.bytebuddy.experimental', 'true' + \t\t\t\t\t\tjvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:%s=%s'] + \t\t\t\t\t} + \t\t\t\t} + \t\t\t} + \t\t} + \t} + }""".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { - Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); - Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); - Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); - Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + Path clientBuildFilePath = Path.of(clientBuildFile); - Files.copy(InstrumentationAgentEffectiveLocation, agentDest); - Files.copy(libraryConfig, workflowDest); + String buildFileContent = Files.readString(clientBuildFilePath); + if (!buildFileContent.contains(clientTestingBlock)) { + buildFileContent += "\n" + clientTestingBlock; - // TODO: Edit of gradle config + Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + Files.writeString(clientBuildFilePath, buildFileContent); + } } // Run the client tests From 2c2d90f1606963a296ca68d26788fd32d9d01407 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 10:37:08 +0200 Subject: [PATCH 119/244] Add missing Xml function in test gen --- .../com/github/gilesi/testgenerator/Main.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 08944d2c..4e0e1504 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -4,6 +4,7 @@ import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; +import com.github.gilesi.testgenerator.exceptions.SerializationException; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; @@ -21,7 +22,7 @@ private static TestTraceResults[] readTraces(String filePathStr) throws IOExcept return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new); } - public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException { + public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { String traceXml = args[0]; String testPath = args[1]; @@ -84,6 +85,7 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); + stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); stringBuilder.append("import org.junit.jupiter.api.Test;\n"); stringBuilder.append("\n"); @@ -132,6 +134,18 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine \t} """); + stringBuilder.append(""" + + \t@SuppressWarnings("unchecked") + \tpublic static T getFromXml(String xmlString) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\txStream.addPermission(AnyTypePermission.ANY); + \t\tObject obj = xStream.fromXML(xmlString); + \t\treturn (T) obj; + \t} + """); + stringBuilder.append("}\n"); stringBuilder.append("\n"); From 63762f1d8692d03f983eebd4697899cc396d1c97 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 10:37:19 +0200 Subject: [PATCH 120/244] Fix a typo in a comment in test gen --- .../com/github/gilesi/testgenerator/SerializationUtils.java | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index e6b734cd..8b212e52 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -58,9 +58,9 @@ public static String serializableDataToJava(TraceData serializableData) { !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - // Casting is not needed if we only use this with variable assignements that are strictly typed - // valueToBeEqualTo = "(%s) (XmlUtils.getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); - valueToBeEqualTo = "XmlUtils.getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + // Casting is not needed if we only use this with variable assignments that are strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.dataAsXml)); } else { valueToBeEqualTo = valueToBeEqualTo.split("[><]")[2]; From d4f3587a31a7f2f99f36439772a2f247ff0ce5d0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 10:37:51 +0200 Subject: [PATCH 121/244] Enable doing assertions using "true equality" instead of serialisation equality Gate this behind a hardcoded flag for now --- .../testgenerator/TestMethodGenerator.java | 81 ++++++++----------- 1 file changed, 35 insertions(+), 46 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index e2b163de..ca3f3fb6 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -11,31 +11,22 @@ import java.util.List; public class TestMethodGenerator { - private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler) throws SerializationException, InstanceNotDefinedException { + private static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; + + private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException, InstanceNotDefinedException { if (arg.dataAsXml != null) { if (arg.dataAsXml.equals("null")) { return arg.dataAsXml; } String dataLine = SerializationUtils.serializableDataToJava(arg); - if (arg.fullyQualifiedTypeName.contains("$$Lambda/")) { + if (failOnLambdas && arg.fullyQualifiedTypeName.contains("$$Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } return dataLine; } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { return variableStackHandler.getInstanceVariableName(arg.instanceId); - } else { + } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); - } - } - - private static String serializableDataToCode2(TraceData arg, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException { - if (arg.dataAsXml != null) { - if (arg.dataAsXml.equals("null")) { - return arg.dataAsXml; - } - return SerializationUtils.serializableDataToJava(arg); - } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { - return variableStackHandler.getInstanceVariableName(arg.instanceId); } else { return "// Unserializable data with instance id: " + arg.instanceId; } @@ -127,7 +118,7 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler return methodCall; } - private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceAlreadyDefinedException, InstanceNotDefinedException { + private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { String methodCall = traceToMethodCall(methodTrace, variableStackHandler); List preCallArguments = new ArrayList<>(); @@ -138,10 +129,10 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab for (TraceData preCallArgument : methodTrace.getPreCallArguments()) { String argumentValue; try { - argumentValue = serializableDataToCode(preCallArgument, variableStackHandler); + argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, true); } catch (SerializationException e) { - argumentValue = serializableDataToCode2(preCallArgument, variableStackHandler); + argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, false); commentItAll = true; } @@ -174,49 +165,47 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab return code; } - private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, SerializationException { + private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { int instanceId = traceData.instanceId; String dataAsXml = traceData.dataAsXml; if (dataAsXml != null) { + String instanceVarName = variableStackHandler.getInstanceVariableName(instanceId); + if (dataAsXml.equals("null")) { - return "assertEquals(null, %s);".formatted(variableStackHandler.getInstanceVariableName(instanceId)); + return "assertEquals(null, %s);".formatted(instanceVarName); } - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - String assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); - - if (traceData.fullyQualifiedTypeName.contains("$$Lambda/")) { + if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("$$Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } - return assertionLine; - } else if (variableStackHandler.isInstanceVariableNameDefined(instanceId)) { - return "// assertEquals(%s, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId), variableStackHandler.getInstanceVariableName(instanceId)); - } else { - throw new SerializationException("We cannot serialize this!"); - } - } + String assertionLine; - private static String getAssertionCodeLine2(TraceData traceData, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException { - int instanceId = traceData.instanceId; - String dataAsXml = traceData.dataAsXml; + if (useAltAssertionMode) { + String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); - if (dataAsXml != null) { - if (dataAsXml.equals("null")) { - return "assertEquals(null, %s);".formatted(variableStackHandler.getInstanceVariableName(instanceId)); + if (valueAsCode.endsWith("[].class)")) { + assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } else { + assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } + } else { + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); + assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); } - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - return "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, variableStackHandler.getInstanceVariableName(instanceId)); + return assertionLine; } else if (variableStackHandler.isInstanceVariableNameDefined(instanceId)) { - return "// assertEquals(%s, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId), variableStackHandler.getInstanceVariableName(instanceId)); + return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId)); + } else if (failOnLambdas) { + throw new SerializationException("We cannot serialize this!"); } else { return "// Unserializable data with instance id: %d".formatted(traceData.instanceId); } } - private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceNotDefinedException { + private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceNotDefinedException, SerializationException { List argList = new ArrayList<>(); for (TraceData traceData : methodTrace.getPostCallArguments()) { @@ -228,10 +217,10 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan // We return a value that we managed to serialize String assertionCodeLine; try { - assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler); + assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getAssertionCodeLine2(traceData, variableStackHandler)); + assertionCodeLine = "// %s".formatted(getAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); } argList.add(assertionCodeLine); } @@ -239,7 +228,7 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan return String.join("\n%s".formatted(indentationPrefix), argList); } - private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException { + private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, SerializationException { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().fullyQualifiedTypeName.equals(cleanedMethodName); @@ -249,10 +238,10 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari if (!isConstructor && traceData != null) { String assertionCodeLine; try { - assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler); + assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getAssertionCodeLine2(traceData, variableStackHandler)); + assertionCodeLine = "// %s".formatted(getAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); } return assertionCodeLine; } @@ -260,7 +249,7 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari return null; } - public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix, boolean addAssertsForArgumentsPostCall) throws InstanceAlreadyDefinedException, InstanceNotDefinedException { + public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix, boolean addAssertsForArgumentsPostCall) throws InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { String traceCode = ""; String methodCallLine = traceToCode(trace, variableStackHandler, indentationPrefix); From 5ddcc4b44ad7a077f2ecf70507f281fccd8705f5 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 11:07:55 +0200 Subject: [PATCH 122/244] Fix: gradle support on some systems --- .../src/main/java/com/github/gilesi/maestro/Main.java | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index c8d8c6f8..25e7b666 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -89,7 +89,7 @@ private static void handleProject(String clientLocation, String libraryLocation, Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); if (Files.exists(clientBuildFileBackup)) { - Files.delete(clientBuildFilePath); + Files.deleteIfExists(clientBuildFilePath); Files.move(clientBuildFileBackup, clientBuildFilePath); } @@ -102,7 +102,7 @@ private static void handleProject(String clientLocation, String libraryLocation, for (String clientBuildFile : clientProjectPomFiles) { Path clientBuildFilePath = Path.of(clientBuildFile); - Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); @@ -156,7 +156,8 @@ private static void handleProject(String clientLocation, String libraryLocation, if (!clientProjectGradleBuildFiles.isEmpty()) { if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("build.gradle"))) { runExternalCommand(new String[]{ - "/bin/sh", + "/usr/bin/env", + "bash", "%s/gradlew".formatted(clientLocation), "test", "--warning-mode", @@ -168,7 +169,8 @@ private static void handleProject(String clientLocation, String libraryLocation, Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); runExternalCommand(new String[]{ - "/bin/sh", + "/usr/bin/env", + "bash", "%s/gradlew".formatted(clientProjectLocationPath), "test", "--warning-mode", From 5433f85c95e9378ea9169b7fb878a62d8457d296 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 11:22:33 +0200 Subject: [PATCH 123/244] fix: Java 21 project support --- .../main/java/com/github/gilesi/maestro/Constants.java | 2 +- Maestro/src/main/java/com/github/gilesi/maestro/Main.java | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index 5410e70b..1f8cf804 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -9,7 +9,7 @@ public class Constants { public static final String TEST_GEN_LOCATION = "/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; public static final String INSTRUMENTATION_LOCATION = "/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; - public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64/bin/java"; + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64"; // These paths are dynamically created by the tool but must stay consistent within methods public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 25e7b666..1d5c3dcc 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -62,7 +62,7 @@ private static void handleProject(String clientLocation, String libraryLocation, // Run ConfGen on Library first runExternalCommand(new String[]{ - Constants.JAVA_21_BINARY_LOCATION, + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), "-jar", "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), libraryConfig.toString(), @@ -141,13 +141,13 @@ private static void handleProject(String clientLocation, String libraryLocation, // This is the maven path if (!clientProjectPomFiles.isEmpty()) { if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { - ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "1.8"); + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "21"); } else { for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); - ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "1.8"); + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "21"); } } } @@ -184,7 +184,7 @@ private static void handleProject(String clientLocation, String libraryLocation, ArrayList traceFiles = FileUtils.enumerateFiles("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), "MethodTraces_.*\\.xml", false); for (String traceFile : traceFiles) { runExternalCommand(new String[]{ - Constants.JAVA_21_BINARY_LOCATION, + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), "-jar", "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), traceFile, From e3de8f4e1ed2e127cef189039cc7217184f2dab6 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 11:28:43 +0200 Subject: [PATCH 124/244] fix: cleanup bak files after execution --- .../java/com/github/gilesi/maestro/Main.java | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 1d5c3dcc..724e2904 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -191,5 +191,22 @@ private static void handleProject(String clientLocation, String libraryLocation, "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation) // output }, null); } + + // Last minute cleanup + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + } } } \ No newline at end of file From b1204e57bcbac36238b838288df4f8fe9063941e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 13:57:50 +0200 Subject: [PATCH 125/244] cleanup --- .../java/com/github/gilesi/maestro/Main.java | 192 +---------------- .../github/gilesi/maestro/Orchestrator.java | 204 ++++++++++++++++++ .../github/gilesi/maestro/ProcessUtils.java | 26 +++ 3 files changed, 234 insertions(+), 188 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 724e2904..72bcb085 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -1,18 +1,11 @@ package com.github.gilesi.maestro; -import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; -import com.github.gilesi.maestro.runners.maven.ProjectRunner; -import com.github.gilesi.maestro.testing.surefire.FileUtils; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; -import java.io.BufferedReader; -import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; import java.nio.file.Files; import java.nio.file.Path; -import java.util.ArrayList; public class Main { public static void main(String[] args) throws MavenInvocationException, XmlPullParserException, IOException, InterruptedException { @@ -26,187 +19,10 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP return; } - handleProject(args[0], args[1], args[2]); - } - - private static void runExternalCommand(String[] command, File directory) throws IOException, InterruptedException { - ProcessBuilder pb = new ProcessBuilder(command); - if (directory != null) { - pb.directory(directory); - } - pb.redirectErrorStream(true); - Process p = pb.start(); - BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); - - String line; - - while ((line = reader.readLine()) != null) { - System.out.println(line); - } - - p.waitFor(); - } - - private static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { - Path libraryLocationPath = Path.of(libraryLocation); - Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); - - // First, perform some preliminary cleanup in case we already ran previously - if (Files.exists(traceResultsLocationPath)) { - FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); - } - - // Create the results directory - Files.createDirectories(traceResultsLocationPath); - - // Run ConfGen on Library first - runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), - libraryConfig.toString(), - "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), - libraryLocation, - clientLocation - }, null); - - Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); - - // Modify Client Build System to use the instrumentation agent - ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); - ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - - ArrayList allProjectFiles = new ArrayList<>(); - allProjectFiles.addAll(clientProjectPomFiles); - allProjectFiles.addAll(clientProjectGradleBuildFiles); - - for (String clientBuildFile : allProjectFiles) { - Path clientBuildFilePath = Path.of(clientBuildFile); - Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); - Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); - Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - - Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); - if (Files.exists(clientBuildFileBackup)) { - Files.deleteIfExists(clientBuildFilePath); - Files.move(clientBuildFileBackup, clientBuildFilePath); - } - - Files.deleteIfExists(agentDest); - Files.deleteIfExists(workflowDest); - - Files.copy(InstrumentationAgentEffectiveLocation, agentDest); - Files.copy(libraryConfig, workflowDest); - } - - for (String clientBuildFile : clientProjectPomFiles) { - Path clientBuildFilePath = Path.of(clientBuildFile); - Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); - - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); - } - - for (String clientBuildFile : clientProjectGradleBuildFiles) { - String clientTestingBlock = """ - testing { - \tsuites { - \t\ttest { - \t\t\tuseJUnitJupiter() - \t\t\ttargets { - \t\t\t\tall { - \t\t\t\t\ttestTask.configure { - \t\t\t\t\t\tsystemProperty 'net.bytebuddy.experimental', 'true' - \t\t\t\t\t\tjvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:%s=%s'] - \t\t\t\t\t} - \t\t\t\t} - \t\t\t} - \t\t} - \t} - }""".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - - Path clientBuildFilePath = Path.of(clientBuildFile); - - String buildFileContent = Files.readString(clientBuildFilePath); - if (!buildFileContent.contains(clientTestingBlock)) { - buildFileContent += "\n" + clientTestingBlock; - - Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); - Files.writeString(clientBuildFilePath, buildFileContent); - } - } - - // Run the client tests - // This is the maven path - if (!clientProjectPomFiles.isEmpty()) { - if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { - ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "21"); - } else { - for (String clientPomFile : clientProjectPomFiles) { - Path clientPomFilePath = Path.of(clientPomFile); - Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + String clientLocation = args[0]; + String libraryLocation = args[1]; + String gilesiRepositoryLocation = args[2]; - ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "21"); - } - } - } - - // This is the gradle path - if (!clientProjectGradleBuildFiles.isEmpty()) { - if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("build.gradle"))) { - runExternalCommand(new String[]{ - "/usr/bin/env", - "bash", - "%s/gradlew".formatted(clientLocation), - "test", - "--warning-mode", - "all" - }, new File(clientLocation)); - } else { - for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { - Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); - Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); - - runExternalCommand(new String[]{ - "/usr/bin/env", - "bash", - "%s/gradlew".formatted(clientProjectLocationPath), - "test", - "--warning-mode", - "all" - }, new File(clientProjectLocationPath.toString())); - } - } - } - - // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), "MethodTraces_.*\\.xml", false); - for (String traceFile : traceFiles) { - runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), - traceFile, - "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation) // output - }, null); - } - - // Last minute cleanup - for (String clientBuildFile : allProjectFiles) { - Path clientBuildFilePath = Path.of(clientBuildFile); - Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); - Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); - Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); - - Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); - if (Files.exists(clientBuildFileBackup)) { - Files.deleteIfExists(clientBuildFilePath); - Files.move(clientBuildFileBackup, clientBuildFilePath); - } - - Files.deleteIfExists(agentDest); - Files.deleteIfExists(workflowDest); - } + Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java new file mode 100644 index 00000000..3749c70a --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -0,0 +1,204 @@ +package com.github.gilesi.maestro; + +import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; +import com.github.gilesi.maestro.runners.maven.ProjectRunner; +import com.github.gilesi.maestro.testing.surefire.FileUtils; +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Orchestrator { + public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); + + // First, perform some preliminary cleanup in case we already ran previously + if (Files.exists(traceResultsLocationPath)) { + FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); + } + + // Create the results directory + Files.createDirectories(traceResultsLocationPath); + + // Run ConfGen on Library first + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), + libraryConfig.toString(), + "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), + libraryLocation, + clientLocation + }, null); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + orchestrateMavenProjects(clientProjectPomFiles); + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + // Run the client tests + executeMavenProjectTests(clientProjectPomFiles, clientLocation); + executeGradleProjectTests(clientProjectGradleBuildFiles, clientLocation); + + tracesToCode(GilesiRepositoryLocation); + + lastMinuteCleanup(allProjectFiles); + } + + private static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + + Files.copy(InstrumentationAgentEffectiveLocation, agentDest); + Files.copy(libraryConfig, workflowDest); + } + } + + private static void orchestrateMavenProjects(ArrayList clientProjectPomFiles) throws IOException, XmlPullParserException { + for (String clientBuildFile : clientProjectPomFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); + } + } + + private static void orchestrateGradleProjects(ArrayList clientProjectGradleBuildFiles) throws IOException { + for (String clientBuildFile : clientProjectGradleBuildFiles) { + String clientTestingBlock = """ + testing { + \tsuites { + \t\ttest { + \t\t\tuseJUnitJupiter() + \t\t\ttargets { + \t\t\t\tall { + \t\t\t\t\ttestTask.configure { + \t\t\t\t\t\tsystemProperty 'net.bytebuddy.experimental', 'true' + \t\t\t\t\t\tjvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:%s=%s'] + \t\t\t\t\t} + \t\t\t\t} + \t\t\t} + \t\t} + \t} + }""".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + + Path clientBuildFilePath = Path.of(clientBuildFile); + + String buildFileContent = Files.readString(clientBuildFilePath); + if (!buildFileContent.contains(clientTestingBlock)) { + buildFileContent += "\n" + clientTestingBlock; + + Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + Files.writeString(clientBuildFilePath, buildFileContent); + } + } + } + + private static void executeMavenProjectTests(ArrayList clientProjectPomFiles, String clientLocation) throws MavenInvocationException { + // This is the maven path + if (!clientProjectPomFiles.isEmpty()) { + if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "21"); + } else { + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "21"); + } + } + } + } + + private static void executeGradleProjectTests(ArrayList clientProjectGradleBuildFiles, String clientLocation) throws IOException, InterruptedException { + // This is the gradle path + if (!clientProjectGradleBuildFiles.isEmpty()) { + if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("build.gradle"))) { + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(clientLocation), + "test", + "--warning-mode", + "all" + }, new File(clientLocation)); + } else { + for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { + Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); + Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); + + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(clientProjectLocationPath), + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString())); + } + } + } + } + + private static void tracesToCode(String GilesiRepositoryLocation) throws IOException, InterruptedException { + // Turn traces into Java files + ArrayList traceFiles = FileUtils.enumerateFiles("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), "MethodTraces_.*\\.xml", false); + for (String traceFile : traceFiles) { + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), + traceFile, + "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation) // output + }, null); + } + } + + private static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { + // Last minute cleanup + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + } + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java new file mode 100644 index 00000000..71f5d5aa --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java @@ -0,0 +1,26 @@ +package com.github.gilesi.maestro; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +public class ProcessUtils { + public static void runExternalCommand(String[] command, File directory) throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder(command); + if (directory != null) { + pb.directory(directory); + } + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + + String line; + + while ((line = reader.readLine()) != null) { + System.out.println(line); + } + + p.waitFor(); + } +} From ad53bdf26023a08915d799c13a8e821801184894 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 11 Jun 2024 22:32:19 +0200 Subject: [PATCH 126/244] add more arguments to fully automate the experience process --- .../java/com/github/gilesi/maestro/Main.java | 6 ++++- .../github/gilesi/maestro/Orchestrator.java | 25 ++++++++++++++++++- 2 files changed, 29 insertions(+), 2 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 72bcb085..04184c6f 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -22,7 +22,11 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP String clientLocation = args[0]; String libraryLocation = args[1]; String gilesiRepositoryLocation = args[2]; + String dependencyName = args[3]; + String dependencyVersion = args[4]; + String dependencyNewVersion = args[5]; + String outputTestProject = args[6]; - Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation); + Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, dependencyNewVersion, outputTestProject); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index 3749c70a..a4c89c74 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -13,7 +13,15 @@ import java.util.ArrayList; public class Orchestrator { - public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + // TODO: More robust logging here using JUnit perhaps... + // TODO: Simplify required arg to run here + // TODO: Ideally we would want to deduce the version from the provided source but not always doable + // TODO: Could we also fetch source jars ourselves somehow or source loc? + // TODO: Maybe the dependency name is also doable to extract here, need to see how... + // TODO: Fix cross plat! + // TODO: picocli? + + public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation, String dependencyName, String dependencyVersion, String dependencyNewVersion, String outputTestProject) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); @@ -27,6 +35,7 @@ public static void handleProject(String clientLocation, String libraryLocation, Files.createDirectories(traceResultsLocationPath); // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... ProcessUtils.runExternalCommand(new String[]{ "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), "-jar", @@ -59,6 +68,20 @@ public static void handleProject(String clientLocation, String libraryLocation, tracesToCode(GilesiRepositoryLocation); lastMinuteCleanup(allProjectFiles); + + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + + // Move test files to said test project + + // Test test project (3 times to be sure) + + // Update test project dependency version at version dependencyNewVersion + + // Test test project with dependency at version dependencyNewVersion (3 times to be sure) + + // Collect results of the execution + + // Write report } private static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { From 32b82ccadce19e7b6763ddbbe7da61459d0045f7 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 18 Jun 2024 09:49:33 +0200 Subject: [PATCH 127/244] Enhancements --- .idea/misc.xml | 2 + .../Maestro__Sample_Project_.xml | 20 ++ Maestro/build.gradle | 2 + .../com/github/gilesi/maestro/CompSuite.java | 113 +++++++ .../maestro/CompSuiteIncompatibility.java | 17 + .../com/github/gilesi/maestro/Constants.java | 1 - .../com/github/gilesi/maestro/FetchGit.java | 62 ++++ .../java/com/github/gilesi/maestro/Main.java | 17 +- .../github/gilesi/maestro/Orchestrator.java | 56 ++- .../github/gilesi/maestro/ProcessUtils.java | 2 +- .../maestro/runners/maven/Log4JLogger.java | 260 ++++++++++++++ .../maestro/runners/maven/ProjectRunner.java | 56 +-- .../runners/maven/TestAssertedLogger.java | 192 +++++++++++ .../testing/surefire/SurefireHarness.java | 4 +- Maestro/src/main/resources/log4j2.xml | 22 ++ .../.gradle/8.7/checksums/checksums.lock | Bin 0 -> 17 bytes .../8.7/dependencies-accessors/gc.properties | 0 .../8.7/executionHistory/executionHistory.bin | Bin 0 -> 19654 bytes .../executionHistory/executionHistory.lock | Bin 0 -> 17 bytes .../.gradle/8.7/fileChanges/last-build.bin | Bin 0 -> 1 bytes .../.gradle/8.7/fileHashes/fileHashes.bin | Bin 0 -> 19247 bytes .../.gradle/8.7/fileHashes/fileHashes.lock | Bin 0 -> 17 bytes MyTestProject/.gradle/8.7/gc.properties | 0 .../buildOutputCleanup.lock | Bin 0 -> 17 bytes .../buildOutputCleanup/cache.properties | 2 + .../buildOutputCleanup/outputFiles.bin | Bin 0 -> 18713 bytes MyTestProject/.gradle/vcs-1/gc.properties | 0 MyTestProject/MethodTraces_1.xml | 1 + MyTestProject/MethodTraces_10.xml | 1 + MyTestProject/MethodTraces_11.xml | 1 + MyTestProject/MethodTraces_12.xml | 1 + MyTestProject/MethodTraces_13.xml | 1 + MyTestProject/MethodTraces_14.xml | 1 + MyTestProject/MethodTraces_15.xml | 1 + MyTestProject/MethodTraces_16.xml | 1 + MyTestProject/MethodTraces_17.xml | 1 + MyTestProject/MethodTraces_18.xml | 1 + MyTestProject/MethodTraces_19.xml | 1 + MyTestProject/MethodTraces_2.xml | 1 + MyTestProject/MethodTraces_20.xml | 1 + MyTestProject/MethodTraces_21.xml | 1 + MyTestProject/MethodTraces_22.xml | 1 + MyTestProject/MethodTraces_23.xml | 1 + MyTestProject/MethodTraces_24.xml | 1 + MyTestProject/MethodTraces_25.xml | 1 + MyTestProject/MethodTraces_26.xml | 1 + MyTestProject/MethodTraces_27.xml | 1 + MyTestProject/MethodTraces_28.xml | 320 ++++++++++++++++++ MyTestProject/MethodTraces_29.xml | 1 + MyTestProject/MethodTraces_3.xml | 1 + MyTestProject/MethodTraces_30.xml | 1 + MyTestProject/MethodTraces_31.xml | 1 + MyTestProject/MethodTraces_32.xml | 1 + MyTestProject/MethodTraces_33.xml | 1 + MyTestProject/MethodTraces_34.xml | 1 + MyTestProject/MethodTraces_35.xml | 1 + MyTestProject/MethodTraces_36.xml | 1 + MyTestProject/MethodTraces_37.xml | 1 + MyTestProject/MethodTraces_38.xml | 1 + MyTestProject/MethodTraces_39.xml | 1 + MyTestProject/MethodTraces_4.xml | 1 + MyTestProject/MethodTraces_40.xml | 1 + MyTestProject/MethodTraces_41.xml | 1 + MyTestProject/MethodTraces_42.xml | 1 + MyTestProject/MethodTraces_43.xml | 1 + MyTestProject/MethodTraces_44.xml | 1 + MyTestProject/MethodTraces_45.xml | 1 + MyTestProject/MethodTraces_46.xml | 1 + MyTestProject/MethodTraces_47.xml | 1 + MyTestProject/MethodTraces_48.xml | 1 + MyTestProject/MethodTraces_49.xml | 1 + MyTestProject/MethodTraces_5.xml | 1 + MyTestProject/MethodTraces_50.xml | 1 + MyTestProject/MethodTraces_51.xml | 1 + MyTestProject/MethodTraces_52.xml | 1 + MyTestProject/MethodTraces_53.xml | 1 + MyTestProject/MethodTraces_54.xml | 1 + MyTestProject/MethodTraces_55.xml | 1 + MyTestProject/MethodTraces_56.xml | 1 + MyTestProject/MethodTraces_57.xml | 1 + MyTestProject/MethodTraces_58.xml | 1 + MyTestProject/MethodTraces_59.xml | 1 + MyTestProject/MethodTraces_6.xml | 1 + MyTestProject/MethodTraces_60.xml | 1 + MyTestProject/MethodTraces_61.xml | 1 + MyTestProject/MethodTraces_62.xml | 1 + MyTestProject/MethodTraces_63.xml | 1 + MyTestProject/MethodTraces_64.xml | 1 + MyTestProject/MethodTraces_65.xml | 1 + MyTestProject/MethodTraces_66.xml | 1 + MyTestProject/MethodTraces_67.xml | 1 + MyTestProject/MethodTraces_68.xml | 1 + MyTestProject/MethodTraces_69.xml | 1 + MyTestProject/MethodTraces_7.xml | 1 + MyTestProject/MethodTraces_70.xml | 1 + MyTestProject/MethodTraces_71.xml | 1 + MyTestProject/MethodTraces_8.xml | 1 + MyTestProject/MethodTraces_9.xml | 1 + MyTestProject/Unknown_28_1.xml | 103 ++++++ MyTestProject/Unknown_28_2.xml | 103 ++++++ MyTestProject/Unknown_28_3.xml | 103 ++++++ MyTestProject/build.gradle | 22 ++ .../gradle/wrapper/gradle-wrapper.properties | 7 + MyTestProject/gradlew | 249 ++++++++++++++ MyTestProject/gradlew.bat | 92 +++++ Samples/Gradle/samplelibrary/build.gradle | 1 + .../target/maven-archiver/pom.properties | 3 + .../compile/default-compile/createdFiles.lst | 0 .../compile/default-compile/inputFiles.lst | 4 + .../default-testCompile/createdFiles.lst | 0 .../default-testCompile/inputFiles.lst | 2 + .../target/surefire-reports/CTest.txt | 4 + .../target/surefire-reports/FooTest.txt | 4 + .../target/surefire-reports/TEST-CTest.xml | 66 ++++ .../target/surefire-reports/TEST-FooTest.xml | 67 ++++ .../TestWorkflowConfiguration.xml | 204 +++++++++++ .../target/maven-archiver/pom.properties | 3 + .../compile/default-compile/createdFiles.lst | 0 .../compile/default-compile/inputFiles.lst | 5 + .../default-testCompile/createdFiles.lst | 0 .../default-testCompile/inputFiles.lst | 1 + .../target/surefire-reports/ATest.txt | 4 + .../target/surefire-reports/TEST-ATest.xml | 59 ++++ 123 files changed, 2278 insertions(+), 46 deletions(-) create mode 100644 .idea/runConfigurations/Maestro__Sample_Project_.xml create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/TestAssertedLogger.java create mode 100644 Maestro/src/main/resources/log4j2.xml create mode 100644 MyTestProject/.gradle/8.7/checksums/checksums.lock create mode 100644 MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties create mode 100644 MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin create mode 100644 MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock create mode 100644 MyTestProject/.gradle/8.7/fileChanges/last-build.bin create mode 100644 MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin create mode 100644 MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock create mode 100644 MyTestProject/.gradle/8.7/gc.properties create mode 100644 MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock create mode 100644 MyTestProject/.gradle/buildOutputCleanup/cache.properties create mode 100644 MyTestProject/.gradle/buildOutputCleanup/outputFiles.bin create mode 100644 MyTestProject/.gradle/vcs-1/gc.properties create mode 100644 MyTestProject/MethodTraces_1.xml create mode 100644 MyTestProject/MethodTraces_10.xml create mode 100644 MyTestProject/MethodTraces_11.xml create mode 100644 MyTestProject/MethodTraces_12.xml create mode 100644 MyTestProject/MethodTraces_13.xml create mode 100644 MyTestProject/MethodTraces_14.xml create mode 100644 MyTestProject/MethodTraces_15.xml create mode 100644 MyTestProject/MethodTraces_16.xml create mode 100644 MyTestProject/MethodTraces_17.xml create mode 100644 MyTestProject/MethodTraces_18.xml create mode 100644 MyTestProject/MethodTraces_19.xml create mode 100644 MyTestProject/MethodTraces_2.xml create mode 100644 MyTestProject/MethodTraces_20.xml create mode 100644 MyTestProject/MethodTraces_21.xml create mode 100644 MyTestProject/MethodTraces_22.xml create mode 100644 MyTestProject/MethodTraces_23.xml create mode 100644 MyTestProject/MethodTraces_24.xml create mode 100644 MyTestProject/MethodTraces_25.xml create mode 100644 MyTestProject/MethodTraces_26.xml create mode 100644 MyTestProject/MethodTraces_27.xml create mode 100644 MyTestProject/MethodTraces_28.xml create mode 100644 MyTestProject/MethodTraces_29.xml create mode 100644 MyTestProject/MethodTraces_3.xml create mode 100644 MyTestProject/MethodTraces_30.xml create mode 100644 MyTestProject/MethodTraces_31.xml create mode 100644 MyTestProject/MethodTraces_32.xml create mode 100644 MyTestProject/MethodTraces_33.xml create mode 100644 MyTestProject/MethodTraces_34.xml create mode 100644 MyTestProject/MethodTraces_35.xml create mode 100644 MyTestProject/MethodTraces_36.xml create mode 100644 MyTestProject/MethodTraces_37.xml create mode 100644 MyTestProject/MethodTraces_38.xml create mode 100644 MyTestProject/MethodTraces_39.xml create mode 100644 MyTestProject/MethodTraces_4.xml create mode 100644 MyTestProject/MethodTraces_40.xml create mode 100644 MyTestProject/MethodTraces_41.xml create mode 100644 MyTestProject/MethodTraces_42.xml create mode 100644 MyTestProject/MethodTraces_43.xml create mode 100644 MyTestProject/MethodTraces_44.xml create mode 100644 MyTestProject/MethodTraces_45.xml create mode 100644 MyTestProject/MethodTraces_46.xml create mode 100644 MyTestProject/MethodTraces_47.xml create mode 100644 MyTestProject/MethodTraces_48.xml create mode 100644 MyTestProject/MethodTraces_49.xml create mode 100644 MyTestProject/MethodTraces_5.xml create mode 100644 MyTestProject/MethodTraces_50.xml create mode 100644 MyTestProject/MethodTraces_51.xml create mode 100644 MyTestProject/MethodTraces_52.xml create mode 100644 MyTestProject/MethodTraces_53.xml create mode 100644 MyTestProject/MethodTraces_54.xml create mode 100644 MyTestProject/MethodTraces_55.xml create mode 100644 MyTestProject/MethodTraces_56.xml create mode 100644 MyTestProject/MethodTraces_57.xml create mode 100644 MyTestProject/MethodTraces_58.xml create mode 100644 MyTestProject/MethodTraces_59.xml create mode 100644 MyTestProject/MethodTraces_6.xml create mode 100644 MyTestProject/MethodTraces_60.xml create mode 100644 MyTestProject/MethodTraces_61.xml create mode 100644 MyTestProject/MethodTraces_62.xml create mode 100644 MyTestProject/MethodTraces_63.xml create mode 100644 MyTestProject/MethodTraces_64.xml create mode 100644 MyTestProject/MethodTraces_65.xml create mode 100644 MyTestProject/MethodTraces_66.xml create mode 100644 MyTestProject/MethodTraces_67.xml create mode 100644 MyTestProject/MethodTraces_68.xml create mode 100644 MyTestProject/MethodTraces_69.xml create mode 100644 MyTestProject/MethodTraces_7.xml create mode 100644 MyTestProject/MethodTraces_70.xml create mode 100644 MyTestProject/MethodTraces_71.xml create mode 100644 MyTestProject/MethodTraces_8.xml create mode 100644 MyTestProject/MethodTraces_9.xml create mode 100644 MyTestProject/Unknown_28_1.xml create mode 100644 MyTestProject/Unknown_28_2.xml create mode 100644 MyTestProject/Unknown_28_3.xml create mode 100644 MyTestProject/build.gradle create mode 100644 MyTestProject/gradle/wrapper/gradle-wrapper.properties create mode 100755 MyTestProject/gradlew create mode 100644 MyTestProject/gradlew.bat create mode 100644 Samples/Maven/sampleclient/target/maven-archiver/pom.properties create mode 100644 Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst create mode 100644 Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst create mode 100644 Samples/Maven/sampleclient/target/surefire-reports/CTest.txt create mode 100644 Samples/Maven/sampleclient/target/surefire-reports/FooTest.txt create mode 100644 Samples/Maven/sampleclient/target/surefire-reports/TEST-CTest.xml create mode 100644 Samples/Maven/sampleclient/target/surefire-reports/TEST-FooTest.xml create mode 100644 Samples/Maven/samplelibrary/TestWorkflowConfiguration.xml create mode 100644 Samples/Maven/samplelibrary/target/maven-archiver/pom.properties create mode 100644 Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst create mode 100644 Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst create mode 100644 Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst create mode 100644 Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst create mode 100644 Samples/Maven/samplelibrary/target/surefire-reports/ATest.txt create mode 100644 Samples/Maven/samplelibrary/target/surefire-reports/TEST-ATest.xml diff --git a/.idea/misc.xml b/.idea/misc.xml index c7cf370a..7b4dd477 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -5,6 +5,7 @@ + @@ -14,6 +15,7 @@ diff --git a/.idea/runConfigurations/Maestro__Sample_Project_.xml b/.idea/runConfigurations/Maestro__Sample_Project_.xml new file mode 100644 index 00000000..b031dd29 --- /dev/null +++ b/.idea/runConfigurations/Maestro__Sample_Project_.xml @@ -0,0 +1,20 @@ + + + + + + + + \ No newline at end of file diff --git a/Maestro/build.gradle b/Maestro/build.gradle index 7de5947e..3e8bb464 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -33,6 +33,8 @@ dependencies { implementation 'org.apache.maven.shared:maven-invoker:3.2.0' testImplementation platform('org.junit:junit-bom:5.10.0') testImplementation 'org.junit.jupiter:junit-jupiter' + implementation 'org.apache.logging.log4j:log4j-core:2.19.0' + implementation 'org.apache.logging.log4j:log4j-api:2.19.0' } jar { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java new file mode 100644 index 00000000..139fd033 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java @@ -0,0 +1,113 @@ +package com.github.gilesi.maestro; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.gilesi.maestro.runners.maven.Log4JLogger; +import com.github.gilesi.maestro.runners.maven.ProjectRunner; +import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; +import com.github.gilesi.maestro.testing.surefire.FileUtils; +import org.apache.maven.shared.invoker.MavenInvocationException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CompSuite { + public static void cloneDataset() throws IOException, InterruptedException { + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite2"; + CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + + //FileUtils.deleteDirectoryIfExists(datasetOutput); + Path datasetOutputPath = Path.of(datasetOutput); + //Files.createDirectories(datasetOutputPath); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + if (!incompatibility.id.equals("i-122")) { + continue; + } + + + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); + FileUtils.deleteDirectoryIfExists(newDestinationProjectPath.toString()); + + Files.createDirectories(oldDestinationProjectPath); + Files.createDirectories(newDestinationProjectPath); + + Main.logger.info("Cloning old at: %s".formatted(oldDestinationProjectPath)); + FetchGit.cloneProject(incompatibility.url, incompatibility.sha, oldDestinationProjectPath); + + Main.logger.info("Cloning new at: %s".formatted(newDestinationProjectPath)); + FetchGit.cloneProject(incompatibility.url, "tags/%s-%s".formatted(incompatibility.lib.replace(":", "--"), incompatibility._new), newDestinationProjectPath); + } + } + + public static void handleDataset() throws IOException, MavenInvocationException { + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite2"; + CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + if (!incompatibility.id.equals("i-122")) { + continue; + } + + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + if (!incompatibility.submodule.equals("N/A")) { + oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); + newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); + } + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } + + Main.logger.info("Testing old project"); + TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + + Main.logger.info("Testing new project"); + TestAssertedLogger testAssertedLogger2 = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger2); + + Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, testAssertedLogger.HasTestFailed(), testAssertedLogger2.HasTestFailed())); + } + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java new file mode 100644 index 00000000..431f782e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java @@ -0,0 +1,17 @@ +package com.github.gilesi.maestro; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CompSuiteIncompatibility { + public String id; + public String client; + public String url; + public String sha; + public String lib; + public String old; + @JsonProperty("new") + public String _new; + public String test; + public String submodule; + public String test_cmd; +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index 1f8cf804..b3bc3d4f 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -14,7 +14,6 @@ public class Constants { // These paths are dynamically created by the tool but must stay consistent within methods public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; public static final String targetConfigurationName = "TestWorkflowConfiguration.xml"; - public static final String traceResultsLocation = "/Results"; public static final Map JAVA_VERSIONS = new Hashtable<>() { { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java b/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java new file mode 100644 index 00000000..8ab82902 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java @@ -0,0 +1,62 @@ +package com.github.gilesi.maestro; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +public class FetchGit { + private static String[] getGitCloneCommands(String repoUrl, String hash) { + /*return new String[]{ + "git init", + "git remote add origin " + repoUrl, + "git fetch --depth 1 origin " + hash, + "git reset --hard FETCH_HEAD", + "git submodule init", + "git submodule update" + };*/ + return new String[]{ + "git clone " + repoUrl, + "git checkout " + hash, + "git submodule init", + "git submodule update" + }; + } + + private static boolean deleteDirectory(File fi) { + boolean globalResult = true; + + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + if (!file.delete()) { + globalResult = false; + } + } + if (!fi.delete()) { + globalResult = false; + } + + return globalResult; + } + + public static void cloneProject(String cloneUrl, String commit, Path repositoryDestination) throws IOException, InterruptedException { + String[] commands = getGitCloneCommands(cloneUrl, commit); + + if (Files.exists(repositoryDestination)) { + if (deleteDirectory(new File(repositoryDestination.toString()))) { + Files.createDirectory(repositoryDestination); + } + } else { + Files.createDirectory(repositoryDestination); + } + + for (String cmd : commands) { + File fi = new File(repositoryDestination.toString()); + Process p1 = Runtime.getRuntime().exec(cmd.split(" "), null, fi); + p1.waitFor(); + } + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 04184c6f..96fc441b 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -2,20 +2,24 @@ import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; public class Main { + public static final Logger logger = LogManager.getLogger(); + public static void main(String[] args) throws MavenInvocationException, XmlPullParserException, IOException, InterruptedException { if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { - System.out.println("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); + logger.info("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); return; } - if (args.length != 3) { - System.out.println("Usage: "); + if (args.length != 6) { + logger.info("Usage: "); return; } @@ -24,9 +28,10 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP String gilesiRepositoryLocation = args[2]; String dependencyName = args[3]; String dependencyVersion = args[4]; - String dependencyNewVersion = args[5]; - String outputTestProject = args[6]; + String outputTestProject = args[5]; + + //Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject); - Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, dependencyNewVersion, outputTestProject); + CompSuite.handleDataset(); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index a4c89c74..bf6a3574 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -1,6 +1,7 @@ package com.github.gilesi.maestro; import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; +import com.github.gilesi.maestro.runners.maven.Log4JLogger; import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.testing.surefire.FileUtils; import org.apache.maven.shared.invoker.MavenInvocationException; @@ -21,18 +22,15 @@ public class Orchestrator { // TODO: Fix cross plat! // TODO: picocli? - public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation, String dependencyName, String dependencyVersion, String dependencyNewVersion, String outputTestProject) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation, String dependencyName, String dependencyVersion, String outputTestProject) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); + Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - Path traceResultsLocationPath = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation)); - - // First, perform some preliminary cleanup in case we already ran previously - if (Files.exists(traceResultsLocationPath)) { - FileUtils.deleteDirectory(new File("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation))); - } // Create the results directory - Files.createDirectories(traceResultsLocationPath); + Files.createDirectories(outputTestProjectPath); // Run ConfGen on Library first // TODO: Check how meta projects get handled here exactly... @@ -41,7 +39,7 @@ public static void handleProject(String clientLocation, String libraryLocation, "-jar", "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), libraryConfig.toString(), - "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), + outputTestProject, libraryLocation, clientLocation }, null); @@ -65,13 +63,39 @@ public static void handleProject(String clientLocation, String libraryLocation, executeMavenProjectTests(clientProjectPomFiles, clientLocation); executeGradleProjectTests(clientProjectGradleBuildFiles, clientLocation); - tracesToCode(GilesiRepositoryLocation); + tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); lastMinuteCleanup(allProjectFiles); // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion - // Move test files to said test project + String buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + }""".formatted(dependencyName, dependencyVersion); + + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); // Test test project (3 times to be sure) @@ -150,13 +174,13 @@ private static void executeMavenProjectTests(ArrayList clientProjectPomF // This is the maven path if (!clientProjectPomFiles.isEmpty()) { if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { - ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test", null, "21"); + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger()); } else { for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); - ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test", null, "21"); + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger()); } } } @@ -192,16 +216,16 @@ private static void executeGradleProjectTests(ArrayList clientProjectGra } } - private static void tracesToCode(String GilesiRepositoryLocation) throws IOException, InterruptedException { + private static void tracesToCode(String GilesiRepositoryLocation, String outputTestProject, String outputCodeDirectory) throws IOException, InterruptedException { // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles("%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation), "MethodTraces_.*\\.xml", false); + ArrayList traceFiles = FileUtils.enumerateFiles(outputTestProject, "MethodTraces_.*\\.xml", false); for (String traceFile : traceFiles) { ProcessUtils.runExternalCommand(new String[]{ "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), "-jar", "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), traceFile, - "%s%s".formatted(GilesiRepositoryLocation, Constants.traceResultsLocation) // output + outputCodeDirectory }, null); } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java index 71f5d5aa..0d413f18 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java @@ -18,7 +18,7 @@ public static void runExternalCommand(String[] command, File directory) throws I String line; while ((line = reader.readLine()) != null) { - System.out.println(line); + Main.logger.info(line); } p.waitFor(); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java new file mode 100644 index 00000000..f2318b53 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java @@ -0,0 +1,260 @@ +package com.github.gilesi.maestro.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class Log4JLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The print stream to write to, never null. + */ + private final Logger out; + + /** + * The threshold used to filter messages. + */ + private int threshold; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public Log4JLogger() { + this(LogManager.getLogger(), INFO); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param out The print stream to write to, must not be null. + * @param threshold The threshold for the logger. + */ + public Log4JLogger(Logger out, int threshold) { + if (out == null) { + throw new NullPointerException("missing output stream"); + } + this.out = out; + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + Level logLevel = Level.INFO; + + switch (level) { + case (DEBUG) -> logLevel = Level.DEBUG; + case (INFO) -> logLevel = Level.INFO; + case (WARN) -> logLevel = Level.WARN; + case (ERROR) -> logLevel = Level.ERROR; + case (FATAL) -> logLevel = Level.FATAL; + default -> { + } + } + + buffer.append("[Maven] "); + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + out.log(logLevel, buffer.toString()); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java index 54322d18..1a1a5b68 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java @@ -1,6 +1,7 @@ package com.github.gilesi.maestro.runners.maven; import com.github.gilesi.maestro.Constants; +import com.github.gilesi.maestro.Main; import org.apache.maven.model.*; import org.apache.maven.shared.invoker.*; @@ -15,7 +16,7 @@ public class ProjectRunner { - public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, Object logger) throws MavenInvocationException { String javaVersion = "8"; @@ -24,38 +25,47 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); - return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion, logger); } - public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion) throws MavenInvocationException { + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger) throws MavenInvocationException { File pomFile = new File(pomFilePath); - File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); + InvokerLogger invokerLogger = null; + InvocationOutputHandler invocationOutputHandler = null; + + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } - ConsoleLogger logger = new ConsoleLogger(); + File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); Properties properties = new Properties(); pomProperties.forEach(p -> properties.put(p, true)); @@ -78,9 +88,11 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, request.setBatchMode(batchMode); request.setJavaHome(new File(JavaHome)); request.setBaseDirectory(projectDirectory); - request.setOutputHandler(logger); request.setInputStream(InputStream.nullInputStream()); - request.setErrorHandler(logger); + if (invocationOutputHandler != null) { + request.setOutputHandler(invocationOutputHandler); + request.setErrorHandler(invocationOutputHandler); + } if (userSettingsFilePath != null && !userSettingsFilePath.isEmpty() && !userSettingsFilePath.isBlank()) { Path pa = Path.of(userSettingsFilePath); @@ -89,25 +101,27 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, } } - System.out.printf("Building with pom=%s goals=%s properties=%s%n", pomFilePath, pomGoals, properties); + Main.logger.info("Building with pom=%s goals=%s properties=%s%n".formatted(pomFilePath, pomGoals, properties)); Invoker invoker = new DefaultInvoker(); - invoker.setLogger(logger); + if (invokerLogger != null) { + invoker.setLogger(invokerLogger); + } invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); InvocationResult result = invoker.execute(request); return result.getExitCode(); } - public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion) throws MavenInvocationException { - System.out.println("ExecuteMavenGoalOnDuetsRepository Entry"); + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { + Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); ArrayList goals = new ArrayList<>(); goals.add(goal); if (javaVersion != null && !javaVersion.isBlank()) { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger) == 0; } else { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger) == 0; } } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/TestAssertedLogger.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/TestAssertedLogger.java new file mode 100644 index 00000000..7fdbf8df --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/TestAssertedLogger.java @@ -0,0 +1,192 @@ +package com.github.gilesi.maestro.runners.maven; + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.IOException; + +public class TestAssertedLogger implements InvokerLogger, InvocationOutputHandler { + + private InvokerLogger invokerLogger = null; + private InvocationOutputHandler invocationOutputHandler = null; + private boolean testFailed = false; + + public TestAssertedLogger(Object logger) { + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + } + + + public void debug(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message); + } + } + + public void debug(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message, throwable); + } + } + + public boolean isDebugEnabled() { + if (invokerLogger != null) { + return invokerLogger.isDebugEnabled(); + } + + return false; + } + + public void info(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message); + } + } + + public void info(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message, throwable); + } + } + + public boolean isInfoEnabled() { + if (invokerLogger != null) { + return invokerLogger.isInfoEnabled(); + } + + return false; + } + + public void warn(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message); + } + } + + public void warn(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message, throwable); + } + } + + public boolean isWarnEnabled() { + if (invokerLogger != null) { + return invokerLogger.isWarnEnabled(); + } + + return false; + } + + public void error(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message); + } + } + + public void error(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message, throwable); + } + } + + public boolean isErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isErrorEnabled(); + } + + return false; + } + + public void fatalError(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message); + } + } + + public void fatalError(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message, throwable); + } + } + + public boolean isFatalErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isFatalErrorEnabled(); + } + + return false; + } + + public int getThreshold() { + if (invokerLogger != null) { + return invokerLogger.getThreshold(); + } + + return 0; + } + + public void setThreshold(int threshold) { + if (invokerLogger != null) { + invokerLogger.setThreshold(threshold); + } + } + + public void consumeLine(String line) throws IOException { + if (line.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invocationOutputHandler != null) { + invocationOutputHandler.consumeLine(line); + } + } + + public boolean HasTestFailed() { + return testFailed; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java index acbbde06..35eea9dd 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java @@ -1,5 +1,7 @@ package com.github.gilesi.maestro.testing.surefire; +import com.github.gilesi.maestro.Main; + import java.io.File; import java.io.IOException; import java.nio.file.Files; @@ -33,7 +35,7 @@ public static ArrayList getProjectTestReports(String projectPathFrie try { buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); } catch (Exception e) { - System.out.println(e); + Main.logger.info(e); } } diff --git a/Maestro/src/main/resources/log4j2.xml b/Maestro/src/main/resources/log4j2.xml new file mode 100644 index 00000000..43d5fcb3 --- /dev/null +++ b/Maestro/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ + + + + + + %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file diff --git a/MyTestProject/.gradle/8.7/checksums/checksums.lock b/MyTestProject/.gradle/8.7/checksums/checksums.lock new file mode 100644 index 0000000000000000000000000000000000000000..7fb0e8a42731fe301e0c79d703da4778c3b6eb6c GIT binary patch literal 17 TcmZQRw)W+f^TEZf3{U_7M7ae{ literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties b/MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin b/MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin new file mode 100644 index 0000000000000000000000000000000000000000..8ce7e6783c963a24b516796787756fce72f5650d GIT binary patch literal 19654 zcmeI%Pe>F|90%~X>jn~qbI1^?Q}#!w9o=bA_zymp_iJIi}-b}=jv zq(ViLu!15YDEb3gheRSf8C{|d)+z8}MgJ~QhZ3S@cU?5 zXNxJ?;!HORQiPPQup5q2ea&I#%4?Uh!;Q7M{||C^yT2qmhARXh009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0{?=5 zmk?LCeaiHCK^}=xEu7>LUo_lK<5oqoLo$=4M7dH|_;B*Z;iu0lYG`lY>Sfd2zx9w& zlSkYUt{E}v))LGuHPIp5DXt|Fl)DdQ@1X$IO|D65D6h*uUA|ws`SG?@1)i@n8(%t? z9DzJ`gz797GlDv22^lI5aVs9uW2Ue;Ei2BoJRzS(EB#ev<&|YszEY#g??2-4=w6@C zFbuz!mRBnAo{^DSbEawCiM3bHcn?i3AJDiSWl37637UUl0yrY$MQqz(yLN+PqlUj@!_BvbmMs{)saSenu zsYkO*#4)Ny%}%ODETJ|qsYY0g3Z^!9wNfElxYwqo#(FiPY(2W-mG?=YS;K~d%EM1W6?3y+>bw3XKu6Dp@{PAz4U9rJ1b8HcTK)K z7WgpUm(DaX<#Y`txM}Yx$*9O=e6sY6^AU;iYWi)?B7WKBa@gOUo}X3e-PiyC literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock b/MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock new file mode 100644 index 0000000000000000000000000000000000000000..07910a6b6f7e1a339c32dae5fe4eac2eb4d1cb90 GIT binary patch literal 17 UcmZRs|9nDi{~z821_)pV06P2xj{pDw literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/fileChanges/last-build.bin b/MyTestProject/.gradle/8.7/fileChanges/last-build.bin new file mode 100644 index 0000000000000000000000000000000000000000..f76dd238ade08917e6712764a16a22005a50573d GIT binary patch literal 1 IcmZPo000310RR91 literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin b/MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin new file mode 100644 index 0000000000000000000000000000000000000000..9dfeccbdaee17f2156a3ef6eb83bcc8aec6c3191 GIT binary patch literal 19247 zcmeI(dn{FP00;1M!{$|9qpQqg$YVmHh&)P-D@q=t+pTHRY^pyfQOI16ndf8}g_`18 zc`T30s~GDxAxT!d>kl(wl_+Ido$H+Ax=w%fXZxP*-1FP_obS2!_c?!_`|~CUuI6ug zBV?PdY={vAAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0{@FZ2ssf|YBF4#P11oz zJVDs2O9w);vEDBQ#zxd>UK#WLApLZ_SD1WQ9N);FE=;3y1tuTA)x{6cSJ$R;AFs81;7a1F zFwtW=uVL~9zDT1!Cntc)eJh#Vv|?wLZ4CDreSIvG+Z*!cP6oC;pszo_me03eZ+0|} zrgIf04~na9=;~|OM&&#wCJ(7qk9o6{luYL@m^?+W)V*ge$(7E}F*$Q22u=cZ4xbQ! z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwx`e-qeE)~v|gM7nE^`e*F0vUKEFME`b|6DK7Dpaba?yVL@9&P0t z?$P-b(YpIu%_UWxZVNx#=|&9IFj-_bhGydSMg%o(&I~%(_c6(PmTovxjk->DV^T7G z%=A+B?T)7Xt)iGsD|Ew&Y7oop1}}V~X!`*zOShD!($@~x$X~$QH-co+5*?Y$fNO^$l{RMIO5`6>=zh z>!XJPeopyU;$}*sTtiPx&TFHtzj}XhS}!LvK{?!E;ParGT*LH?bS1@x=Mg$B3A@2B zkDm}}57%@_$Ymh1nJdgCN3t8a9;u3)6Iyk`LGF(!$0Ovb3R#07^efp7v0=5@VSPfc zZ0Y^hyY~#r+rm}k8pMoP+V}&c@QeBY literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock b/MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock new file mode 100644 index 0000000000000000000000000000000000000000..d6dd2a27ea0805f2e2f18b7607998e6f8405a2a0 GIT binary patch literal 17 UcmZQ(@;MuO%lF|81_%%Z05Zh{aR2}S literal 0 HcmV?d00001 diff --git a/MyTestProject/.gradle/8.7/gc.properties b/MyTestProject/.gradle/8.7/gc.properties new file mode 100644 index 00000000..e69de29b diff --git a/MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock new file mode 100644 index 0000000000000000000000000000000000000000..f6cc2ab97556e4fc31bcf126f04754cd3b886cee GIT binary patch literal 17 UcmZQBk~LbY`S?Qt0|f8`04+cRF0Mpzagm6_M!8AJVR2VzuTHDI%tgwHGOeOG zD7Wz^Cq-PGoaUr3W8TjuHwQ}JshN3w=gpt@xz2!6cJfVcs=U>ghl~(F009ILKmY** z5I_I{1Q0*~0R#|0009ILK;XX!j0FoxM2oT8jc`ztQ>x1f2G(kJqoOV8c+uq{U;ZBy zjPd=Z`}n->57M3M!M&Gs?UnAH^n;maCt;f1y01$w-MLx6dGb{Eg7ll>(bPzzRi}I3 zXFpq7xtQ1~>3%HTU%u^cO;2ZZpOtPbx|zz?bNT+9^p>rTwaz*FB$_`Qm!9g~&R?cB z8}xHVr7t`kdhTPfO7~sqa#kv)*A~s-hyVfzAb \ No newline at end of file diff --git a/MyTestProject/MethodTraces_10.xml b/MyTestProject/MethodTraces_10.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_10.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_11.xml b/MyTestProject/MethodTraces_11.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_11.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_12.xml b/MyTestProject/MethodTraces_12.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_12.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_13.xml b/MyTestProject/MethodTraces_13.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_13.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_14.xml b/MyTestProject/MethodTraces_14.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_14.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_15.xml b/MyTestProject/MethodTraces_15.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_15.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_16.xml b/MyTestProject/MethodTraces_16.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_16.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_17.xml b/MyTestProject/MethodTraces_17.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_17.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_18.xml b/MyTestProject/MethodTraces_18.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_18.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_19.xml b/MyTestProject/MethodTraces_19.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_19.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_2.xml b/MyTestProject/MethodTraces_2.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_2.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_20.xml b/MyTestProject/MethodTraces_20.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_20.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_21.xml b/MyTestProject/MethodTraces_21.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_21.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_22.xml b/MyTestProject/MethodTraces_22.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_22.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_23.xml b/MyTestProject/MethodTraces_23.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_23.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_24.xml b/MyTestProject/MethodTraces_24.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_24.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_25.xml b/MyTestProject/MethodTraces_25.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_25.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_26.xml b/MyTestProject/MethodTraces_26.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_26.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_27.xml b/MyTestProject/MethodTraces_27.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_27.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_28.xml b/MyTestProject/MethodTraces_28.xml new file mode 100644 index 00000000..b4bbef9a --- /dev/null +++ b/MyTestProject/MethodTraces_28.xml @@ -0,0 +1,320 @@ + + + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 1880371134 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 571815947 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1780349599 + + + 779552853 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 571815947 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1780349599 + + + 796111827 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testInvalidSql + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + + Unknown + + + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 366757863 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 348968268 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1655831856 + + + 781587889 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 348968268 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1655831856 + + + 796296548 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testDirectCompile + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + + Unknown + + + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 1678159396 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 454349760 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1885213554 + + + 782530329 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 454349760 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1885213554 + + + 796217120 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testCompile + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + + Unknown + + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_29.xml b/MyTestProject/MethodTraces_29.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_29.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_3.xml b/MyTestProject/MethodTraces_3.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_3.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_30.xml b/MyTestProject/MethodTraces_30.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_30.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_31.xml b/MyTestProject/MethodTraces_31.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_31.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_32.xml b/MyTestProject/MethodTraces_32.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_32.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_33.xml b/MyTestProject/MethodTraces_33.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_33.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_34.xml b/MyTestProject/MethodTraces_34.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_34.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_35.xml b/MyTestProject/MethodTraces_35.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_35.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_36.xml b/MyTestProject/MethodTraces_36.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_36.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_37.xml b/MyTestProject/MethodTraces_37.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_37.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_38.xml b/MyTestProject/MethodTraces_38.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_38.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_39.xml b/MyTestProject/MethodTraces_39.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_39.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_4.xml b/MyTestProject/MethodTraces_4.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_4.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_40.xml b/MyTestProject/MethodTraces_40.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_40.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_41.xml b/MyTestProject/MethodTraces_41.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_41.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_42.xml b/MyTestProject/MethodTraces_42.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_42.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_43.xml b/MyTestProject/MethodTraces_43.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_43.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_44.xml b/MyTestProject/MethodTraces_44.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_44.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_45.xml b/MyTestProject/MethodTraces_45.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_45.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_46.xml b/MyTestProject/MethodTraces_46.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_46.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_47.xml b/MyTestProject/MethodTraces_47.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_47.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_48.xml b/MyTestProject/MethodTraces_48.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_48.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_49.xml b/MyTestProject/MethodTraces_49.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_49.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_5.xml b/MyTestProject/MethodTraces_5.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_5.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_50.xml b/MyTestProject/MethodTraces_50.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_50.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_51.xml b/MyTestProject/MethodTraces_51.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_51.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_52.xml b/MyTestProject/MethodTraces_52.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_52.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_53.xml b/MyTestProject/MethodTraces_53.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_53.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_54.xml b/MyTestProject/MethodTraces_54.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_54.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_55.xml b/MyTestProject/MethodTraces_55.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_55.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_56.xml b/MyTestProject/MethodTraces_56.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_56.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_57.xml b/MyTestProject/MethodTraces_57.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_57.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_58.xml b/MyTestProject/MethodTraces_58.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_58.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_59.xml b/MyTestProject/MethodTraces_59.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_59.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_6.xml b/MyTestProject/MethodTraces_6.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_6.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_60.xml b/MyTestProject/MethodTraces_60.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_60.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_61.xml b/MyTestProject/MethodTraces_61.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_61.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_62.xml b/MyTestProject/MethodTraces_62.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_62.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_63.xml b/MyTestProject/MethodTraces_63.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_63.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_64.xml b/MyTestProject/MethodTraces_64.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_64.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_65.xml b/MyTestProject/MethodTraces_65.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_65.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_66.xml b/MyTestProject/MethodTraces_66.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_66.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_67.xml b/MyTestProject/MethodTraces_67.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_67.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_68.xml b/MyTestProject/MethodTraces_68.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_68.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_69.xml b/MyTestProject/MethodTraces_69.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_69.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_7.xml b/MyTestProject/MethodTraces_7.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_7.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_70.xml b/MyTestProject/MethodTraces_70.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_70.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_71.xml b/MyTestProject/MethodTraces_71.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_71.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_8.xml b/MyTestProject/MethodTraces_8.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_8.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/MethodTraces_9.xml b/MyTestProject/MethodTraces_9.xml new file mode 100644 index 00000000..a5cbb109 --- /dev/null +++ b/MyTestProject/MethodTraces_9.xml @@ -0,0 +1 @@ + \ No newline at end of file diff --git a/MyTestProject/Unknown_28_1.xml b/MyTestProject/Unknown_28_1.xml new file mode 100644 index 00000000..168e5943 --- /dev/null +++ b/MyTestProject/Unknown_28_1.xml @@ -0,0 +1,103 @@ + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 1880371134 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 571815947 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1780349599 + + + 779552853 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 571815947 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1780349599 + + + 796111827 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testInvalidSql + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + \ No newline at end of file diff --git a/MyTestProject/Unknown_28_2.xml b/MyTestProject/Unknown_28_2.xml new file mode 100644 index 00000000..932d0784 --- /dev/null +++ b/MyTestProject/Unknown_28_2.xml @@ -0,0 +1,103 @@ + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 366757863 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 348968268 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1655831856 + + + 781587889 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 348968268 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1655831856 + + + 796296548 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testDirectCompile + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + \ No newline at end of file diff --git a/MyTestProject/Unknown_28_3.xml b/MyTestProject/Unknown_28_3.xml new file mode 100644 index 00000000..2fd6f844 --- /dev/null +++ b/MyTestProject/Unknown_28_3.xml @@ -0,0 +1,103 @@ + + + public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) + + org.apache.flink.api.java.typeutils.RowTypeInfo + <org.apache.flink.api.java.typeutils.RowTypeInfo> + <typeClass>org.apache.flink.types.Row</typeClass> + <types> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + </types> + <totalFields>1</totalFields> + <fieldNames> + <string>id</string> + </fieldNames> +</org.apache.flink.api.java.typeutils.RowTypeInfo> + 1678159396 + + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 454349760 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1885213554 + + + 782530329 + + + org.apache.flink.api.common.typeinfo.TypeInformation[] + <org.apache.flink.api.common.typeinfo.TypeInformation-array> + <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> + <clazz>java.lang.Integer</clazz> + <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> + <possibleCastTargetTypes> + <java-class>java.lang.Long</java-class> + <java-class>java.lang.Float</java-class> + <java-class>java.lang.Double</java-class> + <java-class>java.lang.Character</java-class> + </possibleCastTargetTypes> + <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> + </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> +</org.apache.flink.api.common.typeinfo.TypeInformation-array> + 454349760 + + + java.lang.String[] + <string-array> + <string>id</string> +</string-array> + 1885213554 + + + 796217120 + + org.apache.flink.api.java.typeutils.RowTypeInfo.<init> + com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testCompile + jdk.internal.reflect.DirectMethodHandleAccessor.invoke + java.lang.reflect.Method.invoke + org.junit.runners.model.FrameworkMethod$1.runReflectiveCall + org.junit.internal.runners.model.ReflectiveCallable.run + org.junit.runners.model.FrameworkMethod.invokeExplosively + org.junit.internal.runners.statements.InvokeMethod.evaluate + org.junit.runners.ParentRunner.runLeaf + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.BlockJUnit4ClassRunner.runChild + org.junit.runners.ParentRunner$3.run + org.apache.maven.surefire.junitcore.pc.Scheduler$1.run + java.util.concurrent.Executors$RunnableAdapter.call + java.util.concurrent.FutureTask.run + java.util.concurrent.ThreadPoolExecutor.runWorker + java.util.concurrent.ThreadPoolExecutor$Worker.run + java.lang.Thread.run + + + \ No newline at end of file diff --git a/MyTestProject/build.gradle b/MyTestProject/build.gradle new file mode 100644 index 00000000..10f7a85d --- /dev/null +++ b/MyTestProject/build.gradle @@ -0,0 +1,22 @@ +plugins { + id 'java' +} + +group = 'testProject' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() + mavenLocal() +} + +dependencies { + testImplementation 'commons-codec:commons-codec:1.12' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' +} + +test { + useJUnitPlatform() +} \ No newline at end of file diff --git a/MyTestProject/gradle/wrapper/gradle-wrapper.properties b/MyTestProject/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 00000000..b82aa23a --- /dev/null +++ b/MyTestProject/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,7 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip +networkTimeout=10000 +validateDistributionUrl=true +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/MyTestProject/gradlew b/MyTestProject/gradlew new file mode 100755 index 00000000..1aa94a42 --- /dev/null +++ b/MyTestProject/gradlew @@ -0,0 +1,249 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) +APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC2039,SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command: +# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, +# and any embedded shellness will be escaped. +# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be +# treated as '${Hostname}' itself on the command line. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/MyTestProject/gradlew.bat b/MyTestProject/gradlew.bat new file mode 100644 index 00000000..7101f8e4 --- /dev/null +++ b/MyTestProject/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. 1>&2 +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 +echo. 1>&2 +echo Please set the JAVA_HOME variable in your environment to match the 1>&2 +echo location of your Java installation. 1>&2 + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Samples/Gradle/samplelibrary/build.gradle b/Samples/Gradle/samplelibrary/build.gradle index 34871021..9462d48b 100644 --- a/Samples/Gradle/samplelibrary/build.gradle +++ b/Samples/Gradle/samplelibrary/build.gradle @@ -14,6 +14,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.0' testImplementation platform('org.junit:junit-bom:5.11.0-M1') testImplementation 'org.junit.jupiter:junit-jupiter' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' } test { diff --git a/Samples/Maven/sampleclient/target/maven-archiver/pom.properties b/Samples/Maven/sampleclient/target/maven-archiver/pom.properties new file mode 100644 index 00000000..01523d44 --- /dev/null +++ b/Samples/Maven/sampleclient/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +artifactId=sampleclient +groupId=com.github.gilesi.samples +version=1.0-SNAPSHOT diff --git a/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 00000000..e69de29b diff --git a/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 00000000..6e4487f4 --- /dev/null +++ b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,4 @@ +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main.java +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C1.java +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/Main2.java +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C2.java diff --git a/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst new file mode 100644 index 00000000..e69de29b diff --git a/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 00000000..1fb78123 --- /dev/null +++ b/Samples/Maven/sampleclient/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst @@ -0,0 +1,2 @@ +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/test/java/CTest.java +/home/gus/Git/gilesi/Samples/Maven/sampleclient/src/test/java/FooTest.java diff --git a/Samples/Maven/sampleclient/target/surefire-reports/CTest.txt b/Samples/Maven/sampleclient/target/surefire-reports/CTest.txt new file mode 100644 index 00000000..8a08b499 --- /dev/null +++ b/Samples/Maven/sampleclient/target/surefire-reports/CTest.txt @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +Test set: CTest +------------------------------------------------------------------------------- +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.310 s -- in CTest diff --git a/Samples/Maven/sampleclient/target/surefire-reports/FooTest.txt b/Samples/Maven/sampleclient/target/surefire-reports/FooTest.txt new file mode 100644 index 00000000..b959bdb5 --- /dev/null +++ b/Samples/Maven/sampleclient/target/surefire-reports/FooTest.txt @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +Test set: FooTest +------------------------------------------------------------------------------- +Tests run: 3, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.588 s -- in FooTest diff --git a/Samples/Maven/sampleclient/target/surefire-reports/TEST-CTest.xml b/Samples/Maven/sampleclient/target/surefire-reports/TEST-CTest.xml new file mode 100644 index 00000000..641cca70 --- /dev/null +++ b/Samples/Maven/sampleclient/target/surefire-reports/TEST-CTest.xml @@ -0,0 +1,66 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/Maven/sampleclient/target/surefire-reports/TEST-FooTest.xml b/Samples/Maven/sampleclient/target/surefire-reports/TEST-FooTest.xml new file mode 100644 index 00000000..7d62c74f --- /dev/null +++ b/Samples/Maven/sampleclient/target/surefire-reports/TEST-FooTest.xml @@ -0,0 +1,67 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/Samples/Maven/samplelibrary/TestWorkflowConfiguration.xml b/Samples/Maven/samplelibrary/TestWorkflowConfiguration.xml new file mode 100644 index 00000000..68fdd80b --- /dev/null +++ b/Samples/Maven/samplelibrary/TestWorkflowConfiguration.xml @@ -0,0 +1,204 @@ + + + + com.github.gilesi.samples.samplelibrary.Foo2 + + + triuetyg + + (I)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + njrhbgtujhu + + (Ljava/util/Collection;)Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + jhgbjtjbh + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A2 + + + getOurselves + + ()Lcom/github/gilesi/samples/samplelibrary/A2; + + + + foo + + (I)I + + + + sideEffect + + ()V + + + + + (I)V + + + + com.github.gilesi.samples.samplelibrary.Foo + + + HelloEveryone2 + + (Ljava/util/Collection;)Ljava/lang/String; + + + + TESTING + + (Ljava/lang/String;)Ljava/lang/String; + + + + meaningof + + (I)Ljava/lang/String; + + + + sayHelloFoo + + ()Ljava/lang/String; + + + + hello + + (Ljava/lang/String;)V + ()Ljava/lang/String; + + + + hellow + + (Ljava/lang/String;)Ljava/lang/String; + + + + HelloEveryone + + ([Ljava/lang/String;)Ljava/lang/String; + + + + + (Ljava/lang/String;)V + + + + com.github.gilesi.samples.samplelibrary.A + + + CallBack + + (Lcom/github/gilesi/samples/samplelibrary/IDoSomething;)V + + + + foo + + (I)I + + + + + (I)V + + + + + CTest.ClientATest + CTest.Test + FooTest.TestFoo + FooTest.TestFooIsLifeNice + FooTest.mainTest + com.github.gilesi.samples.sampleclient.C1.Do + com.github.gilesi.samples.sampleclient.C2.bar + com.github.gilesi.samples.sampleclient.Main.DoWork + com.github.gilesi.samples.sampleclient.Main.main + com.github.gilesi.samples.sampleclient.Main2.main + + + CTest.CTest + FooTest.FooTest + com.github.gilesi.samples.sampleclient.C1.C1 + com.github.gilesi.samples.sampleclient.C2.C2 + com.github.gilesi.samples.sampleclient.Main.Main + com.github.gilesi.samples.sampleclient.Main2.Main2 + + + com.github.gilesi.samples.samplelibrary.A.CallBack + com.github.gilesi.samples.samplelibrary.A.foo + com.github.gilesi.samples.samplelibrary.A2.foo + com.github.gilesi.samples.samplelibrary.A2.getOurselves + com.github.gilesi.samples.samplelibrary.A2.sideEffect + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone + com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone2 + com.github.gilesi.samples.samplelibrary.Foo.TESTING + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hello + com.github.gilesi.samples.samplelibrary.Foo.hellow + com.github.gilesi.samples.samplelibrary.Foo.meaningof + com.github.gilesi.samples.samplelibrary.Foo.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.TESTING + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hello + com.github.gilesi.samples.samplelibrary.Foo2.hellow + com.github.gilesi.samples.samplelibrary.Foo2.jhgbjtjbh + com.github.gilesi.samples.samplelibrary.Foo2.njrhbgtujhu + com.github.gilesi.samples.samplelibrary.Foo2.sayHelloFoo + com.github.gilesi.samples.samplelibrary.Foo2.triuetyg + com.github.gilesi.samples.samplelibrary.IDoSomething.Do + + + com.github.gilesi.samples.samplelibrary.A.A + com.github.gilesi.samples.samplelibrary.A2.A2 + com.github.gilesi.samples.samplelibrary.Foo.Foo + com.github.gilesi.samples.samplelibrary.Foo2.Foo2 + com.github.gilesi.samples.samplelibrary.IDoSomething.IDoSomething + + /home/gus/Git/gilesi/MyTestProject + \ No newline at end of file diff --git a/Samples/Maven/samplelibrary/target/maven-archiver/pom.properties b/Samples/Maven/samplelibrary/target/maven-archiver/pom.properties new file mode 100644 index 00000000..0f0623ba --- /dev/null +++ b/Samples/Maven/samplelibrary/target/maven-archiver/pom.properties @@ -0,0 +1,3 @@ +artifactId=samplelibrary +groupId=com.github.gilesi.samples +version=1.0-SNAPSHOT diff --git a/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/createdFiles.lst new file mode 100644 index 00000000..e69de29b diff --git a/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst new file mode 100644 index 00000000..c3b4bc88 --- /dev/null +++ b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/compile/default-compile/inputFiles.lst @@ -0,0 +1,5 @@ +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo.java +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/IDoSomething.java +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/Foo2.java +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A2.java +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java diff --git a/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/createdFiles.lst new file mode 100644 index 00000000..e69de29b diff --git a/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst new file mode 100644 index 00000000..e987ae06 --- /dev/null +++ b/Samples/Maven/samplelibrary/target/maven-status/maven-compiler-plugin/testCompile/default-testCompile/inputFiles.lst @@ -0,0 +1 @@ +/home/gus/Git/gilesi/Samples/Maven/samplelibrary/src/test/java/ATest.java diff --git a/Samples/Maven/samplelibrary/target/surefire-reports/ATest.txt b/Samples/Maven/samplelibrary/target/surefire-reports/ATest.txt new file mode 100644 index 00000000..475da903 --- /dev/null +++ b/Samples/Maven/samplelibrary/target/surefire-reports/ATest.txt @@ -0,0 +1,4 @@ +------------------------------------------------------------------------------- +Test set: ATest +------------------------------------------------------------------------------- +Tests run: 2, Failures: 0, Errors: 0, Skipped: 0, Time elapsed: 0.076 s -- in ATest diff --git a/Samples/Maven/samplelibrary/target/surefire-reports/TEST-ATest.xml b/Samples/Maven/samplelibrary/target/surefire-reports/TEST-ATest.xml new file mode 100644 index 00000000..79b4f370 --- /dev/null +++ b/Samples/Maven/samplelibrary/target/surefire-reports/TEST-ATest.xml @@ -0,0 +1,59 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file From a61019297a771c302f7ed183862bdb7f80faabd8 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 14:42:00 +0200 Subject: [PATCH 128/244] updates --- .../java/com/github/gilesi/confgen/Main.java | 36 +-- .../models/InstrumentationParameters.java | 2 - .../models/InstrumentationParameters.java | 2 - .../github/gilesi/instrumentation/Agent.java | 14 +- .../com/github/gilesi/maestro/CompSuite.java | 247 +++++++++++++++++- .../com/github/gilesi/maestro/Constants.java | 4 +- .../java/com/github/gilesi/maestro/Main.java | 2 +- .../github/gilesi/maestro/Orchestrator.java | 14 +- 8 files changed, 288 insertions(+), 33 deletions(-) diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 22f82470..461b21a3 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -1,5 +1,7 @@ package com.github.gilesi.confgen; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.confgen.exceptions.UnsupportedJavaPrimitiveTypeException; import com.github.gilesi.confgen.spoon.SpoonLauncherUtilities; import com.github.gilesi.confgen.models.Class; @@ -20,6 +22,13 @@ import java.util.*; public class Main { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + private static String getClassNameFromFQN(String fullyQualifiedName) { String parameterLessQualifiedName = fullyQualifiedName; @@ -132,9 +141,7 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); - instrumentationParameters.LibraryMethods = new ArrayList<>(); instrumentationParameters.ClientMethods = new ArrayList<>(); - instrumentationParameters.LibraryTypes = new ArrayList<>(); instrumentationParameters.ClientTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; @@ -159,18 +166,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept } } - System.out.println("Processing Library Project..."); - - libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() - .forEach(method -> instrumentationParameters.LibraryMethods - .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); - - // TODO: there has to be a better way... - libraryModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.LibraryTypes - .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); - - System.out.println("Processing Test Project..."); - Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(clientProjectLocation), CodeType.ALL); CtModel clientModel = clientLauncher.buildModel(); @@ -185,9 +180,18 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.ClientTypes .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); - XStream xstream = new XStream(new DomDriver()); BufferedWriter bufferedWriter = Files.newBufferedWriter(apiReportOutputPath, StandardOpenOption.CREATE); - xstream.toXML(instrumentationParameters, bufferedWriter); + + try { + String serializedJsonString = objectMapper.writeValueAsString(instrumentationParameters); + bufferedWriter.write(serializedJsonString); + } catch (Exception e) { + System.out.println("ERROR: Cannot serialize specific argument: " + e); + } + + //XStream xstream = new XStream(new DomDriver()); + //xstream.toXML(instrumentationParameters, bufferedWriter); + bufferedWriter.close(); } } \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 8d5526d3..590c2e97 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -6,7 +6,5 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; public List ClientMethods; public List ClientTypes; - public List LibraryMethods; - public List LibraryTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 584f4c39..a32dff2f 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,7 +4,5 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; public String[] ClientMethods; public String[] ClientTypes; - public String[] LibraryMethods; - public String[] LibraryTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 1c667d83..9a450c83 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -1,5 +1,7 @@ package com.github.gilesi.instrumentation; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.confgen.models.Class; import com.github.gilesi.confgen.models.InstrumentationParameters; import com.github.gilesi.instrumentation.visitors.CommonAdvisor; @@ -17,9 +19,17 @@ Our main agent class */ public class Agent { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { - String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - return XmlUtils.getFromXml(xmlContent); + //String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + //return XmlUtils.getFromXml(xmlContent); + return objectMapper.readValue(file, InstrumentationParameters.class); } /* diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java index 139fd033..672fa28a 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java @@ -6,11 +6,15 @@ import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; import com.github.gilesi.maestro.testing.surefire.FileUtils; import org.apache.maven.shared.invoker.MavenInvocationException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.ArrayList; + +import static com.github.gilesi.maestro.Orchestrator.*; public class CompSuite { public static void cloneDataset() throws IOException, InterruptedException { @@ -66,7 +70,13 @@ public static void handleDataset() throws IOException, MavenInvocationException Path datasetOutputPath = Path.of(datasetOutput); for (CompSuiteIncompatibility incompatibility : incompatibilities) { - if (!incompatibility.id.equals("i-122")) { + if (incompatibility.id.equals("i-49") || + incompatibility.id.equals("i-59") || + incompatibility.id.equals("i-92") || + incompatibility.id.equals("i-93") || + incompatibility.id.equals("i-99") || + incompatibility.id.equals("i-115") || + incompatibility.id.equals("i-122")) { continue; } @@ -110,4 +120,239 @@ public static void handleDataset() throws IOException, MavenInvocationException Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, testAssertedLogger.HasTestFailed(), testAssertedLogger2.HasTestFailed())); } } + + public static void runOnDataset() throws IOException, MavenInvocationException, InterruptedException, XmlPullParserException { + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite2"; + CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + if (incompatibility.id.equals("i-i-75") || + incompatibility.id.equals("i-59") || + incompatibility.id.equals("i-92") || + incompatibility.id.equals("i-93") || + incompatibility.id.equals("i-99") || + incompatibility.id.equals("i-115") || + incompatibility.id.equals("i-122")) { + continue; + } + + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + if (!incompatibility.submodule.equals("N/A")) { + oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); + newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); + } + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } + + + + + + String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); + String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); + String clientLocation = oldDestinationProjectPath.toString(); + String dependencyName = incompatibility.lib; + String dependencyVersion = incompatibility.old; + String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; + + if (!Files.exists(Path.of(libraryLocation))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + if (incompatibility.id.equals("i-1")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); + + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Create the results directory + Files.createDirectories(outputTestProjectPath); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), + libraryConfig.toString(), + outputTestProject, + libraryLocation, + clientLocation + }, null); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + //orchestrateMavenProjects(clientProjectPomFiles); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; + + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + + + + + + + Main.logger.info("Testing old project"); + TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + + + + + + + + + tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + + lastMinuteCleanup(allProjectFiles); + + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + + String buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + }""".formatted(dependencyName, dependencyVersion); + + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + } + } + + public static void copySourcesForDataset() throws IOException, MavenInvocationException { + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite2"; + CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + String mavenRepoPath = "%s/%s/%s".formatted(incompatibility.lib.split(":")[0].replace(".", "/"), incompatibility.lib.split(":")[1], incompatibility.old); + Path fileSystemRepoPath = Path.of("/home/gus/.m2/repository/" + mavenRepoPath); + + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + + ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); + + if (srcCandidates.size() == 0) { + Main.logger.info("%s Missing sources for lib, aborting!".formatted(incompatibility.id)); + continue; + } + + /*Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old"); + FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); + Files.createDirectories(oldDestinationProjectPath); + + for (String cand : srcCandidates) { + //Files.copy(Path.of(cand), oldDestinationProjectPath); + System.out.println("Extracting " + cand); + extractJar(cand, oldDestinationProjectPath.toString()); + }*/ + } + } + + public static void extractJar(String jar, String destdir) throws java.io.IOException { + java.util.jar.JarFile jarfile = new java.util.jar.JarFile(new java.io.File(jar)); + java.util.Enumeration enu = jarfile.entries(); + while (enu.hasMoreElements()) { + java.util.jar.JarEntry je = enu.nextElement(); + + System.out.println(je.getName()); + + java.io.File fl = new java.io.File(destdir, je.getName()); + if (!fl.exists()) { + fl.getParentFile().mkdirs(); + fl = new java.io.File(destdir, je.getName()); + } + if (je.isDirectory()) { + continue; + } + java.io.InputStream is = jarfile.getInputStream(je); + java.io.FileOutputStream fo = new java.io.FileOutputStream(fl); + while (is.available() > 0) { + fo.write(is.read()); + } + fo.close(); + is.close(); + } + } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index b3bc3d4f..b8986d56 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -13,7 +13,7 @@ public class Constants { // These paths are dynamically created by the tool but must stay consistent within methods public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; - public static final String targetConfigurationName = "TestWorkflowConfiguration.xml"; + public static final String targetConfigurationName = "TestWorkflowConfiguration.json"; public static final Map JAVA_VERSIONS = new Hashtable<>() { { @@ -30,7 +30,7 @@ public class Constants { public static final String GREEN_TEST = "Green"; public static final String RED_TEST = "Red"; - public static final String SUREFIRE_VERSION = "3.2.5"; + public static final String SUREFIRE_VERSION = "2.8"; public static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 96fc441b..0de5b115 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -32,6 +32,6 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP //Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject); - CompSuite.handleDataset(); + CompSuite.runOnDataset(); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index bf6a3574..0b44f491 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -108,7 +108,7 @@ testImplementation platform('org.junit:junit-bom:5.10.0') // Write report } - private static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { + public static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { for (String clientBuildFile : allProjectFiles) { Path clientBuildFilePath = Path.of(clientBuildFile); Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); @@ -129,7 +129,7 @@ private static void copyInstrumentationToolAndConfiguration(ArrayList al } } - private static void orchestrateMavenProjects(ArrayList clientProjectPomFiles) throws IOException, XmlPullParserException { + public static void orchestrateMavenProjects(ArrayList clientProjectPomFiles) throws IOException, XmlPullParserException { for (String clientBuildFile : clientProjectPomFiles) { Path clientBuildFilePath = Path.of(clientBuildFile); Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); @@ -139,7 +139,7 @@ private static void orchestrateMavenProjects(ArrayList clientProjectPomF } } - private static void orchestrateGradleProjects(ArrayList clientProjectGradleBuildFiles) throws IOException { + public static void orchestrateGradleProjects(ArrayList clientProjectGradleBuildFiles) throws IOException { for (String clientBuildFile : clientProjectGradleBuildFiles) { String clientTestingBlock = """ testing { @@ -170,7 +170,7 @@ private static void orchestrateGradleProjects(ArrayList clientProjectGra } } - private static void executeMavenProjectTests(ArrayList clientProjectPomFiles, String clientLocation) throws MavenInvocationException { + public static void executeMavenProjectTests(ArrayList clientProjectPomFiles, String clientLocation) throws MavenInvocationException { // This is the maven path if (!clientProjectPomFiles.isEmpty()) { if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { @@ -186,7 +186,7 @@ private static void executeMavenProjectTests(ArrayList clientProjectPomF } } - private static void executeGradleProjectTests(ArrayList clientProjectGradleBuildFiles, String clientLocation) throws IOException, InterruptedException { + public static void executeGradleProjectTests(ArrayList clientProjectGradleBuildFiles, String clientLocation) throws IOException, InterruptedException { // This is the gradle path if (!clientProjectGradleBuildFiles.isEmpty()) { if (clientProjectGradleBuildFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("build.gradle"))) { @@ -216,7 +216,7 @@ private static void executeGradleProjectTests(ArrayList clientProjectGra } } - private static void tracesToCode(String GilesiRepositoryLocation, String outputTestProject, String outputCodeDirectory) throws IOException, InterruptedException { + public static void tracesToCode(String GilesiRepositoryLocation, String outputTestProject, String outputCodeDirectory) throws IOException, InterruptedException { // Turn traces into Java files ArrayList traceFiles = FileUtils.enumerateFiles(outputTestProject, "MethodTraces_.*\\.xml", false); for (String traceFile : traceFiles) { @@ -230,7 +230,7 @@ private static void tracesToCode(String GilesiRepositoryLocation, String outputT } } - private static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { + public static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { // Last minute cleanup for (String clientBuildFile : allProjectFiles) { Path clientBuildFilePath = Path.of(clientBuildFile); From 97b8df78ff0884ed92eb5f441c7038a22433fded Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:02:06 +0200 Subject: [PATCH 129/244] add compsuiteharness for repro --- CompSuiteHarness/.gitignore | 39 +++ CompSuiteHarness/build.gradle | 81 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + CompSuiteHarness/gradlew | 234 ++++++++++++++++ CompSuiteHarness/gradlew.bat | 89 ++++++ CompSuiteHarness/settings.gradle | 2 + .../gilesi/harness/compsuite/CompSuite.java | 96 +++++++ .../compsuite/CompSuiteIncompatibility.java | 17 ++ .../gilesi/harness/compsuite/Constants.java | 20 ++ .../gilesi/harness/compsuite/FetchGit.java | 67 +++++ .../gilesi/harness/compsuite/FileUtils.java | 25 ++ .../github/gilesi/harness/compsuite/Main.java | 26 ++ .../configuration/maven/PomHelper.java | 21 ++ .../compsuite/runners/maven/Log4JLogger.java | 260 ++++++++++++++++++ .../runners/maven/ProjectRunner.java | 127 +++++++++ .../runners/maven/TestAssertedLogger.java | 192 +++++++++++++ .../src/main/resources/log4j2.xml | 22 ++ 18 files changed, 1324 insertions(+) create mode 100644 CompSuiteHarness/.gitignore create mode 100644 CompSuiteHarness/build.gradle create mode 100644 CompSuiteHarness/gradle/wrapper/gradle-wrapper.jar create mode 100644 CompSuiteHarness/gradle/wrapper/gradle-wrapper.properties create mode 100755 CompSuiteHarness/gradlew create mode 100644 CompSuiteHarness/gradlew.bat create mode 100644 CompSuiteHarness/settings.gradle create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteIncompatibility.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Constants.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FileUtils.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/buildsystem/configuration/maven/PomHelper.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/Log4JLogger.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/TestAssertedLogger.java create mode 100644 CompSuiteHarness/src/main/resources/log4j2.xml diff --git a/CompSuiteHarness/.gitignore b/CompSuiteHarness/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/CompSuiteHarness/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle new file mode 100644 index 00000000..09b6cb53 --- /dev/null +++ b/CompSuiteHarness/build.gradle @@ -0,0 +1,81 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'com.github.gilesi.harness.compsuite' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() + mavenLocal() + maven { + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.14.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.0' + implementation 'com.fasterxml.jackson:jackson-base:2.14.0' + implementation 'org.apache.maven:maven-core:3.8.5' + implementation 'org.apache.maven.shared:maven-invoker:3.2.0' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + implementation 'org.apache.logging.log4j:log4j-core:2.19.0' + implementation 'org.apache.logging.log4j:log4j-api:2.19.0' +} + +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.harness.compsuite.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.harness.compsuite.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.harness.compsuite') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.harness.compsuite' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=2G" + ] +} \ No newline at end of file diff --git a/CompSuiteHarness/gradle/wrapper/gradle-wrapper.jar b/CompSuiteHarness/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/CompSuiteHarness/gradlew.bat b/CompSuiteHarness/gradlew.bat new file mode 100644 index 00000000..ac1b06f9 --- /dev/null +++ b/CompSuiteHarness/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/CompSuiteHarness/settings.gradle b/CompSuiteHarness/settings.gradle new file mode 100644 index 00000000..5b4528a5 --- /dev/null +++ b/CompSuiteHarness/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'CompSuiteHarness' + diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java new file mode 100644 index 00000000..df96903e --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java @@ -0,0 +1,96 @@ +package com.github.gilesi.harness.compsuite; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.gilesi.harness.compsuite.runners.maven.Log4JLogger; +import com.github.gilesi.harness.compsuite.runners.maven.ProjectRunner; +import com.github.gilesi.harness.compsuite.runners.maven.TestAssertedLogger; +import org.apache.maven.shared.invoker.MavenInvocationException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class CompSuite { + private static CompSuiteIncompatibility[] readDataset(String dataset) throws IOException { + return new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + } + + private static void printIncompatibility(CompSuiteIncompatibility incompatibility) { + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + } + + public static void cloneDataset(String dataset, String datasetOutput) throws IOException, InterruptedException { + CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); + + FileUtils.deleteDirectoryIfExists(datasetOutput); + Path datasetOutputPath = Path.of(datasetOutput); + Files.createDirectories(datasetOutputPath); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + printIncompatibility(incompatibility); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); + FileUtils.deleteDirectoryIfExists(newDestinationProjectPath.toString()); + + Files.createDirectories(oldDestinationProjectPath); + Files.createDirectories(newDestinationProjectPath); + + Main.logger.info("Cloning old at: %s".formatted(oldDestinationProjectPath)); + FetchGit.cloneProject(incompatibility.url, incompatibility.sha, oldDestinationProjectPath); + + Main.logger.info("Cloning new at: %s".formatted(newDestinationProjectPath)); + FetchGit.cloneProject(incompatibility.url, "tags/%s-%s".formatted(incompatibility.lib.replace(":", "--"), incompatibility._new), newDestinationProjectPath); + } + } + + public static void runRegressionTestsOnDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { + CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + printIncompatibility(incompatibility); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + if (!incompatibility.submodule.equals("N/A")) { + oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); + newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); + } + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } + + Main.logger.info("Testing old project"); + TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + + Main.logger.info("Testing new project"); + TestAssertedLogger testAssertedLogger2 = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger2); + + Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, testAssertedLogger.HasTestFailed(), testAssertedLogger2.HasTestFailed())); + } + } +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteIncompatibility.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteIncompatibility.java new file mode 100644 index 00000000..990c0848 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteIncompatibility.java @@ -0,0 +1,17 @@ +package com.github.gilesi.harness.compsuite; + +import com.fasterxml.jackson.annotation.JsonProperty; + +public class CompSuiteIncompatibility { + public String id; + public String client; + public String url; + public String sha; + public String lib; + public String old; + @JsonProperty("new") + public String _new; + public String test; + public String submodule; + public String test_cmd; +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Constants.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Constants.java new file mode 100644 index 00000000..f13bbbfe --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Constants.java @@ -0,0 +1,20 @@ +package com.github.gilesi.harness.compsuite; + +import java.util.Hashtable; +import java.util.Map; + +public class Constants { + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64"; + + public static final Map JAVA_VERSIONS = new Hashtable<>() { + { + put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); + put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); + put("21", JAVA_21_BINARY_LOCATION); + } + }; +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java new file mode 100644 index 00000000..2392b38a --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java @@ -0,0 +1,67 @@ +package com.github.gilesi.harness.compsuite; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +public class FetchGit { + private static String[] getGitCloneCommands(String repoUrl, String hash) { + return new String[]{ + "git init", + "git remote add origin " + repoUrl, + "git fetch --depth 1 origin " + hash, + "git reset --hard FETCH_HEAD", + "git submodule init", + "git submodule update" + }; + } + + // Needed for some compsuite projects + // TODO: say which ones right here... + private static String[] getGitFullCloneCommands(String repoUrl, String hash) { + return new String[]{ + "git clone " + repoUrl, + "git checkout " + hash, + "git submodule init", + "git submodule update" + }; + } + + private static boolean deleteDirectory(File fi) { + boolean globalResult = true; + + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + if (!file.delete()) { + globalResult = false; + } + } + if (!fi.delete()) { + globalResult = false; + } + + return globalResult; + } + + public static void cloneProject(String cloneUrl, String commit, Path repositoryDestination) throws IOException, InterruptedException { + String[] commands = getGitCloneCommands(cloneUrl, commit); + + if (Files.exists(repositoryDestination)) { + if (deleteDirectory(new File(repositoryDestination.toString()))) { + Files.createDirectory(repositoryDestination); + } + } else { + Files.createDirectory(repositoryDestination); + } + + for (String cmd : commands) { + File fi = new File(repositoryDestination.toString()); + Process p1 = Runtime.getRuntime().exec(cmd.split(" "), null, fi); + p1.waitFor(); + } + } +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FileUtils.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FileUtils.java new file mode 100644 index 00000000..7f8d7b07 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FileUtils.java @@ -0,0 +1,25 @@ +package com.github.gilesi.harness.compsuite; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.Objects; + +public class FileUtils { + public static void deleteDirectory(File fi) { + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + file.delete(); + } + fi.delete(); + } + + public static void deleteDirectoryIfExists(String path) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + deleteDirectory(new File(path)); + } + } +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java new file mode 100644 index 00000000..bce5b76c --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java @@ -0,0 +1,26 @@ +package com.github.gilesi.harness.compsuite; + +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; + +public class Main { + public static final Logger logger = LogManager.getLogger(); + + public static void main(String[] args) throws MavenInvocationException, IOException, InterruptedException { + if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { + logger.info("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); + return; + } + + String dataset = "/home/gus/Datasets/compsuite3/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite3"; + + CompSuite.cloneDataset(dataset, datasetOutput); + CompSuite.runRegressionTestsOnDataset(dataset, datasetOutput); + } +} \ No newline at end of file diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/buildsystem/configuration/maven/PomHelper.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/buildsystem/configuration/maven/PomHelper.java new file mode 100644 index 00000000..aaaa3405 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/buildsystem/configuration/maven/PomHelper.java @@ -0,0 +1,21 @@ +package com.github.gilesi.harness.compsuite.buildsystem.configuration.maven; + +import org.apache.maven.model.Model; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PomHelper { + public static Model readPomFile(String pomFilePath) throws IOException, XmlPullParserException { + MavenXpp3Reader pomReader = new MavenXpp3Reader(); + Path pomPath = Path.of(pomFilePath); + InputStream pomStream = Files.newInputStream(pomPath); + Model pomModel = pomReader.read(pomStream); + pomModel.setPomFile(new File(pomFilePath)); + pomStream.close(); + return pomModel; + } +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/Log4JLogger.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/Log4JLogger.java new file mode 100644 index 00000000..31885827 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/Log4JLogger.java @@ -0,0 +1,260 @@ +package com.github.gilesi.harness.compsuite.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class Log4JLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The print stream to write to, never null. + */ + private final Logger out; + + /** + * The threshold used to filter messages. + */ + private int threshold; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public Log4JLogger() { + this(LogManager.getLogger(), INFO); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param out The print stream to write to, must not be null. + * @param threshold The threshold for the logger. + */ + public Log4JLogger(Logger out, int threshold) { + if (out == null) { + throw new NullPointerException("missing output stream"); + } + this.out = out; + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + Level logLevel = Level.INFO; + + switch (level) { + case (DEBUG) -> logLevel = Level.DEBUG; + case (INFO) -> logLevel = Level.INFO; + case (WARN) -> logLevel = Level.WARN; + case (ERROR) -> logLevel = Level.ERROR; + case (FATAL) -> logLevel = Level.FATAL; + default -> { + } + } + + buffer.append("[Maven] "); + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + out.log(logLevel, buffer.toString()); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java new file mode 100644 index 00000000..b91e8855 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java @@ -0,0 +1,127 @@ +package com.github.gilesi.harness.compsuite.runners.maven; + +import com.github.gilesi.harness.compsuite.Constants; +import com.github.gilesi.harness.compsuite.Main; +import org.apache.maven.model.*; +import org.apache.maven.shared.invoker.*; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static com.github.gilesi.harness.compsuite.buildsystem.configuration.maven.PomHelper.readPomFile; + +public class ProjectRunner { + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, Object logger) throws MavenInvocationException { + + String javaVersion = "8"; + + try { + Model pomModel = readPomFile(pomFilePath); + Properties props = pomModel.getProperties(); + if (props.stringPropertyNames().contains("java.compiler.version")) { + javaVersion = props.getProperty("java.compiler.version"); + Main.logger.info("Debug: Using java.compiler.version=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.source")) { + javaVersion = props.getProperty("maven.compiler.source"); + Main.logger.info("Debug: Using maven.compiler.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.target")) { + javaVersion = props.getProperty("maven.compiler.target"); + Main.logger.info("Debug: Using maven.compiler.target=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.source")) { + javaVersion = props.getProperty("maven.compile.source"); + Main.logger.info("Debug: Using maven.compile.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.target")) { + javaVersion = props.getProperty("maven.compile.target"); + Main.logger.info("Debug: Using maven.compile.target=" + javaVersion); + } + } catch (Exception ignored) { + Main.logger.info("Debug: Getting java specific version unfortunately failed."); + } + + return runPomGoals(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaVersion, logger); + } + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { + String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion, logger); + } + + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger) throws MavenInvocationException { + File pomFile = new File(pomFilePath); + + InvokerLogger invokerLogger = null; + InvocationOutputHandler invocationOutputHandler = null; + + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + + File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); + + Properties properties = new Properties(); + pomProperties.forEach(p -> properties.put(p, true)); + properties.put("maven.compiler.source", JavaVersion); + properties.put("maven.compiler.target", JavaVersion); + properties.put("maven.compile.source", JavaVersion); + properties.put("maven.compile.target", JavaVersion); + + String javacLocation = "%s%sbin%sjavac".formatted(JavaHome, File.separator, File.separator); + pomGoals.add("-Dmaven.compiler.fork=true"); + if (Files.exists(Path.of(javacLocation))) { + pomGoals.add("-Dmaven.compiler.executable=%s".formatted(javacLocation)); + } + + InvocationRequest request = new DefaultInvocationRequest(); + request.setShellEnvironmentInherited(false); + request.setPomFile(pomFile); + request.setGoals(pomGoals); + request.setProperties(properties); + request.setBatchMode(batchMode); + request.setJavaHome(new File(JavaHome)); + request.setBaseDirectory(projectDirectory); + request.setInputStream(InputStream.nullInputStream()); + if (invocationOutputHandler != null) { + request.setOutputHandler(invocationOutputHandler); + request.setErrorHandler(invocationOutputHandler); + } + + if (userSettingsFilePath != null && !userSettingsFilePath.isEmpty() && !userSettingsFilePath.isBlank()) { + Path pa = Path.of(userSettingsFilePath); + if (Files.exists(pa) && Files.isRegularFile(pa)) { + request.setUserSettingsFile(new File(userSettingsFilePath)); + } + } + + Main.logger.info("Building with pom=%s goals=%s properties=%s%n".formatted(pomFilePath, pomGoals, properties)); + + Invoker invoker = new DefaultInvoker(); + if (invokerLogger != null) { + invoker.setLogger(invokerLogger); + } + invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); + InvocationResult result = invoker.execute(request); + return result.getExitCode(); + } + + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { + Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); + String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); + ArrayList goals = new ArrayList<>(); + goals.add(goal); + + if (javaVersion != null && !javaVersion.isBlank()) { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger) == 0; + } else { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger) == 0; + } + } +} \ No newline at end of file diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/TestAssertedLogger.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/TestAssertedLogger.java new file mode 100644 index 00000000..866fd8f3 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/TestAssertedLogger.java @@ -0,0 +1,192 @@ +package com.github.gilesi.harness.compsuite.runners.maven; + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.IOException; + +public class TestAssertedLogger implements InvokerLogger, InvocationOutputHandler { + + private InvokerLogger invokerLogger = null; + private InvocationOutputHandler invocationOutputHandler = null; + private boolean testFailed = false; + + public TestAssertedLogger(Object logger) { + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + } + + + public void debug(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message); + } + } + + public void debug(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message, throwable); + } + } + + public boolean isDebugEnabled() { + if (invokerLogger != null) { + return invokerLogger.isDebugEnabled(); + } + + return false; + } + + public void info(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message); + } + } + + public void info(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message, throwable); + } + } + + public boolean isInfoEnabled() { + if (invokerLogger != null) { + return invokerLogger.isInfoEnabled(); + } + + return false; + } + + public void warn(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message); + } + } + + public void warn(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message, throwable); + } + } + + public boolean isWarnEnabled() { + if (invokerLogger != null) { + return invokerLogger.isWarnEnabled(); + } + + return false; + } + + public void error(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message); + } + } + + public void error(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message, throwable); + } + } + + public boolean isErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isErrorEnabled(); + } + + return false; + } + + public void fatalError(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message); + } + } + + public void fatalError(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message, throwable); + } + } + + public boolean isFatalErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isFatalErrorEnabled(); + } + + return false; + } + + public int getThreshold() { + if (invokerLogger != null) { + return invokerLogger.getThreshold(); + } + + return 0; + } + + public void setThreshold(int threshold) { + if (invokerLogger != null) { + invokerLogger.setThreshold(threshold); + } + } + + public void consumeLine(String line) throws IOException { + if (line.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invocationOutputHandler != null) { + invocationOutputHandler.consumeLine(line); + } + } + + public boolean HasTestFailed() { + return testFailed; + } +} diff --git a/CompSuiteHarness/src/main/resources/log4j2.xml b/CompSuiteHarness/src/main/resources/log4j2.xml new file mode 100644 index 00000000..43d5fcb3 --- /dev/null +++ b/CompSuiteHarness/src/main/resources/log4j2.xml @@ -0,0 +1,22 @@ + + + + + + %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + \ No newline at end of file From ac7da18b238a617fd18ae5718a0b137f76268093 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:06:29 +0200 Subject: [PATCH 130/244] fixes for harness --- .../java/com/github/gilesi/harness/compsuite/Main.java | 2 +- CompSuiteHarness/src/main/resources/log4j2.xml | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java index bce5b76c..7abd1f67 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java @@ -17,7 +17,7 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept return; } - String dataset = "/home/gus/Datasets/compsuite3/incompatibilities.json"; + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; String datasetOutput = "/home/gus/Datasets/compsuite3"; CompSuite.cloneDataset(dataset, datasetOutput); diff --git a/CompSuiteHarness/src/main/resources/log4j2.xml b/CompSuiteHarness/src/main/resources/log4j2.xml index 43d5fcb3..e49fab87 100644 --- a/CompSuiteHarness/src/main/resources/log4j2.xml +++ b/CompSuiteHarness/src/main/resources/log4j2.xml @@ -1,8 +1,8 @@ - + - + %d{HH:mm:ss.SSS} [%t] %-5level %logger{36} - %msg%n @@ -15,7 +15,7 @@ - + From ee7849d7410f3a240f06c21b590e79a0adcd2c94 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:14:21 +0200 Subject: [PATCH 131/244] fixes for maestro --- .../com/github/gilesi/maestro/CompSuite.java | 358 ------------------ .../com/github/gilesi/maestro/FetchGit.java | 62 --- .../{testing/surefire => }/FileUtils.java | 2 +- .../java/com/github/gilesi/maestro/Main.java | 5 +- .../github/gilesi/maestro/Orchestrator.java | 1 - .../gilesi/maestro/compsuite/CompSuite.java | 193 ++++++++++ .../maestro/compsuite/CompSuiteFixes.java | 67 ++++ .../CompSuiteIncompatibility.java | 2 +- .../testing/surefire/SurefireHarness.java | 1 + 9 files changed, 267 insertions(+), 424 deletions(-) delete mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java delete mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java rename Maestro/src/main/java/com/github/gilesi/maestro/{testing/surefire => }/FileUtils.java (98%) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java rename Maestro/src/main/java/com/github/gilesi/maestro/{ => compsuite}/CompSuiteIncompatibility.java (89%) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java deleted file mode 100644 index 672fa28a..00000000 --- a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuite.java +++ /dev/null @@ -1,358 +0,0 @@ -package com.github.gilesi.maestro; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.gilesi.maestro.runners.maven.Log4JLogger; -import com.github.gilesi.maestro.runners.maven.ProjectRunner; -import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; -import com.github.gilesi.maestro.testing.surefire.FileUtils; -import org.apache.maven.shared.invoker.MavenInvocationException; -import org.codehaus.plexus.util.xml.pull.XmlPullParserException; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.ArrayList; - -import static com.github.gilesi.maestro.Orchestrator.*; - -public class CompSuite { - public static void cloneDataset() throws IOException, InterruptedException { - String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; - String datasetOutput = "/home/gus/Datasets/compsuite2"; - CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); - - //FileUtils.deleteDirectoryIfExists(datasetOutput); - Path datasetOutputPath = Path.of(datasetOutput); - //Files.createDirectories(datasetOutputPath); - - for (CompSuiteIncompatibility incompatibility : incompatibilities) { - if (!incompatibility.id.equals("i-122")) { - continue; - } - - - Main.logger.info("-----------------------------------"); - Main.logger.info("id: %s".formatted(incompatibility.id)); - Main.logger.info("client: %s".formatted(incompatibility.client)); - Main.logger.info("url: %s".formatted(incompatibility.url)); - Main.logger.info("sha: %s".formatted(incompatibility.sha)); - Main.logger.info("lib: %s".formatted(incompatibility.lib)); - Main.logger.info("old: %s".formatted(incompatibility.old)); - Main.logger.info("new: %s".formatted(incompatibility._new)); - Main.logger.info("test: %s".formatted(incompatibility.test)); - Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); - Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); - Main.logger.info("-----------------------------------"); - - Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); - Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); - - FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); - FileUtils.deleteDirectoryIfExists(newDestinationProjectPath.toString()); - - Files.createDirectories(oldDestinationProjectPath); - Files.createDirectories(newDestinationProjectPath); - - Main.logger.info("Cloning old at: %s".formatted(oldDestinationProjectPath)); - FetchGit.cloneProject(incompatibility.url, incompatibility.sha, oldDestinationProjectPath); - - Main.logger.info("Cloning new at: %s".formatted(newDestinationProjectPath)); - FetchGit.cloneProject(incompatibility.url, "tags/%s-%s".formatted(incompatibility.lib.replace(":", "--"), incompatibility._new), newDestinationProjectPath); - } - } - - public static void handleDataset() throws IOException, MavenInvocationException { - String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; - String datasetOutput = "/home/gus/Datasets/compsuite2"; - CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); - - Path datasetOutputPath = Path.of(datasetOutput); - - for (CompSuiteIncompatibility incompatibility : incompatibilities) { - if (incompatibility.id.equals("i-49") || - incompatibility.id.equals("i-59") || - incompatibility.id.equals("i-92") || - incompatibility.id.equals("i-93") || - incompatibility.id.equals("i-99") || - incompatibility.id.equals("i-115") || - incompatibility.id.equals("i-122")) { - continue; - } - - Main.logger.info("-----------------------------------"); - Main.logger.info("id: %s".formatted(incompatibility.id)); - Main.logger.info("client: %s".formatted(incompatibility.client)); - Main.logger.info("url: %s".formatted(incompatibility.url)); - Main.logger.info("sha: %s".formatted(incompatibility.sha)); - Main.logger.info("lib: %s".formatted(incompatibility.lib)); - Main.logger.info("old: %s".formatted(incompatibility.old)); - Main.logger.info("new: %s".formatted(incompatibility._new)); - Main.logger.info("test: %s".formatted(incompatibility.test)); - Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); - Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); - Main.logger.info("-----------------------------------"); - - Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); - Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); - - if (!incompatibility.submodule.equals("N/A")) { - oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); - newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); - } - - String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); - if (!incompatibility.test_cmd.equals("N/A")) { - testCmd = incompatibility.test_cmd; - if (testCmd.startsWith("mvn ")) { - testCmd = testCmd.substring(4); - } - } - - Main.logger.info("Testing old project"); - TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); - - Main.logger.info("Testing new project"); - TestAssertedLogger testAssertedLogger2 = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger2); - - Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, testAssertedLogger.HasTestFailed(), testAssertedLogger2.HasTestFailed())); - } - } - - public static void runOnDataset() throws IOException, MavenInvocationException, InterruptedException, XmlPullParserException { - String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; - String datasetOutput = "/home/gus/Datasets/compsuite2"; - CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); - - Path datasetOutputPath = Path.of(datasetOutput); - - for (CompSuiteIncompatibility incompatibility : incompatibilities) { - if (incompatibility.id.equals("i-i-75") || - incompatibility.id.equals("i-59") || - incompatibility.id.equals("i-92") || - incompatibility.id.equals("i-93") || - incompatibility.id.equals("i-99") || - incompatibility.id.equals("i-115") || - incompatibility.id.equals("i-122")) { - continue; - } - - Main.logger.info("-----------------------------------"); - Main.logger.info("id: %s".formatted(incompatibility.id)); - Main.logger.info("client: %s".formatted(incompatibility.client)); - Main.logger.info("url: %s".formatted(incompatibility.url)); - Main.logger.info("sha: %s".formatted(incompatibility.sha)); - Main.logger.info("lib: %s".formatted(incompatibility.lib)); - Main.logger.info("old: %s".formatted(incompatibility.old)); - Main.logger.info("new: %s".formatted(incompatibility._new)); - Main.logger.info("test: %s".formatted(incompatibility.test)); - Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); - Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); - Main.logger.info("-----------------------------------"); - - Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); - Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); - - if (!incompatibility.submodule.equals("N/A")) { - oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); - newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); - } - - String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); - if (!incompatibility.test_cmd.equals("N/A")) { - testCmd = incompatibility.test_cmd; - if (testCmd.startsWith("mvn ")) { - testCmd = testCmd.substring(4); - } - } - - - - - - String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); - String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); - String clientLocation = oldDestinationProjectPath.toString(); - String dependencyName = incompatibility.lib; - String dependencyVersion = incompatibility.old; - String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; - - if (!Files.exists(Path.of(libraryLocation))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - if (incompatibility.id.equals("i-1")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - FileUtils.deleteDirectoryIfExists(outputTestProject); - Path outputTestProjectPath = Path.of(outputTestProject); - - Path libraryLocationPath = Path.of(libraryLocation); - Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - - // Create the results directory - Files.createDirectories(outputTestProjectPath); - - // Run ConfGen on Library first - // TODO: Check how meta projects get handled here exactly... - ProcessUtils.runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), - libraryConfig.toString(), - outputTestProject, - libraryLocation, - clientLocation - }, null); - - Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); - - // Modify Client Build System to use the instrumentation agent - ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); - ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - - ArrayList allProjectFiles = new ArrayList<>(); - allProjectFiles.addAll(clientProjectPomFiles); - allProjectFiles.addAll(clientProjectGradleBuildFiles); - - copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); - - //orchestrateMavenProjects(clientProjectPomFiles); - - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; - - orchestrateGradleProjects(clientProjectGradleBuildFiles); - - - - - - - - Main.logger.info("Testing old project"); - TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); - - - - - - - - - tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); - - lastMinuteCleanup(allProjectFiles); - - // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion - - String buildGradleProjectFile = """ - plugins { - id 'java' - } - - group = 'testProject' - version = '1.0-SNAPSHOT' - - repositories { - mavenCentral() - mavenLocal() - } - - dependencies { - testImplementation '%s:%s' - testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' - testImplementation platform('org.junit:junit-bom:5.10.0') - testImplementation 'org.junit.jupiter:junit-jupiter' - } - - test { - useJUnitPlatform() - }""".formatted(dependencyName, dependencyVersion); - - Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); - } - } - - public static void copySourcesForDataset() throws IOException, MavenInvocationException { - String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; - String datasetOutput = "/home/gus/Datasets/compsuite2"; - CompSuiteIncompatibility[] incompatibilities = new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); - - Path datasetOutputPath = Path.of(datasetOutput); - - for (CompSuiteIncompatibility incompatibility : incompatibilities) { - String mavenRepoPath = "%s/%s/%s".formatted(incompatibility.lib.split(":")[0].replace(".", "/"), incompatibility.lib.split(":")[1], incompatibility.old); - Path fileSystemRepoPath = Path.of("/home/gus/.m2/repository/" + mavenRepoPath); - - Main.logger.info("-----------------------------------"); - Main.logger.info("id: %s".formatted(incompatibility.id)); - Main.logger.info("client: %s".formatted(incompatibility.client)); - Main.logger.info("url: %s".formatted(incompatibility.url)); - Main.logger.info("sha: %s".formatted(incompatibility.sha)); - Main.logger.info("lib: %s".formatted(incompatibility.lib)); - Main.logger.info("old: %s".formatted(incompatibility.old)); - Main.logger.info("new: %s".formatted(incompatibility._new)); - Main.logger.info("test: %s".formatted(incompatibility.test)); - Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); - Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); - Main.logger.info("-----------------------------------"); - - ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); - - if (srcCandidates.size() == 0) { - Main.logger.info("%s Missing sources for lib, aborting!".formatted(incompatibility.id)); - continue; - } - - /*Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old"); - FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); - Files.createDirectories(oldDestinationProjectPath); - - for (String cand : srcCandidates) { - //Files.copy(Path.of(cand), oldDestinationProjectPath); - System.out.println("Extracting " + cand); - extractJar(cand, oldDestinationProjectPath.toString()); - }*/ - } - } - - public static void extractJar(String jar, String destdir) throws java.io.IOException { - java.util.jar.JarFile jarfile = new java.util.jar.JarFile(new java.io.File(jar)); - java.util.Enumeration enu = jarfile.entries(); - while (enu.hasMoreElements()) { - java.util.jar.JarEntry je = enu.nextElement(); - - System.out.println(je.getName()); - - java.io.File fl = new java.io.File(destdir, je.getName()); - if (!fl.exists()) { - fl.getParentFile().mkdirs(); - fl = new java.io.File(destdir, je.getName()); - } - if (je.isDirectory()) { - continue; - } - java.io.InputStream is = jarfile.getInputStream(je); - java.io.FileOutputStream fo = new java.io.FileOutputStream(fl); - while (is.available() > 0) { - fo.write(is.read()); - } - fo.close(); - is.close(); - } - } -} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java b/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java deleted file mode 100644 index 8ab82902..00000000 --- a/Maestro/src/main/java/com/github/gilesi/maestro/FetchGit.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.github.gilesi.maestro; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.util.Objects; - -public class FetchGit { - private static String[] getGitCloneCommands(String repoUrl, String hash) { - /*return new String[]{ - "git init", - "git remote add origin " + repoUrl, - "git fetch --depth 1 origin " + hash, - "git reset --hard FETCH_HEAD", - "git submodule init", - "git submodule update" - };*/ - return new String[]{ - "git clone " + repoUrl, - "git checkout " + hash, - "git submodule init", - "git submodule update" - }; - } - - private static boolean deleteDirectory(File fi) { - boolean globalResult = true; - - for (File file : Objects.requireNonNull(fi.listFiles())) { - if (file.isDirectory()) { - deleteDirectory(file); - } - if (!file.delete()) { - globalResult = false; - } - } - if (!fi.delete()) { - globalResult = false; - } - - return globalResult; - } - - public static void cloneProject(String cloneUrl, String commit, Path repositoryDestination) throws IOException, InterruptedException { - String[] commands = getGitCloneCommands(cloneUrl, commit); - - if (Files.exists(repositoryDestination)) { - if (deleteDirectory(new File(repositoryDestination.toString()))) { - Files.createDirectory(repositoryDestination); - } - } else { - Files.createDirectory(repositoryDestination); - } - - for (String cmd : commands) { - File fi = new File(repositoryDestination.toString()); - Process p1 = Runtime.getRuntime().exec(cmd.split(" "), null, fi); - p1.waitFor(); - } - } -} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java similarity index 98% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java rename to Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java index b552f315..b4d1f367 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/FileUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro; import java.io.File; import java.io.IOException; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 0de5b115..720401a8 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -1,5 +1,6 @@ package com.github.gilesi.maestro; +import com.github.gilesi.maestro.compsuite.CompSuite; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.apache.logging.log4j.LogManager; @@ -32,6 +33,8 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP //Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject); - CompSuite.runOnDataset(); + String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; + String datasetOutput = "/home/gus/Datasets/compsuite2"; + CompSuite.runOnDataset(dataset, datasetOutput); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index 0b44f491..a38badd5 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -3,7 +3,6 @@ import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; import com.github.gilesi.maestro.runners.maven.Log4JLogger; import com.github.gilesi.maestro.runners.maven.ProjectRunner; -import com.github.gilesi.maestro.testing.surefire.FileUtils; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java new file mode 100644 index 00000000..803a4c1e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -0,0 +1,193 @@ +package com.github.gilesi.maestro.compsuite; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.github.gilesi.maestro.Constants; +import com.github.gilesi.maestro.FileUtils; +import com.github.gilesi.maestro.Main; +import com.github.gilesi.maestro.ProcessUtils; +import com.github.gilesi.maestro.runners.maven.Log4JLogger; +import com.github.gilesi.maestro.runners.maven.ProjectRunner; +import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; +import org.apache.maven.shared.invoker.MavenInvocationException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +import static com.github.gilesi.maestro.Orchestrator.*; + +public class CompSuite { + static CompSuiteIncompatibility[] readDataset(String dataset) throws IOException { + return new ObjectMapper().readValue(new File(dataset), CompSuiteIncompatibility[].class); + } + + static void printIncompatibility(CompSuiteIncompatibility incompatibility) { + Main.logger.info("-----------------------------------"); + Main.logger.info("id: %s".formatted(incompatibility.id)); + Main.logger.info("client: %s".formatted(incompatibility.client)); + Main.logger.info("url: %s".formatted(incompatibility.url)); + Main.logger.info("sha: %s".formatted(incompatibility.sha)); + Main.logger.info("lib: %s".formatted(incompatibility.lib)); + Main.logger.info("old: %s".formatted(incompatibility.old)); + Main.logger.info("new: %s".formatted(incompatibility._new)); + Main.logger.info("test: %s".formatted(incompatibility.test)); + Main.logger.info("submodule: %s".formatted(incompatibility.submodule)); + Main.logger.info("test_cmd: %s".formatted(incompatibility.test_cmd)); + Main.logger.info("-----------------------------------"); + } + + public static void runOnDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException, InterruptedException { + CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + if (incompatibility.id.equals("i-i-75") || + incompatibility.id.equals("i-59") || + incompatibility.id.equals("i-92") || + incompatibility.id.equals("i-93") || + incompatibility.id.equals("i-99") || + incompatibility.id.equals("i-115") || + incompatibility.id.equals("i-122")) { + continue; + } + + printIncompatibility(incompatibility); + + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + if (!incompatibility.submodule.equals("N/A")) { + oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); + newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); + } + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } + + + + + + String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); + String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); + String clientLocation = oldDestinationProjectPath.toString(); + String dependencyName = incompatibility.lib; + String dependencyVersion = incompatibility.old; + String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; + + if (!Files.exists(Path.of(libraryLocation))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + if (incompatibility.id.equals("i-1")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); + + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Create the results directory + Files.createDirectories(outputTestProjectPath); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), + libraryConfig.toString(), + outputTestProject, + libraryLocation, + clientLocation + }, null); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + //orchestrateMavenProjects(clientProjectPomFiles); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; + + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + + + + + + + Main.logger.info("Testing old project"); + TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + + + + + + + + + tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + + lastMinuteCleanup(allProjectFiles); + + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + + String buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + }""".formatted(dependencyName, dependencyVersion); + + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + } + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java new file mode 100644 index 00000000..5c3fee3e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java @@ -0,0 +1,67 @@ +package com.github.gilesi.maestro.compsuite; + +import com.github.gilesi.maestro.FileUtils; +import com.github.gilesi.maestro.Main; +import org.apache.maven.shared.invoker.MavenInvocationException; + +import java.io.IOException; +import java.nio.file.Path; +import java.util.ArrayList; + +public class CompSuiteFixes { + public static void copySourcesForDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { + CompSuiteIncompatibility[] incompatibilities = CompSuite.readDataset(dataset); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + String mavenRepoPath = "%s/%s/%s".formatted(incompatibility.lib.split(":")[0].replace(".", "/"), incompatibility.lib.split(":")[1], incompatibility.old); + Path fileSystemRepoPath = Path.of("/home/gus/.m2/repository/" + mavenRepoPath); + + CompSuite.printIncompatibility(incompatibility); + + ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); + + if (srcCandidates.size() == 0) { + Main.logger.info("%s Missing sources for lib, aborting!".formatted(incompatibility.id)); + continue; + } + + /*Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old"); + FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); + Files.createDirectories(oldDestinationProjectPath); + + for (String cand : srcCandidates) { + //Files.copy(Path.of(cand), oldDestinationProjectPath); + System.out.println("Extracting " + cand); + extractJar(cand, oldDestinationProjectPath.toString()); + }*/ + } + } + + public static void extractJar(String jar, String destdir) throws java.io.IOException { + java.util.jar.JarFile jarfile = new java.util.jar.JarFile(new java.io.File(jar)); + java.util.Enumeration enu = jarfile.entries(); + while (enu.hasMoreElements()) { + java.util.jar.JarEntry je = enu.nextElement(); + + System.out.println(je.getName()); + + java.io.File fl = new java.io.File(destdir, je.getName()); + if (!fl.exists()) { + fl.getParentFile().mkdirs(); + fl = new java.io.File(destdir, je.getName()); + } + if (je.isDirectory()) { + continue; + } + java.io.InputStream is = jarfile.getInputStream(je); + java.io.FileOutputStream fo = new java.io.FileOutputStream(fl); + while (is.available() > 0) { + fo.write(is.read()); + } + fo.close(); + is.close(); + } + } +} \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteIncompatibility.java similarity index 89% rename from Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java rename to Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteIncompatibility.java index 431f782e..b29b15a9 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/CompSuiteIncompatibility.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteIncompatibility.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro; +package com.github.gilesi.maestro.compsuite; import com.fasterxml.jackson.annotation.JsonProperty; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java index 35eea9dd..98dac4ba 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java @@ -1,5 +1,6 @@ package com.github.gilesi.maestro.testing.surefire; +import com.github.gilesi.maestro.FileUtils; import com.github.gilesi.maestro.Main; import java.io.File; From 03e5126b9c7d4697e5d68c4565c9549c8f950529 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:33:52 +0200 Subject: [PATCH 132/244] fixes for harness --- .../gilesi/harness/compsuite/CompSuite.java | 20 +++++++++++----- .../compsuite/CompSuiteRegressionResults.java | 23 +++++++++++++++++++ .../gilesi/harness/compsuite/FetchGit.java | 6 ++--- .../github/gilesi/harness/compsuite/Main.java | 10 +++++++- 4 files changed, 49 insertions(+), 10 deletions(-) create mode 100644 CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteRegressionResults.java diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java index df96903e..b03edfb1 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java @@ -10,6 +10,8 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.HashMap; +import java.util.Map; public class CompSuite { private static CompSuiteIncompatibility[] readDataset(String dataset) throws IOException { @@ -58,9 +60,11 @@ public static void cloneDataset(String dataset, String datasetOutput) throws IOE } } - public static void runRegressionTestsOnDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { + public static Map runRegressionTestsOnDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); + Map mapList = new HashMap<>(); + Path datasetOutputPath = Path.of(datasetOutput); for (CompSuiteIncompatibility incompatibility : incompatibilities) { @@ -83,14 +87,18 @@ public static void runRegressionTestsOnDataset(String dataset, String datasetOut } Main.logger.info("Testing old project"); - TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger); Main.logger.info("Testing new project"); - TestAssertedLogger testAssertedLogger2 = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger2); + TestAssertedLogger newTestAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", newTestAssertedLogger); + + Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, oldTestAssertedLogger.HasTestFailed(), newTestAssertedLogger.HasTestFailed())); - Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, testAssertedLogger.HasTestFailed(), testAssertedLogger2.HasTestFailed())); + mapList.put(incompatibility, new CompSuiteRegressionResults(oldTestAssertedLogger.HasTestFailed(), newTestAssertedLogger.HasTestFailed())); } + + return mapList; } } diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteRegressionResults.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteRegressionResults.java new file mode 100644 index 00000000..39fc5409 --- /dev/null +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuiteRegressionResults.java @@ -0,0 +1,23 @@ +package com.github.gilesi.harness.compsuite; + +public class CompSuiteRegressionResults { + public boolean oldPassed; + public boolean newPassed; + + public CompSuiteRegressionResults(boolean oldPassed, boolean newPassed) { + this.oldPassed = oldPassed; + this.newPassed = newPassed; + } + + public boolean isNewPassed() { + return newPassed; + } + + public boolean isOldPassed() { + return oldPassed; + } + + public boolean isRegressionReproduced() { + return oldPassed && !newPassed; + } +} diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java index 2392b38a..27061338 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/FetchGit.java @@ -22,8 +22,8 @@ private static String[] getGitCloneCommands(String repoUrl, String hash) { // TODO: say which ones right here... private static String[] getGitFullCloneCommands(String repoUrl, String hash) { return new String[]{ - "git clone " + repoUrl, - "git checkout " + hash, + "git clone %s .".formatted(repoUrl), + "git checkout %s".formatted(hash), "git submodule init", "git submodule update" }; @@ -48,7 +48,7 @@ private static boolean deleteDirectory(File fi) { } public static void cloneProject(String cloneUrl, String commit, Path repositoryDestination) throws IOException, InterruptedException { - String[] commands = getGitCloneCommands(cloneUrl, commit); + String[] commands = getGitFullCloneCommands(cloneUrl, commit); if (Files.exists(repositoryDestination)) { if (deleteDirectory(new File(repositoryDestination.toString()))) { diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java index 7abd1f67..786b9113 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java @@ -7,6 +7,7 @@ import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; +import java.util.Map; public class Main { public static final Logger logger = LogManager.getLogger(); @@ -20,7 +21,14 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; String datasetOutput = "/home/gus/Datasets/compsuite3"; + logger.info("Cloning CompSuite DataSet"); CompSuite.cloneDataset(dataset, datasetOutput); - CompSuite.runRegressionTestsOnDataset(dataset, datasetOutput); + + logger.info("Running CompSuite Incompatibilities"); + Map result = CompSuite.runRegressionTestsOnDataset(dataset, datasetOutput); + + for (Map.Entry entry : result.entrySet()) { + logger.info("Project: %s Old: %s New: %s RegressionReproduced: %s".formatted(entry.getKey().id, entry.getValue().isOldPassed(), entry.getValue().isNewPassed(), entry.getValue().isRegressionReproduced())); + } } } \ No newline at end of file From d6e9ac62ec902de07adce1416b117418343f7507 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:45:45 +0200 Subject: [PATCH 133/244] misc fixes --- .../github/gilesi/instrumentation/Agent.java | 2 +- .../github/gilesi/instrumentation/Logger.java | 2 +- .../instrumentation/TraceCollector.java | 4 +- .../instrumentation/TraceDataFactory.java | 4 +- .../visitors/MethodAdvisor.java | 2 +- .../.gradle/8.7/checksums/checksums.lock | Bin 17 -> 0 bytes .../8.7/dependencies-accessors/gc.properties | 0 .../8.7/executionHistory/executionHistory.bin | Bin 19654 -> 0 bytes .../executionHistory/executionHistory.lock | Bin 17 -> 0 bytes .../.gradle/8.7/fileChanges/last-build.bin | Bin 1 -> 0 bytes .../.gradle/8.7/fileHashes/fileHashes.bin | Bin 19247 -> 0 bytes .../.gradle/8.7/fileHashes/fileHashes.lock | Bin 17 -> 0 bytes MyTestProject/.gradle/8.7/gc.properties | 0 .../buildOutputCleanup.lock | Bin 17 -> 0 bytes .../buildOutputCleanup/cache.properties | 2 - .../buildOutputCleanup/outputFiles.bin | Bin 18713 -> 0 bytes MyTestProject/.gradle/vcs-1/gc.properties | 0 MyTestProject/MethodTraces_1.xml | 1 - MyTestProject/MethodTraces_10.xml | 1 - MyTestProject/MethodTraces_11.xml | 1 - MyTestProject/MethodTraces_12.xml | 1 - MyTestProject/MethodTraces_13.xml | 1 - MyTestProject/MethodTraces_14.xml | 1 - MyTestProject/MethodTraces_15.xml | 1 - MyTestProject/MethodTraces_16.xml | 1 - MyTestProject/MethodTraces_17.xml | 1 - MyTestProject/MethodTraces_18.xml | 1 - MyTestProject/MethodTraces_19.xml | 1 - MyTestProject/MethodTraces_2.xml | 1 - MyTestProject/MethodTraces_20.xml | 1 - MyTestProject/MethodTraces_21.xml | 1 - MyTestProject/MethodTraces_22.xml | 1 - MyTestProject/MethodTraces_23.xml | 1 - MyTestProject/MethodTraces_24.xml | 1 - MyTestProject/MethodTraces_25.xml | 1 - MyTestProject/MethodTraces_26.xml | 1 - MyTestProject/MethodTraces_27.xml | 1 - MyTestProject/MethodTraces_28.xml | 320 ------------------ MyTestProject/MethodTraces_29.xml | 1 - MyTestProject/MethodTraces_3.xml | 1 - MyTestProject/MethodTraces_30.xml | 1 - MyTestProject/MethodTraces_31.xml | 1 - MyTestProject/MethodTraces_32.xml | 1 - MyTestProject/MethodTraces_33.xml | 1 - MyTestProject/MethodTraces_34.xml | 1 - MyTestProject/MethodTraces_35.xml | 1 - MyTestProject/MethodTraces_36.xml | 1 - MyTestProject/MethodTraces_37.xml | 1 - MyTestProject/MethodTraces_38.xml | 1 - MyTestProject/MethodTraces_39.xml | 1 - MyTestProject/MethodTraces_4.xml | 1 - MyTestProject/MethodTraces_40.xml | 1 - MyTestProject/MethodTraces_41.xml | 1 - MyTestProject/MethodTraces_42.xml | 1 - MyTestProject/MethodTraces_43.xml | 1 - MyTestProject/MethodTraces_44.xml | 1 - MyTestProject/MethodTraces_45.xml | 1 - MyTestProject/MethodTraces_46.xml | 1 - MyTestProject/MethodTraces_47.xml | 1 - MyTestProject/MethodTraces_48.xml | 1 - MyTestProject/MethodTraces_49.xml | 1 - MyTestProject/MethodTraces_5.xml | 1 - MyTestProject/MethodTraces_50.xml | 1 - MyTestProject/MethodTraces_51.xml | 1 - MyTestProject/MethodTraces_52.xml | 1 - MyTestProject/MethodTraces_53.xml | 1 - MyTestProject/MethodTraces_54.xml | 1 - MyTestProject/MethodTraces_55.xml | 1 - MyTestProject/MethodTraces_56.xml | 1 - MyTestProject/MethodTraces_57.xml | 1 - MyTestProject/MethodTraces_58.xml | 1 - MyTestProject/MethodTraces_59.xml | 1 - MyTestProject/MethodTraces_6.xml | 1 - MyTestProject/MethodTraces_60.xml | 1 - MyTestProject/MethodTraces_61.xml | 1 - MyTestProject/MethodTraces_62.xml | 1 - MyTestProject/MethodTraces_63.xml | 1 - MyTestProject/MethodTraces_64.xml | 1 - MyTestProject/MethodTraces_65.xml | 1 - MyTestProject/MethodTraces_66.xml | 1 - MyTestProject/MethodTraces_67.xml | 1 - MyTestProject/MethodTraces_68.xml | 1 - MyTestProject/MethodTraces_69.xml | 1 - MyTestProject/MethodTraces_7.xml | 1 - MyTestProject/MethodTraces_70.xml | 1 - MyTestProject/MethodTraces_71.xml | 1 - MyTestProject/MethodTraces_8.xml | 1 - MyTestProject/MethodTraces_9.xml | 1 - MyTestProject/Unknown_28_1.xml | 103 ------ MyTestProject/Unknown_28_2.xml | 103 ------ MyTestProject/Unknown_28_3.xml | 103 ------ MyTestProject/build.gradle | 22 -- .../gradle/wrapper/gradle-wrapper.properties | 7 - MyTestProject/gradlew | 249 -------------- MyTestProject/gradlew.bat | 92 ----- run-test-workflow.sh | 5 +- 96 files changed, 11 insertions(+), 1079 deletions(-) delete mode 100644 MyTestProject/.gradle/8.7/checksums/checksums.lock delete mode 100644 MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties delete mode 100644 MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin delete mode 100644 MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock delete mode 100644 MyTestProject/.gradle/8.7/fileChanges/last-build.bin delete mode 100644 MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin delete mode 100644 MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock delete mode 100644 MyTestProject/.gradle/8.7/gc.properties delete mode 100644 MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock delete mode 100644 MyTestProject/.gradle/buildOutputCleanup/cache.properties delete mode 100644 MyTestProject/.gradle/buildOutputCleanup/outputFiles.bin delete mode 100644 MyTestProject/.gradle/vcs-1/gc.properties delete mode 100644 MyTestProject/MethodTraces_1.xml delete mode 100644 MyTestProject/MethodTraces_10.xml delete mode 100644 MyTestProject/MethodTraces_11.xml delete mode 100644 MyTestProject/MethodTraces_12.xml delete mode 100644 MyTestProject/MethodTraces_13.xml delete mode 100644 MyTestProject/MethodTraces_14.xml delete mode 100644 MyTestProject/MethodTraces_15.xml delete mode 100644 MyTestProject/MethodTraces_16.xml delete mode 100644 MyTestProject/MethodTraces_17.xml delete mode 100644 MyTestProject/MethodTraces_18.xml delete mode 100644 MyTestProject/MethodTraces_19.xml delete mode 100644 MyTestProject/MethodTraces_2.xml delete mode 100644 MyTestProject/MethodTraces_20.xml delete mode 100644 MyTestProject/MethodTraces_21.xml delete mode 100644 MyTestProject/MethodTraces_22.xml delete mode 100644 MyTestProject/MethodTraces_23.xml delete mode 100644 MyTestProject/MethodTraces_24.xml delete mode 100644 MyTestProject/MethodTraces_25.xml delete mode 100644 MyTestProject/MethodTraces_26.xml delete mode 100644 MyTestProject/MethodTraces_27.xml delete mode 100644 MyTestProject/MethodTraces_28.xml delete mode 100644 MyTestProject/MethodTraces_29.xml delete mode 100644 MyTestProject/MethodTraces_3.xml delete mode 100644 MyTestProject/MethodTraces_30.xml delete mode 100644 MyTestProject/MethodTraces_31.xml delete mode 100644 MyTestProject/MethodTraces_32.xml delete mode 100644 MyTestProject/MethodTraces_33.xml delete mode 100644 MyTestProject/MethodTraces_34.xml delete mode 100644 MyTestProject/MethodTraces_35.xml delete mode 100644 MyTestProject/MethodTraces_36.xml delete mode 100644 MyTestProject/MethodTraces_37.xml delete mode 100644 MyTestProject/MethodTraces_38.xml delete mode 100644 MyTestProject/MethodTraces_39.xml delete mode 100644 MyTestProject/MethodTraces_4.xml delete mode 100644 MyTestProject/MethodTraces_40.xml delete mode 100644 MyTestProject/MethodTraces_41.xml delete mode 100644 MyTestProject/MethodTraces_42.xml delete mode 100644 MyTestProject/MethodTraces_43.xml delete mode 100644 MyTestProject/MethodTraces_44.xml delete mode 100644 MyTestProject/MethodTraces_45.xml delete mode 100644 MyTestProject/MethodTraces_46.xml delete mode 100644 MyTestProject/MethodTraces_47.xml delete mode 100644 MyTestProject/MethodTraces_48.xml delete mode 100644 MyTestProject/MethodTraces_49.xml delete mode 100644 MyTestProject/MethodTraces_5.xml delete mode 100644 MyTestProject/MethodTraces_50.xml delete mode 100644 MyTestProject/MethodTraces_51.xml delete mode 100644 MyTestProject/MethodTraces_52.xml delete mode 100644 MyTestProject/MethodTraces_53.xml delete mode 100644 MyTestProject/MethodTraces_54.xml delete mode 100644 MyTestProject/MethodTraces_55.xml delete mode 100644 MyTestProject/MethodTraces_56.xml delete mode 100644 MyTestProject/MethodTraces_57.xml delete mode 100644 MyTestProject/MethodTraces_58.xml delete mode 100644 MyTestProject/MethodTraces_59.xml delete mode 100644 MyTestProject/MethodTraces_6.xml delete mode 100644 MyTestProject/MethodTraces_60.xml delete mode 100644 MyTestProject/MethodTraces_61.xml delete mode 100644 MyTestProject/MethodTraces_62.xml delete mode 100644 MyTestProject/MethodTraces_63.xml delete mode 100644 MyTestProject/MethodTraces_64.xml delete mode 100644 MyTestProject/MethodTraces_65.xml delete mode 100644 MyTestProject/MethodTraces_66.xml delete mode 100644 MyTestProject/MethodTraces_67.xml delete mode 100644 MyTestProject/MethodTraces_68.xml delete mode 100644 MyTestProject/MethodTraces_69.xml delete mode 100644 MyTestProject/MethodTraces_7.xml delete mode 100644 MyTestProject/MethodTraces_70.xml delete mode 100644 MyTestProject/MethodTraces_71.xml delete mode 100644 MyTestProject/MethodTraces_8.xml delete mode 100644 MyTestProject/MethodTraces_9.xml delete mode 100644 MyTestProject/Unknown_28_1.xml delete mode 100644 MyTestProject/Unknown_28_2.xml delete mode 100644 MyTestProject/Unknown_28_3.xml delete mode 100644 MyTestProject/build.gradle delete mode 100644 MyTestProject/gradle/wrapper/gradle-wrapper.properties delete mode 100755 MyTestProject/gradlew delete mode 100644 MyTestProject/gradlew.bat diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 9a450c83..c13ff635 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -41,7 +41,7 @@ private static void installAgent(String arg, Instrumentation inst) { // Sometimes this can fail, so try to catch it try { ByteBuddyAgent.install(); - } catch (Exception e) { + } catch (Throwable e) { System.err.println("ERROR: Could not install byte buddy agent!"); System.err.println(e.getMessage()); e.printStackTrace(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index a4b70ffa..e453488c 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -34,7 +34,7 @@ public static void SaveLogResults(InstrumentationParameters instrumentationParam try { Files.write(new File(logFileName).toPath(), logLines); - } catch (Exception e) { + } catch (Throwable e) { System.err.println("ERROR while saving logs"); e.printStackTrace(); } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index 16f0e435..c585ad47 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -65,7 +65,7 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar FileWriter outputFile = new FileWriter(tracesFileName); outputFile.write(xmlOutputString); outputFile.close(); - } catch (Exception e) { + } catch (Throwable e) { System.err.println("ERROR"); e.printStackTrace(); } @@ -87,7 +87,7 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar FileWriter outputFile = new FileWriter(traceFileName); outputFile.write(xmlOutputString); outputFile.close(); - } catch (Exception e) { + } catch (Throwable e) { System.err.println("ERROR"); e.printStackTrace(); } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index bedd36fb..e9953cfc 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -41,7 +41,7 @@ public static TraceData valueOf(Object object, int nullInstanceId) { try { serializedString = XmlUtils.getToXml(object); - } catch (Exception e) { + } catch (Throwable e) { int loggerInstance = Logger.GetInstance(); Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); } @@ -50,7 +50,7 @@ public static TraceData valueOf(Object object, int nullInstanceId) { try { serializedJsonString = objectMapper.writeValueAsString(object); - } catch (Exception e) { + } catch (Throwable e) { int loggerInstance = Logger.GetInstance(); Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); }*/ diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java index d7d2f235..70c0d6c9 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodAdvisor.java @@ -15,7 +15,7 @@ public static Object enter( return CommonAdvisor.commonEnter(origin, arguments, instance); } - @Advice.OnMethodExit(onThrowable = Exception.class, inline = false) + @Advice.OnMethodExit(onThrowable = Throwable.class, inline = false) public static void exit( @Advice.Origin Executable origin, @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, diff --git a/MyTestProject/.gradle/8.7/checksums/checksums.lock b/MyTestProject/.gradle/8.7/checksums/checksums.lock deleted file mode 100644 index 7fb0e8a42731fe301e0c79d703da4778c3b6eb6c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 TcmZQRw)W+f^TEZf3{U_7M7ae{ diff --git a/MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties b/MyTestProject/.gradle/8.7/dependencies-accessors/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin b/MyTestProject/.gradle/8.7/executionHistory/executionHistory.bin deleted file mode 100644 index 8ce7e6783c963a24b516796787756fce72f5650d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19654 zcmeI%Pe>F|90%~X>jn~qbI1^?Q}#!w9o=bA_zymp_iJIi}-b}=jv zq(ViLu!15YDEb3gheRSf8C{|d)+z8}MgJ~QhZ3S@cU?5 zXNxJ?;!HORQiPPQup5q2ea&I#%4?Uh!;Q7M{||C^yT2qmhARXh009U<00Izz00bZa z0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0{?=5 zmk?LCeaiHCK^}=xEu7>LUo_lK<5oqoLo$=4M7dH|_;B*Z;iu0lYG`lY>Sfd2zx9w& zlSkYUt{E}v))LGuHPIp5DXt|Fl)DdQ@1X$IO|D65D6h*uUA|ws`SG?@1)i@n8(%t? z9DzJ`gz797GlDv22^lI5aVs9uW2Ue;Ei2BoJRzS(EB#ev<&|YszEY#g??2-4=w6@C zFbuz!mRBnAo{^DSbEawCiM3bHcn?i3AJDiSWl37637UUl0yrY$MQqz(yLN+PqlUj@!_BvbmMs{)saSenu zsYkO*#4)Ny%}%ODETJ|qsYY0g3Z^!9wNfElxYwqo#(FiPY(2W-mG?=YS;K~d%EM1W6?3y+>bw3XKu6Dp@{PAz4U9rJ1b8HcTK)K z7WgpUm(DaX<#Y`txM}Yx$*9O=e6sY6^AU;iYWi)?B7WKBa@gOUo}X3e-PiyC diff --git a/MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock b/MyTestProject/.gradle/8.7/executionHistory/executionHistory.lock deleted file mode 100644 index 07910a6b6f7e1a339c32dae5fe4eac2eb4d1cb90..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZRs|9nDi{~z821_)pV06P2xj{pDw diff --git a/MyTestProject/.gradle/8.7/fileChanges/last-build.bin b/MyTestProject/.gradle/8.7/fileChanges/last-build.bin deleted file mode 100644 index f76dd238ade08917e6712764a16a22005a50573d..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1 IcmZPo000310RR91 diff --git a/MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin b/MyTestProject/.gradle/8.7/fileHashes/fileHashes.bin deleted file mode 100644 index 9dfeccbdaee17f2156a3ef6eb83bcc8aec6c3191..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 19247 zcmeI(dn{FP00;1M!{$|9qpQqg$YVmHh&)P-D@q=t+pTHRY^pyfQOI16ndf8}g_`18 zc`T30s~GDxAxT!d>kl(wl_+Ido$H+Ax=w%fXZxP*-1FP_obS2!_c?!_`|~CUuI6ug zBV?PdY={vAAOHafKmY;|fB*y_009U<00Izz00bZa0SG_<0{@FZ2ssf|YBF4#P11oz zJVDs2O9w);vEDBQ#zxd>UK#WLApLZ_SD1WQ9N);FE=;3y1tuTA)x{6cSJ$R;AFs81;7a1F zFwtW=uVL~9zDT1!Cntc)eJh#Vv|?wLZ4CDreSIvG+Z*!cP6oC;pszo_me03eZ+0|} zrgIf04~na9=;~|OM&&#wCJ(7qk9o6{luYL@m^?+W)V*ge$(7E}F*$Q22u=cZ4xbQ! z00bZa0SG_<0uX=z1Rwwb2tWV=5P$##AOHafKmY;|fB*y_009U<00Izz00bZa0SG_< z0uX=z1Rwx`e-qeE)~v|gM7nE^`e*F0vUKEFME`b|6DK7Dpaba?yVL@9&P0t z?$P-b(YpIu%_UWxZVNx#=|&9IFj-_bhGydSMg%o(&I~%(_c6(PmTovxjk->DV^T7G z%=A+B?T)7Xt)iGsD|Ew&Y7oop1}}V~X!`*zOShD!($@~x$X~$QH-co+5*?Y$fNO^$l{RMIO5`6>=zh z>!XJPeopyU;$}*sTtiPx&TFHtzj}XhS}!LvK{?!E;ParGT*LH?bS1@x=Mg$B3A@2B zkDm}}57%@_$Ymh1nJdgCN3t8a9;u3)6Iyk`LGF(!$0Ovb3R#07^efp7v0=5@VSPfc zZ0Y^hyY~#r+rm}k8pMoP+V}&c@QeBY diff --git a/MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock b/MyTestProject/.gradle/8.7/fileHashes/fileHashes.lock deleted file mode 100644 index d6dd2a27ea0805f2e2f18b7607998e6f8405a2a0..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQ(@;MuO%lF|81_%%Z05Zh{aR2}S diff --git a/MyTestProject/.gradle/8.7/gc.properties b/MyTestProject/.gradle/8.7/gc.properties deleted file mode 100644 index e69de29b..00000000 diff --git a/MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock b/MyTestProject/.gradle/buildOutputCleanup/buildOutputCleanup.lock deleted file mode 100644 index f6cc2ab97556e4fc31bcf126f04754cd3b886cee..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 17 UcmZQBk~LbY`S?Qt0|f8`04+cRF0Mpzagm6_M!8AJVR2VzuTHDI%tgwHGOeOG zD7Wz^Cq-PGoaUr3W8TjuHwQ}JshN3w=gpt@xz2!6cJfVcs=U>ghl~(F009ILKmY** z5I_I{1Q0*~0R#|0009ILK;XX!j0FoxM2oT8jc`ztQ>x1f2G(kJqoOV8c+uq{U;ZBy zjPd=Z`}n->57M3M!M&Gs?UnAH^n;maCt;f1y01$w-MLx6dGb{Eg7ll>(bPzzRi}I3 zXFpq7xtQ1~>3%HTU%u^cO;2ZZpOtPbx|zz?bNT+9^p>rTwaz*FB$_`Qm!9g~&R?cB z8}xHVr7t`kdhTPfO7~sqa#kv)*A~s-hyVfzAb \ No newline at end of file diff --git a/MyTestProject/MethodTraces_10.xml b/MyTestProject/MethodTraces_10.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_10.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_11.xml b/MyTestProject/MethodTraces_11.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_11.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_12.xml b/MyTestProject/MethodTraces_12.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_12.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_13.xml b/MyTestProject/MethodTraces_13.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_13.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_14.xml b/MyTestProject/MethodTraces_14.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_14.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_15.xml b/MyTestProject/MethodTraces_15.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_15.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_16.xml b/MyTestProject/MethodTraces_16.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_16.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_17.xml b/MyTestProject/MethodTraces_17.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_17.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_18.xml b/MyTestProject/MethodTraces_18.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_18.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_19.xml b/MyTestProject/MethodTraces_19.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_19.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_2.xml b/MyTestProject/MethodTraces_2.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_2.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_20.xml b/MyTestProject/MethodTraces_20.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_20.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_21.xml b/MyTestProject/MethodTraces_21.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_21.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_22.xml b/MyTestProject/MethodTraces_22.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_22.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_23.xml b/MyTestProject/MethodTraces_23.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_23.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_24.xml b/MyTestProject/MethodTraces_24.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_24.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_25.xml b/MyTestProject/MethodTraces_25.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_25.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_26.xml b/MyTestProject/MethodTraces_26.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_26.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_27.xml b/MyTestProject/MethodTraces_27.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_27.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_28.xml b/MyTestProject/MethodTraces_28.xml deleted file mode 100644 index b4bbef9a..00000000 --- a/MyTestProject/MethodTraces_28.xml +++ /dev/null @@ -1,320 +0,0 @@ - - - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 1880371134 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 571815947 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1780349599 - - - 779552853 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 571815947 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1780349599 - - - 796111827 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testInvalidSql - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - - Unknown - - - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 366757863 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 348968268 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1655831856 - - - 781587889 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 348968268 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1655831856 - - - 796296548 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testDirectCompile - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - - Unknown - - - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 1678159396 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 454349760 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1885213554 - - - 782530329 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 454349760 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1885213554 - - - 796217120 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testCompile - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - - Unknown - - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_29.xml b/MyTestProject/MethodTraces_29.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_29.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_3.xml b/MyTestProject/MethodTraces_3.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_3.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_30.xml b/MyTestProject/MethodTraces_30.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_30.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_31.xml b/MyTestProject/MethodTraces_31.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_31.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_32.xml b/MyTestProject/MethodTraces_32.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_32.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_33.xml b/MyTestProject/MethodTraces_33.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_33.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_34.xml b/MyTestProject/MethodTraces_34.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_34.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_35.xml b/MyTestProject/MethodTraces_35.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_35.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_36.xml b/MyTestProject/MethodTraces_36.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_36.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_37.xml b/MyTestProject/MethodTraces_37.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_37.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_38.xml b/MyTestProject/MethodTraces_38.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_38.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_39.xml b/MyTestProject/MethodTraces_39.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_39.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_4.xml b/MyTestProject/MethodTraces_4.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_4.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_40.xml b/MyTestProject/MethodTraces_40.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_40.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_41.xml b/MyTestProject/MethodTraces_41.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_41.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_42.xml b/MyTestProject/MethodTraces_42.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_42.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_43.xml b/MyTestProject/MethodTraces_43.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_43.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_44.xml b/MyTestProject/MethodTraces_44.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_44.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_45.xml b/MyTestProject/MethodTraces_45.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_45.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_46.xml b/MyTestProject/MethodTraces_46.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_46.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_47.xml b/MyTestProject/MethodTraces_47.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_47.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_48.xml b/MyTestProject/MethodTraces_48.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_48.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_49.xml b/MyTestProject/MethodTraces_49.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_49.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_5.xml b/MyTestProject/MethodTraces_5.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_5.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_50.xml b/MyTestProject/MethodTraces_50.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_50.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_51.xml b/MyTestProject/MethodTraces_51.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_51.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_52.xml b/MyTestProject/MethodTraces_52.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_52.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_53.xml b/MyTestProject/MethodTraces_53.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_53.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_54.xml b/MyTestProject/MethodTraces_54.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_54.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_55.xml b/MyTestProject/MethodTraces_55.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_55.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_56.xml b/MyTestProject/MethodTraces_56.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_56.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_57.xml b/MyTestProject/MethodTraces_57.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_57.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_58.xml b/MyTestProject/MethodTraces_58.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_58.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_59.xml b/MyTestProject/MethodTraces_59.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_59.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_6.xml b/MyTestProject/MethodTraces_6.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_6.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_60.xml b/MyTestProject/MethodTraces_60.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_60.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_61.xml b/MyTestProject/MethodTraces_61.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_61.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_62.xml b/MyTestProject/MethodTraces_62.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_62.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_63.xml b/MyTestProject/MethodTraces_63.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_63.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_64.xml b/MyTestProject/MethodTraces_64.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_64.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_65.xml b/MyTestProject/MethodTraces_65.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_65.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_66.xml b/MyTestProject/MethodTraces_66.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_66.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_67.xml b/MyTestProject/MethodTraces_67.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_67.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_68.xml b/MyTestProject/MethodTraces_68.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_68.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_69.xml b/MyTestProject/MethodTraces_69.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_69.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_7.xml b/MyTestProject/MethodTraces_7.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_7.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_70.xml b/MyTestProject/MethodTraces_70.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_70.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_71.xml b/MyTestProject/MethodTraces_71.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_71.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_8.xml b/MyTestProject/MethodTraces_8.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_8.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/MethodTraces_9.xml b/MyTestProject/MethodTraces_9.xml deleted file mode 100644 index a5cbb109..00000000 --- a/MyTestProject/MethodTraces_9.xml +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/MyTestProject/Unknown_28_1.xml b/MyTestProject/Unknown_28_1.xml deleted file mode 100644 index 168e5943..00000000 --- a/MyTestProject/Unknown_28_1.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 1880371134 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 571815947 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1780349599 - - - 779552853 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 571815947 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1780349599 - - - 796111827 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testInvalidSql - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - \ No newline at end of file diff --git a/MyTestProject/Unknown_28_2.xml b/MyTestProject/Unknown_28_2.xml deleted file mode 100644 index 932d0784..00000000 --- a/MyTestProject/Unknown_28_2.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 366757863 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 348968268 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1655831856 - - - 781587889 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 348968268 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1655831856 - - - 796296548 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testDirectCompile - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - \ No newline at end of file diff --git a/MyTestProject/Unknown_28_3.xml b/MyTestProject/Unknown_28_3.xml deleted file mode 100644 index 2fd6f844..00000000 --- a/MyTestProject/Unknown_28_3.xml +++ /dev/null @@ -1,103 +0,0 @@ - - - public org.apache.flink.api.java.typeutils.RowTypeInfo(org.apache.flink.api.common.typeinfo.TypeInformation<?>[],java.lang.String[]) - - org.apache.flink.api.java.typeutils.RowTypeInfo - <org.apache.flink.api.java.typeutils.RowTypeInfo> - <typeClass>org.apache.flink.types.Row</typeClass> - <types> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - </types> - <totalFields>1</totalFields> - <fieldNames> - <string>id</string> - </fieldNames> -</org.apache.flink.api.java.typeutils.RowTypeInfo> - 1678159396 - - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 454349760 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1885213554 - - - 782530329 - - - org.apache.flink.api.common.typeinfo.TypeInformation[] - <org.apache.flink.api.common.typeinfo.TypeInformation-array> - <org.apache.flink.api.common.typeinfo.IntegerTypeInfo> - <clazz>java.lang.Integer</clazz> - <serializer class="org.apache.flink.api.common.typeutils.base.IntSerializer"/> - <possibleCastTargetTypes> - <java-class>java.lang.Long</java-class> - <java-class>java.lang.Float</java-class> - <java-class>java.lang.Double</java-class> - <java-class>java.lang.Character</java-class> - </possibleCastTargetTypes> - <comparatorClass>org.apache.flink.api.common.typeutils.base.IntComparator</comparatorClass> - </org.apache.flink.api.common.typeinfo.IntegerTypeInfo> -</org.apache.flink.api.common.typeinfo.TypeInformation-array> - 454349760 - - - java.lang.String[] - <string-array> - <string>id</string> -</string-array> - 1885213554 - - - 796217120 - - org.apache.flink.api.java.typeutils.RowTypeInfo.<init> - com.uber.athenax.vm.compiler.executor.ProcessExecutorTest.testCompile - jdk.internal.reflect.DirectMethodHandleAccessor.invoke - java.lang.reflect.Method.invoke - org.junit.runners.model.FrameworkMethod$1.runReflectiveCall - org.junit.internal.runners.model.ReflectiveCallable.run - org.junit.runners.model.FrameworkMethod.invokeExplosively - org.junit.internal.runners.statements.InvokeMethod.evaluate - org.junit.runners.ParentRunner.runLeaf - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.BlockJUnit4ClassRunner.runChild - org.junit.runners.ParentRunner$3.run - org.apache.maven.surefire.junitcore.pc.Scheduler$1.run - java.util.concurrent.Executors$RunnableAdapter.call - java.util.concurrent.FutureTask.run - java.util.concurrent.ThreadPoolExecutor.runWorker - java.util.concurrent.ThreadPoolExecutor$Worker.run - java.lang.Thread.run - - - \ No newline at end of file diff --git a/MyTestProject/build.gradle b/MyTestProject/build.gradle deleted file mode 100644 index 10f7a85d..00000000 --- a/MyTestProject/build.gradle +++ /dev/null @@ -1,22 +0,0 @@ -plugins { - id 'java' -} - -group = 'testProject' -version = '1.0-SNAPSHOT' - -repositories { - mavenCentral() - mavenLocal() -} - -dependencies { - testImplementation 'commons-codec:commons-codec:1.12' - testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' - testImplementation platform('org.junit:junit-bom:5.10.0') - testImplementation 'org.junit.jupiter:junit-jupiter' -} - -test { - useJUnitPlatform() -} \ No newline at end of file diff --git a/MyTestProject/gradle/wrapper/gradle-wrapper.properties b/MyTestProject/gradle/wrapper/gradle-wrapper.properties deleted file mode 100644 index b82aa23a..00000000 --- a/MyTestProject/gradle/wrapper/gradle-wrapper.properties +++ /dev/null @@ -1,7 +0,0 @@ -distributionBase=GRADLE_USER_HOME -distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip -networkTimeout=10000 -validateDistributionUrl=true -zipStoreBase=GRADLE_USER_HOME -zipStorePath=wrapper/dists diff --git a/MyTestProject/gradlew b/MyTestProject/gradlew deleted file mode 100755 index 1aa94a42..00000000 --- a/MyTestProject/gradlew +++ /dev/null @@ -1,249 +0,0 @@ -#!/bin/sh - -# -# Copyright © 2015-2021 the original authors. -# -# Licensed under the Apache License, Version 2.0 (the "License"); -# you may not use this file except in compliance with the License. -# You may obtain a copy of the License at -# -# https://www.apache.org/licenses/LICENSE-2.0 -# -# Unless required by applicable law or agreed to in writing, software -# distributed under the License is distributed on an "AS IS" BASIS, -# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -# See the License for the specific language governing permissions and -# limitations under the License. -# - -############################################################################## -# -# Gradle start up script for POSIX generated by Gradle. -# -# Important for running: -# -# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is -# noncompliant, but you have some other compliant shell such as ksh or -# bash, then to run this script, type that shell name before the whole -# command line, like: -# -# ksh Gradle -# -# Busybox and similar reduced shells will NOT work, because this script -# requires all of these POSIX shell features: -# * functions; -# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», -# «${var#prefix}», «${var%suffix}», and «$( cmd )»; -# * compound commands having a testable exit status, especially «case»; -# * various built-in commands including «command», «set», and «ulimit». -# -# Important for patching: -# -# (2) This script targets any POSIX shell, so it avoids extensions provided -# by Bash, Ksh, etc; in particular arrays are avoided. -# -# The "traditional" practice of packing multiple parameters into a -# space-separated string is a well documented source of bugs and security -# problems, so this is (mostly) avoided, by progressively accumulating -# options in "$@", and eventually passing that to Java. -# -# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, -# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; -# see the in-line comments for details. -# -# There are tweaks for specific operating systems such as AIX, CygWin, -# Darwin, MinGW, and NonStop. -# -# (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt -# within the Gradle project. -# -# You can find Gradle at https://github.com/gradle/gradle/. -# -############################################################################## - -# Attempt to set APP_HOME - -# Resolve links: $0 may be a link -app_path=$0 - -# Need this for daisy-chained symlinks. -while - APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path - [ -h "$app_path" ] -do - ls=$( ls -ld "$app_path" ) - link=${ls#*' -> '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -# Discard cd standard output in case $CDPATH is set (https://github.com/gradle/gradle/issues/25036) -APP_HOME=$( cd "${APP_HOME:-./}" > /dev/null && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC2039,SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command: -# * DEFAULT_JVM_OPTS, JAVA_OPTS, JAVA_OPTS, and optsEnvironmentVar are not allowed to contain shell fragments, -# and any embedded shellness will be escaped. -# * For example: A user cannot expect ${Hostname} to be expanded, as it is an environment variable and will be -# treated as '${Hostname}' itself on the command line. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/MyTestProject/gradlew.bat b/MyTestProject/gradlew.bat deleted file mode 100644 index 7101f8e4..00000000 --- a/MyTestProject/gradlew.bat +++ /dev/null @@ -1,92 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. 1>&2 -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 -echo. 1>&2 -echo Please set the JAVA_HOME variable in your environment to match the 1>&2 -echo location of your Java installation. 1>&2 - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/run-test-workflow.sh b/run-test-workflow.sh index b5a1fc68..f312dafe 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -48,4 +48,7 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Results/MethodTraces.xml" "$PWD/Results/TestGenerator.Output" +for file in $PWD/Results/MethodTraces_*.xml; do + [ -f "$file" ] || continue + "$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$file" "$PWD/Results/TestGenerator.Output" +done From 99356072b3a9c771f5b9d5cebef4411f7f02100f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:46:54 +0200 Subject: [PATCH 134/244] fix: +x on sh files --- compile.sh | 0 maracas-test.sh | 0 2 files changed, 0 insertions(+), 0 deletions(-) mode change 100644 => 100755 compile.sh mode change 100644 => 100755 maracas-test.sh diff --git a/compile.sh b/compile.sh old mode 100644 new mode 100755 diff --git a/maracas-test.sh b/maracas-test.sh old mode 100644 new mode 100755 From e0575009297993e059aea8fdd67be69ec3b7c023 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:48:07 +0200 Subject: [PATCH 135/244] fix: add logs folder to gitignore --- .gitignore | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 3abf9ae2..5f5d4116 100644 --- a/.gitignore +++ b/.gitignore @@ -149,4 +149,5 @@ fabric.properties *.db .vscode/ -Results/ \ No newline at end of file +Results/ +/logs/ From 3a2c5018461f6572839399a75c320122f07f169e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 15:48:40 +0200 Subject: [PATCH 136/244] fix: add idea folder to gitignore --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index 5f5d4116..2e9b11a1 100644 --- a/.gitignore +++ b/.gitignore @@ -151,3 +151,4 @@ fabric.properties .vscode/ Results/ /logs/ +/.idea/ From 60b4422f68b66c234526f0595c9ca70ba5b4305a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 16:03:09 +0200 Subject: [PATCH 137/244] refactor: maestro + compsuite --- .../java/com/github/gilesi/maestro/Main.java | 4 +- .../gilesi/maestro/compsuite/CompSuite.java | 168 ++++++++++-------- .../maestro/compsuite/CompSuiteRunnable.java | 11 ++ 3 files changed, 105 insertions(+), 78 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 720401a8..b7905745 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -35,6 +35,8 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; String datasetOutput = "/home/gus/Datasets/compsuite2"; - CompSuite.runOnDataset(dataset, datasetOutput); + String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; + + CompSuite.runOnDataset(GilesiRepositoryLocation, dataset, datasetOutput); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 803a4c1e..73fe75eb 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -38,30 +38,18 @@ static void printIncompatibility(CompSuiteIncompatibility incompatibility) { Main.logger.info("-----------------------------------"); } - public static void runOnDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException, InterruptedException { + public static void runOldOnDataset(String dataset, String datasetOutput, CompSuiteRunnable actionInterface) throws IOException, MavenInvocationException, InterruptedException { CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); Path datasetOutputPath = Path.of(datasetOutput); for (CompSuiteIncompatibility incompatibility : incompatibilities) { - if (incompatibility.id.equals("i-i-75") || - incompatibility.id.equals("i-59") || - incompatibility.id.equals("i-92") || - incompatibility.id.equals("i-93") || - incompatibility.id.equals("i-99") || - incompatibility.id.equals("i-115") || - incompatibility.id.equals("i-122")) { - continue; - } - printIncompatibility(incompatibility); Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); - Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); if (!incompatibility.submodule.equals("N/A")) { oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); - newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); } String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); @@ -72,96 +60,121 @@ public static void runOnDataset(String dataset, String datasetOutput) throws IOE } } - - - - - String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); - String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); - String clientLocation = oldDestinationProjectPath.toString(); - String dependencyName = incompatibility.lib; - String dependencyVersion = incompatibility.old; - String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; - - if (!Files.exists(Path.of(libraryLocation))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - if (incompatibility.id.equals("i-1")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + testCmd = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + if (testCmd == null) { continue; } - FileUtils.deleteDirectoryIfExists(outputTestProject); - Path outputTestProjectPath = Path.of(outputTestProject); - - Path libraryLocationPath = Path.of(libraryLocation); - Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + Main.logger.info("Testing old project"); + TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger); - // Create the results directory - Files.createDirectories(outputTestProjectPath); + actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger); + } + } - // Run ConfGen on Library first - // TODO: Check how meta projects get handled here exactly... - ProcessUtils.runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), - libraryConfig.toString(), - outputTestProject, - libraryLocation, - clientLocation - }, null); + public static void runOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput) throws IOException, MavenInvocationException, InterruptedException { + Path datasetOutputPath = Path.of(datasetOutput); - Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + runOldOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { + @Override + public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException { + if (incompatibility.id.equals("i-75") || + incompatibility.id.equals("i-59") || + incompatibility.id.equals("i-92") || + incompatibility.id.equals("i-93") || + incompatibility.id.equals("i-99") || + incompatibility.id.equals("i-115") || + incompatibility.id.equals("i-122")) { + return null; + } - // Modify Client Build System to use the instrumentation agent - ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); - ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + if (incompatibility.id.equals("i-1")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } - ArrayList allProjectFiles = new ArrayList<>(); - allProjectFiles.addAll(clientProjectPomFiles); - allProjectFiles.addAll(clientProjectGradleBuildFiles); + String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); + String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); + String clientLocation = oldDestinationProjectPath.toString(); - copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + if (!Files.exists(Path.of(libraryLocation))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } - //orchestrateMavenProjects(clientProjectPomFiles); + if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); - testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); - orchestrateGradleProjects(clientProjectGradleBuildFiles); + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + // Create the results directory + Files.createDirectories(outputTestProjectPath); + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), + libraryConfig.toString(), + outputTestProject, + libraryLocation, + clientLocation + }, null); + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); - Main.logger.info("Testing old project"); - TestAssertedLogger testAssertedLogger = new TestAssertedLogger(new Log4JLogger()); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", testAssertedLogger); + //orchestrateMavenProjects(clientProjectPomFiles); + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; + orchestrateGradleProjects(clientProjectGradleBuildFiles); + return testCmd; + } + @Override + public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger) throws IOException, InterruptedException { + String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); + Path outputTestProjectPath = Path.of(outputTestProject); + String dependencyName = incompatibility.lib; + String dependencyVersion = incompatibility.old; + tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + String clientLocation = oldDestinationProjectPath.toString(); + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); - tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); - lastMinuteCleanup(allProjectFiles); + lastMinuteCleanup(allProjectFiles); - // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion - String buildGradleProjectFile = """ + String buildGradleProjectFile = """ plugins { id 'java' } @@ -185,9 +198,10 @@ testImplementation platform('org.junit:junit-bom:5.10.0') useJUnitPlatform() }""".formatted(dependencyName, dependencyVersion); - Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); - } + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + } + }); } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java new file mode 100644 index 00000000..b54a87d2 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java @@ -0,0 +1,11 @@ +package com.github.gilesi.maestro.compsuite; + +import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; + +import java.io.IOException; +import java.nio.file.Path; + +public interface CompSuiteRunnable { + String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException; + void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger) throws IOException, InterruptedException; +} From c15854a54a4221bfa4b7064ffbb1c1ca303e0994 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 21 Jun 2024 18:28:55 +0200 Subject: [PATCH 138/244] fix: reports for harness --- .../java/com/github/gilesi/harness/compsuite/CompSuite.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java index b03edfb1..da106237 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/CompSuite.java @@ -96,7 +96,7 @@ public static Map runRegre Main.logger.info("Project ID: %s - OLD TEST FAILED: %s - NEW TEST FAILED: %s".formatted(incompatibility.id, oldTestAssertedLogger.HasTestFailed(), newTestAssertedLogger.HasTestFailed())); - mapList.put(incompatibility, new CompSuiteRegressionResults(oldTestAssertedLogger.HasTestFailed(), newTestAssertedLogger.HasTestFailed())); + mapList.put(incompatibility, new CompSuiteRegressionResults(!oldTestAssertedLogger.HasTestFailed(), !newTestAssertedLogger.HasTestFailed())); } return mapList; From eb03a6f9debd532dc2c09a153c887fa9a0bfd5c0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 24 Jun 2024 14:35:29 +0200 Subject: [PATCH 139/244] feat: rework filter for java agent --- .../github/gilesi/harness/compsuite/Main.java | 2 +- .../java/com/github/gilesi/confgen/Main.java | 20 ----- .../models/InstrumentationParameters.java | 2 - .../models/InstrumentationParameters.java | 2 - .../github/gilesi/instrumentation/Agent.java | 3 - .../visitors/CommonAdvisor.java | 87 +++++++++---------- 6 files changed, 44 insertions(+), 72 deletions(-) diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java index 786b9113..e333da1b 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/Main.java @@ -22,7 +22,7 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept String datasetOutput = "/home/gus/Datasets/compsuite3"; logger.info("Cloning CompSuite DataSet"); - CompSuite.cloneDataset(dataset, datasetOutput); + //CompSuite.cloneDataset(dataset, datasetOutput); logger.info("Running CompSuite Incompatibilities"); Map result = CompSuite.runRegressionTestsOnDataset(dataset, datasetOutput); diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java index 461b21a3..921a66a8 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/Main.java @@ -126,7 +126,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept String apiReportOutputLocation = args[0]; String traceOutputLocation = args[1]; String libraryProjectLocation = args[2]; - String clientProjectLocation = args[3]; Path apiReportOutputPath = Path.of(apiReportOutputLocation); @@ -141,8 +140,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); - instrumentationParameters.ClientMethods = new ArrayList<>(); - instrumentationParameters.ClientTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; for (ClassDecl classDecl : libraryApiModel.getExportedTypes() @@ -166,20 +163,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept } } - Launcher clientLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); - SpoonLauncherUtilities.applyProjectToLauncher(clientLauncher, Path.of(clientProjectLocation), CodeType.ALL); - CtModel clientModel = clientLauncher.buildModel(); - - System.out.println("Processing Client Project..."); - - clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> type.getMethods() - .forEach(method -> instrumentationParameters.ClientMethods - .add("%s.%s".formatted(type.getQualifiedName(), method.getSimpleName()))))); - - // TODO: there has to be a better way... - clientModel.getAllPackages().forEach(pkg -> pkg.getTypes().forEach(type -> instrumentationParameters.ClientTypes - .add("%s.%s".formatted(type.getQualifiedName(), type.getSimpleName())))); - BufferedWriter bufferedWriter = Files.newBufferedWriter(apiReportOutputPath, StandardOpenOption.CREATE); try { @@ -189,9 +172,6 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept System.out.println("ERROR: Cannot serialize specific argument: " + e); } - //XStream xstream = new XStream(new DomDriver()); - //xstream.toXML(instrumentationParameters, bufferedWriter); - bufferedWriter.close(); } } \ No newline at end of file diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 590c2e97..1c3412c5 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,7 +4,5 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; - public List ClientMethods; - public List ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index a32dff2f..7b3a764e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/Instrumentation/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -2,7 +2,5 @@ public class InstrumentationParameters { public Class[] InstrumentedAPIClasses; - public String[] ClientMethods; - public String[] ClientTypes; public String traceOutputLocation; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index c13ff635..e6f28842 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -83,9 +83,6 @@ private static void installAgent(String arg, Instrumentation inst) { // Add a shutdown hook to save all method execution traces at exit Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(instrumentationParameters))); - CommonAdvisor.ClientMethods = instrumentationParameters.ClientMethods; - CommonAdvisor.ClientTypes = instrumentationParameters.ClientTypes; - // Instrument every class for (Class instrumentationParameter : instrumentationParameters.InstrumentedAPIClasses) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index 3c890da5..abd46a36 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -7,14 +7,14 @@ import com.github.gilesi.instrumentation.models.Trace; import java.lang.reflect.Executable; +import java.util.ArrayList; import java.util.Arrays; public class CommonAdvisor { private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; private static final String JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL = "org.junit.runners.model.FrameworkMethod$1.runReflectiveCall"; private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; - public static String[] ClientMethods = new String[0]; - public static String[] ClientTypes = new String[0]; + private static final ArrayList StackTraces = new ArrayList<>(); public static Object commonEnter( Executable origin, @@ -24,6 +24,8 @@ public static Object commonEnter( String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); if (isAcceptedTrace(stackTrace)) { + StackTraces.add(stackTrace); + PartialTrace partialTrace = TraceFactory.getPartialMethodTrace(origin, arguments, instance); // Need to fetch this asap to not be off on the measurements! @@ -46,26 +48,36 @@ public static void commonExit( // Need to fetch this asap to not be off on the measurements! long exitMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; + int loggerInstance = Logger.GetInstance(); + + if (entryTrace == null) { + Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); + + return; + } + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); - if (isAcceptedTrace(stackTrace)) { - String testName = getTestMethodName(stackTrace); - - if (testName != null && !testName.isEmpty()) { - int index; - for (index = 0; index < stackTrace.length; index++) { - if (stackTrace[index].equals(testName)) { - break; - } + // Remove existing stacktrace + StackTraces.remove(stackTrace); + + String testName = getTestMethodName(stackTrace); + + if (testName != null && !testName.isEmpty()) { + int index; + for (index = 0; index < stackTrace.length; index++) { + if (stackTrace[index].equals(testName)) { + break; } - stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); } - - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, stackTrace); - trace.setTimeStampExit(exitMarker); - TraceCollector.addMethodTrace(testName, trace); + stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); } + + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, stackTrace); + trace.setTimeStampExit(exitMarker); + TraceCollector.addMethodTrace(testName, trace); } private static String getTestMethodName(String[] stackTrace) { @@ -87,51 +99,38 @@ private static String getTestMethodName(String[] stackTrace) { } private static boolean isAcceptedTrace(String[] stackTrace) { - int instrumentedMethodStackTraceIndex = 0; - int loggerInstance = Logger.GetInstance(); - Logger.Log(loggerInstance, "++MethodAdvisor::Exit"); + Logger.Log(loggerInstance, "++CommonAdvisor::isAcceptedTrace"); Logger.Log(loggerInstance, " StackTrace:"); for (String methodName : stackTrace) { Logger.Log(loggerInstance, String.format(" %s", methodName)); } - // Start with the caller - for (int i = instrumentedMethodStackTraceIndex + 1; i < stackTrace.length; i++) { - String stackTraceMethodName = stackTrace[i]; - - if (stackTraceMethodName.startsWith("org.junit.") || - stackTraceMethodName.startsWith("sun.") || - stackTraceMethodName.startsWith("jdk.") || - stackTraceMethodName.startsWith("java.")) { + for (String[] previousStackTrace : StackTraces) { + // An existing stacktrace can only be smaller than us if they overlap + if (previousStackTrace.length >= stackTrace.length) { continue; } - // This is our client, and we didn't find a lib method, first, we're good to go. - if (Arrays.asList(ClientMethods).contains(stackTraceMethodName)) { - break; - } - - if (Arrays.stream(ClientTypes).map(t -> { - if (t.contains(".")) { - String[] nameElements = t.split("\\."); - return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); + boolean matchesExistingStackTrace = true; + for (int i = 0; i < previousStackTrace.length; i++) { + if (!previousStackTrace[i].equals(stackTrace[i])) { + matchesExistingStackTrace = false; + break; } - return t; - }).anyMatch(stackTraceMethodName::startsWith)) { - break; } - // We never found any trace of the client, something is up... - Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + if (matchesExistingStackTrace) { + Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); - return false; + return false; + } } Logger.Log(loggerInstance, " Accepted Trace"); - Logger.Log(loggerInstance, "--MethodAdvisor::Exit"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); return true; } } \ No newline at end of file From cd7c7a84c343c142ce3425b1ef57d559207ab86f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 25 Jun 2024 11:15:43 +0200 Subject: [PATCH 140/244] fix: conflicts with jacksons in clients/libs + filter --- Instrumentation/build.gradle | 14 +++++ .../visitors/CommonAdvisor.java | 62 ++++++++++++++++--- .../samples/sampleclient/SelfCaller.java | 9 +++ .../sampleclient/src/test/java/SelfTest.java | 9 +++ .../samples/samplelibrary/SelfCallTest.java | 11 ++++ 5 files changed, 96 insertions(+), 9 deletions(-) create mode 100644 Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/SelfCaller.java create mode 100644 Samples/Gradle/sampleclient/src/test/java/SelfTest.java create mode 100644 Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/SelfCallTest.java diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 0a4f445e..8e4f2dfd 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -45,6 +45,20 @@ shadowJar { archiveClassifier.set('') archiveVersion.set('') mergeServiceFiles() + + // Filtering shadow jar contents by file pattern. + exclude('LICENSE.txt') + exclude('META-INF/LICENSE') + exclude('META-INF/LICENSE.txt') + exclude('META-INF/NOTICE') + exclude('META-INF/NOTICE.txt') + + // Relocating dependencies. + relocate('com.fasterxml', 'gilesi.com.fasterxml') + relocate('com.thoughtworks', 'gilesi.com.thoughtworks') + relocate('net', 'gilesi.net') + relocate('io', 'gilesi.io') + //relocate('org', 'gilesi.org') // causes issues with xtream if done } distributions { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index abd46a36..bdd164a4 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -48,12 +48,7 @@ public static void commonExit( // Need to fetch this asap to not be off on the measurements! long exitMarker = System.nanoTime() - TraceFactory.ProcessEntryTimeStamp; - int loggerInstance = Logger.GetInstance(); - if (entryTrace == null) { - Logger.Log(loggerInstance, " Rejected Trace (Case 2)"); - Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); - return; } @@ -61,7 +56,27 @@ public static void commonExit( String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); // Remove existing stacktrace - StackTraces.remove(stackTrace); + for (int j = 0; j < StackTraces.size(); j++) { + String[] StackTrace = StackTraces.get(j); + if (StackTrace.length != stackTrace.length) { + continue; + } + + boolean match = true; + + for (int i = 0; i < StackTrace.length; i++) { + String methodName = StackTrace[i]; + if (!methodName.equals(stackTrace[i])) { + match = false; + break; + } + } + + if (match) { + StackTraces.remove(j); + break; + } + } String testName = getTestMethodName(stackTrace); @@ -98,16 +113,42 @@ private static String getTestMethodName(String[] stackTrace) { return UNKNOWN_TEST_METHOD_NAME; } + private static String[] getCutOffStackTrace(String[] stackTrace) { + String testName = getTestMethodName(stackTrace); + ArrayList cutOffStackTrace = new ArrayList<>(); + for (String stackTraceMethodName : stackTrace) { + if (stackTraceMethodName.startsWith("org.junit.") || + stackTraceMethodName.startsWith("sun.") || + stackTraceMethodName.startsWith("jdk.") || + stackTraceMethodName.startsWith("java.")) { + continue; + } + + cutOffStackTrace.add(stackTraceMethodName); + + if (stackTraceMethodName.equals(testName)) { + break; + } + } + + return cutOffStackTrace.stream().toArray(String[]::new); + } + private static boolean isAcceptedTrace(String[] stackTrace) { int loggerInstance = Logger.GetInstance(); + stackTrace = getCutOffStackTrace(stackTrace); + Logger.Log(loggerInstance, "++CommonAdvisor::isAcceptedTrace"); - Logger.Log(loggerInstance, " StackTrace:"); + + Logger.Log(loggerInstance, " Incoming StackTrace:"); for (String methodName : stackTrace) { Logger.Log(loggerInstance, String.format(" %s", methodName)); } for (String[] previousStackTrace : StackTraces) { + previousStackTrace = getCutOffStackTrace(previousStackTrace); + // An existing stacktrace can only be smaller than us if they overlap if (previousStackTrace.length >= stackTrace.length) { continue; @@ -115,14 +156,17 @@ private static boolean isAcceptedTrace(String[] stackTrace) { boolean matchesExistingStackTrace = true; for (int i = 0; i < previousStackTrace.length; i++) { - if (!previousStackTrace[i].equals(stackTrace[i])) { + String oldMethod = previousStackTrace[previousStackTrace.length - 1 - i]; + String newMethod = stackTrace[stackTrace.length - 1 -i]; + + if (!oldMethod.equals(newMethod)) { matchesExistingStackTrace = false; break; } } if (matchesExistingStackTrace) { - Logger.Log(loggerInstance, " Rejected Trace (Case 1)"); + Logger.Log(loggerInstance, " Rejected Trace"); Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); return false; diff --git a/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/SelfCaller.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/SelfCaller.java new file mode 100644 index 00000000..ffa1cecf --- /dev/null +++ b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/SelfCaller.java @@ -0,0 +1,9 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.SelfCallTest; + +public class SelfCaller { + public static void call() { + SelfCallTest.FirstAPI(); + } +} diff --git a/Samples/Gradle/sampleclient/src/test/java/SelfTest.java b/Samples/Gradle/sampleclient/src/test/java/SelfTest.java new file mode 100644 index 00000000..8bb017e5 --- /dev/null +++ b/Samples/Gradle/sampleclient/src/test/java/SelfTest.java @@ -0,0 +1,9 @@ +import com.github.gilesi.samples.sampleclient.SelfCaller; +import org.junit.jupiter.api.Test; + +public class SelfTest { + @Test + public void test() { + SelfCaller.call(); + } +} diff --git a/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/SelfCallTest.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/SelfCallTest.java new file mode 100644 index 00000000..2efae323 --- /dev/null +++ b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/SelfCallTest.java @@ -0,0 +1,11 @@ +package com.github.gilesi.samples.samplelibrary; + +public class SelfCallTest { + public static void FirstAPI() { + SecondAPI(); + } + + public static void SecondAPI() { + + } +} From c1fe4059e16dc2245da94824e3e47d9f6b08f72d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 26 Jun 2024 09:33:01 +0200 Subject: [PATCH 141/244] general fixes --- .../instrumentation/TraceCollector.java | 12 +- .../gilesi/instrumentation/XmlUtils.java | 14 +++ .../visitors/CommonAdvisor.java | 110 +++++++++--------- .../java/com/github/gilesi/maestro/Main.java | 4 +- .../github/gilesi/maestro/Orchestrator.java | 30 ++--- .../github/gilesi/maestro/ProcessUtils.java | 4 +- .../gilesi/maestro/compsuite/CompSuite.java | 65 ++++++----- .../maestro/compsuite/CompSuiteFixes.java | 7 +- .../maestro/runners/maven/Log4JLogger.java | 17 ++- .../github/gilesi/maestro/tools/ConfGen.java | 23 ++++ .../github/gilesi/maestro/tools/TestGen.java | 22 ++++ TestGenerator/build.gradle | 5 + .../instrumentation/models/PartialTrace.java | 12 +- .../gilesi/instrumentation/models/Trace.java | 22 ++-- .../com/github/gilesi/testgenerator/Main.java | 15 ++- 15 files changed, 228 insertions(+), 134 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/tools/ConfGen.java create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index c585ad47..00bf6d75 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -48,10 +48,10 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar System.out.println("Saving trace results in progress..."); int mainPadding = 1; - String tracesFileName = String.format("%s%sMethodTraces_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); + String tracesFileName = String.format("%s%sMethodTraces_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sMethodTraces_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); + tracesFileName = String.format("%s%sMethodTraces_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); } Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); @@ -61,7 +61,7 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar Collection results = TraceCollector.getMethodTraces(); try { - String xmlOutputString = XmlUtils.getToXml(results); + String xmlOutputString = XmlUtils.getToJson(results); FileWriter outputFile = new FileWriter(tracesFileName); outputFile.write(xmlOutputString); outputFile.close(); @@ -72,10 +72,10 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar for (TestTraceResults testTraceResults : results) { int padding = 1; - String traceFileName = String.format("%s%s%s_%d_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); + String traceFileName = String.format("%s%s%s_%d_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); while (Files.exists(Paths.get(traceFileName))) { - traceFileName = String.format("%s%s%s_%d_%d.xml", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); + traceFileName = String.format("%s%s%s_%d_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); } Path tracePath = Paths.get(traceFileName).toAbsolutePath(); @@ -83,7 +83,7 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar System.out.printf("Test Output location: %s%n", tracePath); try { - String xmlOutputString = XmlUtils.getToXml(testTraceResults.Traces); + String xmlOutputString = XmlUtils.getToJson(testTraceResults.Traces); FileWriter outputFile = new FileWriter(traceFileName); outputFile.write(xmlOutputString); outputFile.close(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java index 9be1906b..d99dace2 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java @@ -1,5 +1,8 @@ package com.github.gilesi.instrumentation; +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; @@ -19,4 +22,15 @@ public static String getToXml(Object obj) { XStream xStream = new XStream(domDriver); return xStream.toXML(obj); } + + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + public static String getToJson(Object obj) throws JsonProcessingException { + return objectMapper.writeValueAsString(obj); + } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index bdd164a4..b10d47d2 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -24,8 +24,6 @@ public static Object commonEnter( String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); if (isAcceptedTrace(stackTrace)) { - StackTraces.add(stackTrace); - PartialTrace partialTrace = TraceFactory.getPartialMethodTrace(origin, arguments, instance); // Need to fetch this asap to not be off on the measurements! @@ -53,44 +51,47 @@ public static void commonExit( } StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); - String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + String[] currentStackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); - // Remove existing stacktrace - for (int j = 0; j < StackTraces.size(); j++) { - String[] StackTrace = StackTraces.get(j); - if (StackTrace.length != stackTrace.length) { - continue; - } + synchronized (StackTraces) { + // Remove existing stacktrace + for (int StoredPreviousStackTraceIndex = 0; StoredPreviousStackTraceIndex < StackTraces.size(); StoredPreviousStackTraceIndex++) { + String[] StoredPreviousStackTrace = StackTraces.get(StoredPreviousStackTraceIndex); + + if (StoredPreviousStackTrace.length != currentStackTrace.length) { + continue; + } - boolean match = true; + boolean match = true; - for (int i = 0; i < StackTrace.length; i++) { - String methodName = StackTrace[i]; - if (!methodName.equals(stackTrace[i])) { - match = false; - break; + for (int i = 0; i < StoredPreviousStackTrace.length; i++) { + String methodName = StoredPreviousStackTrace[i]; + if (!methodName.equals(currentStackTrace[i])) { + match = false; + break; + } } - } - if (match) { - StackTraces.remove(j); - break; + if (match) { + StackTraces.remove(StoredPreviousStackTraceIndex); + break; + } } } - String testName = getTestMethodName(stackTrace); + String testName = getTestMethodName(currentStackTrace); if (testName != null && !testName.isEmpty()) { int index; - for (index = 0; index < stackTrace.length; index++) { - if (stackTrace[index].equals(testName)) { + for (index = 0; index < currentStackTrace.length; index++) { + if (currentStackTrace[index].equals(testName)) { break; } } - stackTrace = Arrays.stream(stackTrace).limit(index + 1).toArray(String[]::new); + currentStackTrace = Arrays.stream(currentStackTrace).limit(index + 1).toArray(String[]::new); } - Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, stackTrace); + Trace trace = TraceFactory.getMethodTrace(origin, arguments, returned, instance, thrown, entryTrace, currentStackTrace); trace.setTimeStampExit(exitMarker); TraceCollector.addMethodTrace(testName, trace); } @@ -135,46 +136,49 @@ private static String[] getCutOffStackTrace(String[] stackTrace) { } private static boolean isAcceptedTrace(String[] stackTrace) { - int loggerInstance = Logger.GetInstance(); + synchronized (StackTraces) { + int loggerInstance = Logger.GetInstance(); - stackTrace = getCutOffStackTrace(stackTrace); + stackTrace = getCutOffStackTrace(stackTrace); - Logger.Log(loggerInstance, "++CommonAdvisor::isAcceptedTrace"); + Logger.Log(loggerInstance, "++CommonAdvisor::isAcceptedTrace"); - Logger.Log(loggerInstance, " Incoming StackTrace:"); - for (String methodName : stackTrace) { - Logger.Log(loggerInstance, String.format(" %s", methodName)); - } + Logger.Log(loggerInstance, " Incoming StackTrace:"); + for (String methodName : stackTrace) { + Logger.Log(loggerInstance, String.format(" %s", methodName)); + } - for (String[] previousStackTrace : StackTraces) { - previousStackTrace = getCutOffStackTrace(previousStackTrace); + for (String[] previousStackTrace : StackTraces) { + previousStackTrace = getCutOffStackTrace(previousStackTrace); - // An existing stacktrace can only be smaller than us if they overlap - if (previousStackTrace.length >= stackTrace.length) { - continue; - } + // An existing stacktrace can only be smaller than us if they overlap + if (previousStackTrace.length >= stackTrace.length) { + continue; + } - boolean matchesExistingStackTrace = true; - for (int i = 0; i < previousStackTrace.length; i++) { - String oldMethod = previousStackTrace[previousStackTrace.length - 1 - i]; - String newMethod = stackTrace[stackTrace.length - 1 -i]; + boolean matchesExistingStackTrace = true; + for (int i = 0; i < previousStackTrace.length; i++) { + String oldMethod = previousStackTrace[previousStackTrace.length - 1 - i]; + String newMethod = stackTrace[stackTrace.length - 1 -i]; - if (!oldMethod.equals(newMethod)) { - matchesExistingStackTrace = false; - break; + if (!oldMethod.equals(newMethod)) { + matchesExistingStackTrace = false; + break; + } } - } - if (matchesExistingStackTrace) { - Logger.Log(loggerInstance, " Rejected Trace"); - Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); + if (matchesExistingStackTrace) { + Logger.Log(loggerInstance, " Rejected Trace"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); - return false; + return false; + } } - } - Logger.Log(loggerInstance, " Accepted Trace"); - Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); - return true; + Logger.Log(loggerInstance, " Accepted Trace"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); + StackTraces.add(stackTrace); + return true; + } } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index b7905745..984b35de 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -1,6 +1,7 @@ package com.github.gilesi.maestro; import com.github.gilesi.maestro.compsuite.CompSuite; +import com.github.gilesi.maestro.compsuite.CompSuiteFixes; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; import org.apache.logging.log4j.LogManager; @@ -34,9 +35,10 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP //Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject); String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; - String datasetOutput = "/home/gus/Datasets/compsuite2"; + String datasetOutput = "/home/gus/Datasets/compsuite3"; String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; + //CompSuiteFixes.copySourcesForDataset(dataset, datasetOutput); CompSuite.runOnDataset(GilesiRepositoryLocation, dataset, datasetOutput); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index a38badd5..698441bf 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -3,6 +3,8 @@ import com.github.gilesi.maestro.buildsystem.configuration.maven.PomHelper; import com.github.gilesi.maestro.runners.maven.Log4JLogger; import com.github.gilesi.maestro.runners.maven.ProjectRunner; +import com.github.gilesi.maestro.tools.ConfGen; +import com.github.gilesi.maestro.tools.TestGen; import org.apache.maven.shared.invoker.MavenInvocationException; import org.codehaus.plexus.util.xml.pull.XmlPullParserException; @@ -33,15 +35,7 @@ public static void handleProject(String clientLocation, String libraryLocation, // Run ConfGen on Library first // TODO: Check how meta projects get handled here exactly... - ProcessUtils.runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), - libraryConfig.toString(), - outputTestProject, - libraryLocation, - clientLocation - }, null); + ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), outputTestProject, libraryLocation); Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); @@ -123,8 +117,8 @@ public static void copyInstrumentationToolAndConfiguration(ArrayList all Files.deleteIfExists(agentDest); Files.deleteIfExists(workflowDest); - Files.copy(InstrumentationAgentEffectiveLocation, agentDest); - Files.copy(libraryConfig, workflowDest); + //Files.copy(InstrumentationAgentEffectiveLocation, agentDest); + //Files.copy(libraryConfig, workflowDest); } } @@ -196,7 +190,7 @@ public static void executeGradleProjectTests(ArrayList clientProjectGrad "test", "--warning-mode", "all" - }, new File(clientLocation)); + }, new File(clientLocation), Main.logger); } else { for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); @@ -209,7 +203,7 @@ public static void executeGradleProjectTests(ArrayList clientProjectGrad "test", "--warning-mode", "all" - }, new File(clientProjectLocationPath.toString())); + }, new File(clientProjectLocationPath.toString()), Main.logger); } } } @@ -217,15 +211,9 @@ public static void executeGradleProjectTests(ArrayList clientProjectGrad public static void tracesToCode(String GilesiRepositoryLocation, String outputTestProject, String outputCodeDirectory) throws IOException, InterruptedException { // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles(outputTestProject, "MethodTraces_.*\\.xml", false); + ArrayList traceFiles = FileUtils.enumerateFiles(outputTestProject, "MethodTraces_.*\\.json", false); for (String traceFile : traceFiles) { - ProcessUtils.runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), - traceFile, - outputCodeDirectory - }, null); + TestGen.runTestGen(GilesiRepositoryLocation, traceFile, outputCodeDirectory); } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java index 0d413f18..26f71819 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java @@ -6,7 +6,7 @@ import java.io.InputStreamReader; public class ProcessUtils { - public static void runExternalCommand(String[] command, File directory) throws IOException, InterruptedException { + public static void runExternalCommand(String[] command, File directory, org.apache.logging.log4j.Logger logger) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(command); if (directory != null) { pb.directory(directory); @@ -18,7 +18,7 @@ public static void runExternalCommand(String[] command, File directory) throws I String line; while ((line = reader.readLine()) != null) { - Main.logger.info(line); + logger.info(line); } p.waitFor(); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 73fe75eb..e11bd18e 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -4,10 +4,10 @@ import com.github.gilesi.maestro.Constants; import com.github.gilesi.maestro.FileUtils; import com.github.gilesi.maestro.Main; -import com.github.gilesi.maestro.ProcessUtils; import com.github.gilesi.maestro.runners.maven.Log4JLogger; import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; +import com.github.gilesi.maestro.tools.ConfGen; import org.apache.maven.shared.invoker.MavenInvocationException; import java.io.File; @@ -66,7 +66,7 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } Main.logger.info("Testing old project"); - TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger()); + TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger); actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger); @@ -79,32 +79,42 @@ public static void runOnDataset(String GilesiRepositoryLocation, String dataset, runOldOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { @Override public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException { - if (incompatibility.id.equals("i-75") || - incompatibility.id.equals("i-59") || - incompatibility.id.equals("i-92") || - incompatibility.id.equals("i-93") || - incompatibility.id.equals("i-99") || - incompatibility.id.equals("i-115") || - incompatibility.id.equals("i-122")) { + String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); + String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); + String clientLocation = oldDestinationProjectPath.toString(); + + // Assert + if (incompatibility.id.equals("i-1")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return null; } - if (incompatibility.id.equals("i-1")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT TRANSFORM FAILURE KNOWN: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + // Exception loop during testing + if (incompatibility.id.equals("i-6")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return null; } - String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); - String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); - String clientLocation = oldDestinationProjectPath.toString(); + // Assert + if (incompatibility.id.equals("i-19")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } - if (!Files.exists(Path.of(libraryLocation))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + // Hangs and never finishes + if (incompatibility.id.equals("i-41")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return null; } - if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED BEFORE: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + // Hangs and never finishes + if (incompatibility.id.equals("i-45")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } + + if (!Files.exists(Path.of(libraryLocation))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return null; } @@ -119,15 +129,7 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin // Run ConfGen on Library first // TODO: Check how meta projects get handled here exactly... - ProcessUtils.runExternalCommand(new String[]{ - "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), - "-jar", - "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), - libraryConfig.toString(), - outputTestProject, - libraryLocation, - clientLocation - }, null); + ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), outputTestProject, libraryLocation); Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); @@ -141,9 +143,7 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); - //orchestrateMavenProjects(clientProjectPomFiles); - - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; orchestrateGradleProjects(clientProjectGradleBuildFiles); @@ -158,6 +158,11 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina String dependencyName = incompatibility.lib; String dependencyVersion = incompatibility.old; + if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO LOAD OUR AGENT: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); String clientLocation = oldDestinationProjectPath.toString(); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java index 5c3fee3e..f8fdcc99 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java @@ -5,6 +5,7 @@ import org.apache.maven.shared.invoker.MavenInvocationException; import java.io.IOException; +import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -27,7 +28,7 @@ public static void copySourcesForDataset(String dataset, String datasetOutput) t continue; } - /*Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old"); + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old"); FileUtils.deleteDirectoryIfExists(oldDestinationProjectPath.toString()); Files.createDirectories(oldDestinationProjectPath); @@ -35,7 +36,7 @@ public static void copySourcesForDataset(String dataset, String datasetOutput) t //Files.copy(Path.of(cand), oldDestinationProjectPath); System.out.println("Extracting " + cand); extractJar(cand, oldDestinationProjectPath.toString()); - }*/ + } } } @@ -45,7 +46,7 @@ public static void extractJar(String jar, String destdir) throws java.io.IOExcep while (enu.hasMoreElements()) { java.util.jar.JarEntry je = enu.nextElement(); - System.out.println(je.getName()); + //System.out.println(je.getName()); java.io.File fl = new java.io.File(destdir, je.getName()); if (!fl.exists()) { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java index f2318b53..c3881aaa 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/Log4JLogger.java @@ -45,11 +45,17 @@ public class Log4JLogger implements InvokerLogger, InvocationOutputHandler { */ private int threshold; + private String prefix; + /** * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. */ public Log4JLogger() { - this(LogManager.getLogger(), INFO); + this(LogManager.getLogger(), INFO, ""); + } + + public Log4JLogger(String prefix) { + this(LogManager.getLogger(), INFO, prefix); } /** @@ -58,10 +64,11 @@ public Log4JLogger() { * @param out The print stream to write to, must not be null. * @param threshold The threshold for the logger. */ - public Log4JLogger(Logger out, int threshold) { + public Log4JLogger(Logger out, int threshold, String prefix) { if (out == null) { throw new NullPointerException("missing output stream"); } + this.prefix = prefix; this.out = out; setThreshold(threshold); } @@ -97,7 +104,11 @@ private void log(int level, String message, Throwable error) { } } - buffer.append("[Maven] "); + if (prefix != null && !prefix.isEmpty()) { + buffer.append("[%s-Maven] ".formatted(prefix)); + } else { + buffer.append("[Maven] "); + } if (message != null) { buffer.append(message); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/tools/ConfGen.java b/Maestro/src/main/java/com/github/gilesi/maestro/tools/ConfGen.java new file mode 100644 index 00000000..d9e5e9a3 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/tools/ConfGen.java @@ -0,0 +1,23 @@ +package com.github.gilesi.maestro.tools; + +import com.github.gilesi.maestro.Constants; +import com.github.gilesi.maestro.ProcessUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; + +public class ConfGen { + public static final Logger logger = LogManager.getLogger(); + + public static void runConfGen(String GilesiRepositoryLocation, String libraryConfig, String outputTestProject, String libraryLocation) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.CONF_GEN_LOCATION), + libraryConfig, + outputTestProject, + libraryLocation + }, null, logger); + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java b/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java new file mode 100644 index 00000000..f43526c0 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java @@ -0,0 +1,22 @@ +package com.github.gilesi.maestro.tools; + +import com.github.gilesi.maestro.Constants; +import com.github.gilesi.maestro.ProcessUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; + +public class TestGen { + public static final Logger logger = LogManager.getLogger(); + + public static void runTestGen(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), + "-jar", + "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), + traceFile, + outputCodeDirectory + }, null, logger); + } +} \ No newline at end of file diff --git a/TestGenerator/build.gradle b/TestGenerator/build.gradle index 9f3a9c5a..1d5a16fb 100644 --- a/TestGenerator/build.gradle +++ b/TestGenerator/build.gradle @@ -24,6 +24,11 @@ repositories { } dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.14.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.0' + implementation 'com.fasterxml.jackson:jackson-base:2.14.0' implementation 'org.apache.commons:commons-text:1.11.0' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index c9c5a707..c4304c77 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -1,5 +1,8 @@ package com.github.gilesi.instrumentation.models; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; public class PartialTrace { @@ -8,11 +11,12 @@ public class PartialTrace { private List preCallArguments; private long timeStampEntry; + @JsonCreator public PartialTrace( - String methodSignature, - TraceData instance, - List preCallArguments, - long timeStampEntry) { + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("timeStampEntry") long timeStampEntry) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index 4cc97861..f6d78710 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -1,5 +1,8 @@ package com.github.gilesi.instrumentation.models; +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + import java.util.List; public class Trace extends PartialTrace { @@ -9,16 +12,17 @@ public class Trace extends PartialTrace { private TraceData exceptionThrown; private String[] stackTrace; + @JsonCreator public Trace( - String methodSignature, - TraceData instance, - List preCallArguments, - List postCallArguments, - TraceData returnedValue, - long timeStampEntry, - long timeStampExit, - TraceData exceptionThrown, - String[] stackTrace) { + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("stackTrace") String[] stackTrace) { super(methodSignature, instance, preCallArguments, timeStampEntry); this.postCallArguments = postCallArguments; diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 4e0e1504..f0296a08 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -1,5 +1,7 @@ package com.github.gilesi.testgenerator; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; @@ -9,17 +11,26 @@ import com.thoughtworks.xstream.io.xml.DomDriver; import com.thoughtworks.xstream.security.AnyTypePermission; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; public class Main { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + private static TestTraceResults[] readTraces(String filePathStr) throws IOException { - XStream xstream = new XStream(new DomDriver()); + /*XStream xstream = new XStream(new DomDriver()); xstream.addPermission(AnyTypePermission.ANY); String xmlContent = Files.readString(Path.of(filePathStr)); - return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new); + return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new);*/ + return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); } public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { From 38ee58eb6e79cfc0384d71b4983e7b30b7e9b357 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 27 Jun 2024 12:21:59 +0200 Subject: [PATCH 142/244] General Update Sync --- .../github/gilesi/instrumentation/Agent.java | 57 +++++++++---------- .../instrumentation/ConfigurationReader.java | 23 ++++++++ .../github/gilesi/instrumentation/Logger.java | 10 +++- .../instrumentation/RunMilestoneService.java | 46 +++++++++++++++ .../instrumentation/TraceCollector.java | 17 +++--- Maestro/build.gradle | 2 +- .../github/gilesi/maestro/Orchestrator.java | 4 +- .../gilesi/maestro/compsuite/CompSuite.java | 23 +++++--- .../maestro/runners/maven/ProjectRunner.java | 20 ++++--- Samples/Gradle/sampleclient/build.gradle | 15 +---- Samples/Maven/sampleclient/pom.xml | 2 +- maracas-test.cmd | 10 ++-- maracas-test.sh | 10 ++-- run-test-workflow.cmd | 8 +-- run-test-workflow.sh | 10 ++-- 15 files changed, 164 insertions(+), 93 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java create mode 100644 Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index e6f28842..2d20b0fd 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -1,17 +1,13 @@ package com.github.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.confgen.models.Class; import com.github.gilesi.confgen.models.InstrumentationParameters; -import com.github.gilesi.instrumentation.visitors.CommonAdvisor; import com.github.gilesi.instrumentation.visitors.MethodInstrumentor; import net.bytebuddy.agent.ByteBuddyAgent; import java.io.File; import java.io.IOException; import java.lang.instrument.Instrumentation; -import java.nio.charset.StandardCharsets; import java.nio.file.Files; import java.nio.file.Paths; @@ -19,32 +15,12 @@ Our main agent class */ public class Agent { - private static final ObjectMapper objectMapper = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - - public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { - //String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - //return XmlUtils.getFromXml(xmlContent); - return objectMapper.readValue(file, InstrumentationParameters.class); - } - /* Our primary method to install the agent required to trace methods during execution We take in as parameter an XML file with the list of methods to instrument and their class */ private static void installAgent(String arg, Instrumentation inst) { - // First, install the ByteBuddy Agent required to redefine classes during execution - // Sometimes this can fail, so try to catch it - try { - ByteBuddyAgent.install(); - } catch (Throwable e) { - System.err.println("ERROR: Could not install byte buddy agent!"); - System.err.println(e.getMessage()); - e.printStackTrace(); + if (!RunMilestoneService.shouldRun()) { return; } @@ -58,7 +34,7 @@ private static void installAgent(String arg, Instrumentation inst) { InstrumentationParameters instrumentationParameters; try { - instrumentationParameters = parseInstrumentationparameters(configurationFile); + instrumentationParameters = ConfigurationReader.parseInstrumentationparameters(configurationFile); } catch (IOException ioException) { System.err.printf("ERROR: Could not parse instrumentation configuration file (%s)!%n", arg); System.err.println(ioException.getMessage()); @@ -66,9 +42,13 @@ private static void installAgent(String arg, Instrumentation inst) { return; } - if (!Files.isDirectory(Paths.get(instrumentationParameters.traceOutputLocation))) { + String traceOutputLocation = instrumentationParameters.traceOutputLocation; + + RunMilestoneService.writeMarker(traceOutputLocation); + + if (!Files.isDirectory(Paths.get(traceOutputLocation))) { try { - Files.createDirectory(Paths.get(instrumentationParameters.traceOutputLocation)); + Files.createDirectory(Paths.get(traceOutputLocation)); } catch (IOException ioException) { System.err.printf("ERROR: Could not create trace output directory (%s)!%n", arg); System.err.println(ioException.getMessage()); @@ -78,13 +58,28 @@ private static void installAgent(String arg, Instrumentation inst) { } // Add a shutdown hook to save all logs at exit - Runtime.getRuntime().addShutdownHook(new Thread(() -> Logger.SaveLogResults(instrumentationParameters))); + Runtime.getRuntime().addShutdownHook(new Thread(() -> Logger.SaveLogResults(traceOutputLocation))); + + setupInstrumentation(inst, traceOutputLocation, instrumentationParameters.InstrumentedAPIClasses); + } + + private static void setupInstrumentation(Instrumentation inst, String traceOutputLocation, Class[] InstrumentedAPIClasses) { + // First, install the ByteBuddy Agent required to redefine classes during execution + // Sometimes this can fail, so try to catch it + try { + ByteBuddyAgent.install(); + } catch (Throwable e) { + System.err.println("ERROR: Could not install byte buddy agent!"); + System.err.println(e.getMessage()); + e.printStackTrace(); + return; + } // Add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(instrumentationParameters))); + Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(traceOutputLocation))); // Instrument every class - for (Class instrumentationParameter : instrumentationParameters.InstrumentedAPIClasses) { + for (Class instrumentationParameter : InstrumentedAPIClasses) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java new file mode 100644 index 00000000..2646517a --- /dev/null +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java @@ -0,0 +1,23 @@ +package com.github.gilesi.instrumentation; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.confgen.models.InstrumentationParameters; + +import java.io.File; +import java.io.IOException; + +public class ConfigurationReader { + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { + ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + //String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); + //return XmlUtils.getFromXml(xmlContent); + return objectMapper.readValue(file, InstrumentationParameters.class); + } +} diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index e453488c..950e8b01 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -14,12 +14,12 @@ public class Logger { private static final Map> LOGGER = new HashMap<>(); private static int LOGGERINSTANCE = 0; - public static void SaveLogResults(InstrumentationParameters instrumentationParameters) { + public static void SaveLogResults(String traceOutputLocation) { int mainPadding = 1; - String logFileName = String.format("%s%sgilesi.instrumentation_%d.log", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); + String logFileName = String.format("%s%sgilesi.instrumentation_%d.log", traceOutputLocation, File.separatorChar, mainPadding); while (Files.exists(Paths.get(logFileName))) { - logFileName = String.format("%s%sgilesi.instrumentation_%d.log", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); + logFileName = String.format("%s%sgilesi.instrumentation_%d.log", traceOutputLocation, File.separatorChar, ++mainPadding); } ArrayList logLines = new ArrayList<>(); @@ -32,6 +32,10 @@ public static void SaveLogResults(InstrumentationParameters instrumentationParam } } + if (logLines.isEmpty()) { + return; + } + try { Files.write(new File(logFileName).toPath(), logLines); } catch (Throwable e) { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java new file mode 100644 index 00000000..4cbe12d2 --- /dev/null +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java @@ -0,0 +1,46 @@ +package com.github.gilesi.instrumentation; + +import java.io.File; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class RunMilestoneService { + public static void writeMarker(String traceOutputLocation) { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + + int mainPadding = 1; + String tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", traceOutputLocation, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", traceOutputLocation, File.separatorChar, ++mainPadding); + } + + try { + Files.write(new File(tracesFileName).toPath(), arguments); + } catch (Throwable e) { + System.err.println("ERROR while saving marker"); + e.printStackTrace(); + } + } + + public static boolean shouldRun() { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + + for (String argument : arguments) { + if (argument.startsWith("-Dmaven.home=")) { + return false; + } else if (argument.startsWith("-Dorg.gradle.appname=")) { + return false; + } else if (argument.startsWith("-Dnet.bytebuddy.agent.attacher.dump=")) { + return false; + } + } + + return true; + } +} diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index 00bf6d75..5f4df818 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -1,6 +1,5 @@ package com.github.gilesi.instrumentation; -import com.github.gilesi.confgen.models.InstrumentationParameters; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; @@ -44,22 +43,24 @@ public static Collection getMethodTraces() { /** * Generates the tracing results text file on disk */ - public static void SaveTraceResults(InstrumentationParameters instrumentationParameters) { + public static void SaveTraceResults(String traceOutputLocation) { + Collection results = TraceCollector.getMethodTraces(); + if (results.isEmpty()) { + return; + } System.out.println("Saving trace results in progress..."); int mainPadding = 1; - String tracesFileName = String.format("%s%sMethodTraces_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, mainPadding); + String tracesFileName = String.format("%s%sMethodTraces_%d.json", traceOutputLocation, File.separatorChar, mainPadding); while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sMethodTraces_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, ++mainPadding); + tracesFileName = String.format("%s%sMethodTraces_%d.json", traceOutputLocation, File.separatorChar, ++mainPadding); } Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); System.out.printf("Output location: %s%n", tracesPath); - Collection results = TraceCollector.getMethodTraces(); - try { String xmlOutputString = XmlUtils.getToJson(results); FileWriter outputFile = new FileWriter(tracesFileName); @@ -72,10 +73,10 @@ public static void SaveTraceResults(InstrumentationParameters instrumentationPar for (TestTraceResults testTraceResults : results) { int padding = 1; - String traceFileName = String.format("%s%s%s_%d_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); + String traceFileName = String.format("%s%s%s_%d_%d.json", traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); while (Files.exists(Paths.get(traceFileName))) { - traceFileName = String.format("%s%s%s_%d_%d.json", instrumentationParameters.traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); + traceFileName = String.format("%s%s%s_%d_%d.json", traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); } Path tracePath = Paths.get(traceFileName).toAbsolutePath(); diff --git a/Maestro/build.gradle b/Maestro/build.gradle index 3e8bb464..13f55ada 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -76,6 +76,6 @@ idea { run { jvmArgs = [ "-XX:InitialHeapSize=2G", - "-XX:MaxHeapSize=2G" + "-XX:MaxHeapSize=32G" ] } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index 698441bf..e0474b05 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -167,13 +167,13 @@ public static void executeMavenProjectTests(ArrayList clientProjectPomFi // This is the maven path if (!clientProjectPomFiles.isEmpty()) { if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s//".formatted(clientLocation), "").replace(clientLocation, "").equals("pom.xml"))) { - ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); } else { for (String clientPomFile : clientProjectPomFiles) { Path clientPomFilePath = Path.of(clientPomFile); Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); - ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger()); + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); } } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index e11bd18e..0aca3da4 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -60,14 +60,14 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } } - testCmd = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); - if (testCmd == null) { + String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + if (javaToolOptions == null) { continue; } Main.logger.info("Testing old project"); TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger); } @@ -83,6 +83,10 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); String clientLocation = oldDestinationProjectPath.toString(); + if (!incompatibility.id.equals("i-23")) { + return null; + } + // Assert if (incompatibility.id.equals("i-1")) { Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); @@ -101,6 +105,12 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin return null; } + // Assert v2 + if (incompatibility.id.equals("i-22")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return null; + } + // Hangs and never finishes if (incompatibility.id.equals("i-41")) { Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); @@ -143,12 +153,11 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); - String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); - testCmd += " -DargLine=\"" + clientSurefireArgLine + "\""; + String javaToolOptions = "";//= "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); orchestrateGradleProjects(clientProjectGradleBuildFiles); - return testCmd; + return javaToolOptions; } @Override @@ -158,7 +167,7 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina String dependencyName = incompatibility.lib; String dependencyVersion = incompatibility.old; - if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_1.log"))) { + if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_loaded.marker"))) { Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO LOAD OUR AGENT: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return; } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java index 1a1a5b68..d367e843 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/runners/maven/ProjectRunner.java @@ -16,7 +16,7 @@ public class ProjectRunner { - public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, Object logger) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, Object logger, String javaToolOptions) throws MavenInvocationException { String javaVersion = "8"; @@ -43,15 +43,15 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); - return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion, logger); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion, logger, javaToolOptions); } - public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger) throws MavenInvocationException { + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { File pomFile = new File(pomFilePath); InvokerLogger invokerLogger = null; @@ -101,6 +101,10 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, } } + if (javaToolOptions != null && !javaToolOptions.isEmpty()) { + request.addShellEnvironment("JAVA_TOOL_OPTIONS", javaToolOptions); + } + Main.logger.info("Building with pom=%s goals=%s properties=%s%n".formatted(pomFilePath, pomGoals, properties)); Invoker invoker = new DefaultInvoker(); @@ -112,16 +116,16 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, return result.getExitCode(); } - public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion, Object logger) throws MavenInvocationException { + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); ArrayList goals = new ArrayList<>(); goals.add(goal); if (javaVersion != null && !javaVersion.isBlank()) { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger, javaToolOptions) == 0; } else { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger, javaToolOptions) == 0; } } } \ No newline at end of file diff --git a/Samples/Gradle/sampleclient/build.gradle b/Samples/Gradle/sampleclient/build.gradle index 78a063e1..151e1ea1 100644 --- a/Samples/Gradle/sampleclient/build.gradle +++ b/Samples/Gradle/sampleclient/build.gradle @@ -15,18 +15,9 @@ dependencies { } testing { - suites { - test { - useJUnitJupiter() - - targets { - all { - testTask.configure { - systemProperty 'net.bytebuddy.experimental', 'true' - jvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml'] - } - } - } + suites { + test { + useJUnitJupiter() } } } \ No newline at end of file diff --git a/Samples/Maven/sampleclient/pom.xml b/Samples/Maven/sampleclient/pom.xml index f9e7e276..4dabb1e5 100644 --- a/Samples/Maven/sampleclient/pom.xml +++ b/Samples/Maven/sampleclient/pom.xml @@ -40,7 +40,7 @@ 1 false - -Dnet.bytebuddy.experimental=true -javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.xml + -Dnet.bytebuddy.experimental=true -javaagent:com.github.gilesi.instrumentation.jar=TestWorkflowConfiguration.json methods 1 40 diff --git a/maracas-test.cmd b/maracas-test.cmd index ef258560..ddbda5d4 100644 --- a/maracas-test.cmd +++ b/maracas-test.cmd @@ -13,7 +13,7 @@ echo Running ConfGen echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.xml" "%CD%\Traces.Output" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" +%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "%CD%\Traces.Output" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" echo. echo =========================================================== @@ -33,12 +33,12 @@ echo Running TestGenerator echo =========================================================== echo. -%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.xml" "%CD%\TestGenerator.Output" +%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.json" "%CD%\TestGenerator.Output" mkdir Results -move %CD%\MaracasConfiguration.xml Results\ +move %CD%\MaracasConfiguration.json Results\ move %CD%\Traces.Output\gilesi.instrumentation.log Results\ -move %CD%\Traces.Output\MethodTraces.xml Results\ -move %CD%\Traces.Output\*.xml Results\ +move %CD%\Traces.Output\MethodTraces.json Results\ +move %CD%\Traces.Output\*.json Results\ move %CD%\TestGenerator.Output Results\ diff --git a/maracas-test.sh b/maracas-test.sh index fb033178..8ce4a79c 100755 --- a/maracas-test.sh +++ b/maracas-test.sh @@ -10,7 +10,7 @@ echo Running ConfGen echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.xml" "$PWD/Traces.Output" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" +$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.json" "$PWD/Traces.Output" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" echo echo =========================================================== @@ -30,12 +30,12 @@ echo Running TestGenerator echo =========================================================== echo -$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.xml" "$PWD/TestGenerator.Output" +$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.json" "$PWD/TestGenerator.Output" mkdir Results -mv $PWD/MaracasConfiguration.xml Results/ +mv $PWD/MaracasConfiguration.json Results/ mv $PWD/Traces.Output/gilesi.instrumentation.log Results/ -mv $PWD/Traces.Output/MethodTraces.xml Results/ -mv $PWD/Traces.Output/*.xml Results/ +mv $PWD/Traces.Output/MethodTraces.json Results/ +mv $PWD/Traces.Output/*.json Results/ mv $PWD/TestGenerator.Output Results/ diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index e3a7a1cd..c5956f64 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -25,7 +25,7 @@ echo Running ConfGen echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\Results\TestWorkflowConfiguration.xml" "%CD%\Results" "%CD%\Samples\Gradle\samplelibrary" "%CD%\Samples\Gradle\sampleclient" +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\Results\TestWorkflowConfiguration.json" "%CD%\Results" "%CD%\Samples\Gradle\samplelibrary" "%CD%\Samples\Gradle\sampleclient" echo. @@ -35,14 +35,14 @@ echo =========================================================== echo. copy "%CD%\Instrumentation\build\libs\com.github.gilesi.instrumentation.jar" "%CD%\Samples\Gradle\sampleclient\" -copy "%CD%\Results\TestWorkflowConfiguration.xml" "%CD%\Samples\Gradle\sampleclient\" +copy "%CD%\Results\TestWorkflowConfiguration.json" "%CD%\Samples\Gradle\sampleclient\" cd Samples\Gradle call .\gradlew.bat sampleclient:test --warning-mode all cd ..\.. del "%CD%\Samples\Gradle\sampleclient\com.github.gilesi.instrumentation.jar" -del "%CD%\Samples\Gradle\sampleclient\TestWorkflowConfiguration.xml" +del "%CD%\Samples\Gradle\sampleclient\TestWorkflowConfiguration.json" echo. echo =========================================================== @@ -50,4 +50,4 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Results\MethodTraces.xml" "%CD%\Results\TestGenerator.Output" \ No newline at end of file +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Results\MethodTraces.json" "%CD%\Results\TestGenerator.Output" \ No newline at end of file diff --git a/run-test-workflow.sh b/run-test-workflow.sh index f312dafe..fc87f958 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -23,7 +23,7 @@ echo Running ConfGen echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/Results/TestWorkflowConfiguration.xml" "$PWD/Results" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/Results/TestWorkflowConfiguration.json" "$PWD/Results" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" echo @@ -32,15 +32,13 @@ echo $'Running Sample\'s Client Test Suite with Agent' echo =========================================================== echo -cp $PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar $PWD/Samples/Gradle/sampleclient/ -cp $PWD/Results/TestWorkflowConfiguration.xml $PWD/Samples/Gradle/sampleclient/ +export JAVA_TOOL_OPTIONS="-XX:+EnableDynamicAgentLoading -javaagent:$PWD/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar=$PWD/Results/TestWorkflowConfiguration.json" cd Samples/Gradle sh ./gradlew sampleclient:test --warning-mode all cd ../.. -rm $PWD/Samples/Gradle/sampleclient/com.github.gilesi.instrumentation.jar -rm $PWD/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml +export JAVA_TOOL_OPTIONS="" echo echo =========================================================== @@ -48,7 +46,7 @@ echo Running TestGenerator echo =========================================================== echo -for file in $PWD/Results/MethodTraces_*.xml; do +for file in $PWD/Results/MethodTraces_*.json; do [ -f "$file" ] || continue "$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$file" "$PWD/Results/TestGenerator.Output" done From 0818bbcbc1474bf2d1c04dcb7cb249de5f2e5a8e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 27 Jun 2024 15:02:13 +0200 Subject: [PATCH 143/244] General Update Sync --- .../github/gilesi/instrumentation/Agent.java | 59 ++++++++++--- .../instrumentation/ConfigurationReader.java | 13 +-- .../github/gilesi/instrumentation/Logger.java | 9 +- .../instrumentation/RunMilestoneService.java | 6 +- .../instrumentation/TraceCollector.java | 88 ++----------------- .../instrumentation/TraceDataFactory.java | 24 +---- .../gilesi/instrumentation/XmlUtils.java | 49 +++++++---- .../models/TestTraceResults.java | 4 +- .../visitors/CommonAdvisor.java | 2 +- .../visitors/MethodInstrumentor.java | 8 +- .../github/gilesi/maestro/Orchestrator.java | 10 +-- .../gilesi/maestro/compsuite/CompSuite.java | 40 +++++---- .../models/TestTraceResults.java | 2 +- .../com/github/gilesi/testgenerator/Main.java | 66 ++++++++++---- 14 files changed, 176 insertions(+), 204 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java index 2d20b0fd..8d18a126 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Agent.java @@ -9,12 +9,17 @@ import java.io.IOException; import java.lang.instrument.Instrumentation; import java.nio.file.Files; +import java.nio.file.Path; import java.nio.file.Paths; /* Our main agent class */ public class Agent { + public static Path generatedTracesFolderPath; + public static Path generatedLogsFolderPath; + public static Path generatedMarkersFolderPath; + /* Our primary method to install the agent required to trace methods during execution We take in as parameter an XML file with the list of methods to instrument and their class @@ -42,13 +47,26 @@ private static void installAgent(String arg, Instrumentation inst) { return; } - String traceOutputLocation = instrumentationParameters.traceOutputLocation; + String generatedFolderLocation = instrumentationParameters.traceOutputLocation; + Path generatedFolderPath = Paths.get(generatedFolderLocation); + generatedTracesFolderPath = generatedFolderPath.resolve("traces"); + generatedLogsFolderPath = generatedFolderPath.resolve("logs"); + generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); - RunMilestoneService.writeMarker(traceOutputLocation); + if (!Files.isDirectory(generatedFolderPath)) { + try { + Files.createDirectory(generatedFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } - if (!Files.isDirectory(Paths.get(traceOutputLocation))) { + if (!Files.isDirectory(generatedTracesFolderPath)) { try { - Files.createDirectory(Paths.get(traceOutputLocation)); + Files.createDirectory(generatedTracesFolderPath); } catch (IOException ioException) { System.err.printf("ERROR: Could not create trace output directory (%s)!%n", arg); System.err.println(ioException.getMessage()); @@ -57,13 +75,37 @@ private static void installAgent(String arg, Instrumentation inst) { } } + if (!Files.isDirectory(generatedLogsFolderPath)) { + try { + Files.createDirectory(generatedLogsFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create logs output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + if (!Files.isDirectory(generatedMarkersFolderPath)) { + try { + Files.createDirectory(generatedMarkersFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create markers output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + RunMilestoneService.writeMarker(); + // Add a shutdown hook to save all logs at exit - Runtime.getRuntime().addShutdownHook(new Thread(() -> Logger.SaveLogResults(traceOutputLocation))); + Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); - setupInstrumentation(inst, traceOutputLocation, instrumentationParameters.InstrumentedAPIClasses); + setupInstrumentation(inst, instrumentationParameters.InstrumentedAPIClasses); } - private static void setupInstrumentation(Instrumentation inst, String traceOutputLocation, Class[] InstrumentedAPIClasses) { + private static void setupInstrumentation(Instrumentation inst, Class[] InstrumentedAPIClasses) { // First, install the ByteBuddy Agent required to redefine classes during execution // Sometimes this can fail, so try to catch it try { @@ -75,9 +117,6 @@ private static void setupInstrumentation(Instrumentation inst, String traceOutpu return; } - // Add a shutdown hook to save all method execution traces at exit - Runtime.getRuntime().addShutdownHook(new Thread(() -> TraceCollector.SaveTraceResults(traceOutputLocation))); - // Instrument every class for (Class instrumentationParameter : InstrumentedAPIClasses) { MethodInstrumentor.instrumentClassForTracingAgent(inst, instrumentationParameter); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java index 2646517a..27f4c5ae 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java @@ -1,7 +1,5 @@ package com.github.gilesi.instrumentation; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.confgen.models.InstrumentationParameters; import java.io.File; @@ -9,15 +7,6 @@ public class ConfigurationReader { public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { - ObjectMapper objectMapper = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - - //String xmlContent = new String(Files.readAllBytes(file.toPath()), StandardCharsets.UTF_8); - //return XmlUtils.getFromXml(xmlContent); - return objectMapper.readValue(file, InstrumentationParameters.class); + return XmlUtils.objectMapper.readValue(file, InstrumentationParameters.class); } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java index 950e8b01..d442cd61 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/Logger.java @@ -1,12 +1,9 @@ package com.github.gilesi.instrumentation; -import com.github.gilesi.confgen.models.InstrumentationParameters; - import java.io.File; import java.nio.file.Files; import java.nio.file.Paths; import java.util.ArrayList; -import java.util.Dictionary; import java.util.HashMap; import java.util.Map; @@ -14,12 +11,12 @@ public class Logger { private static final Map> LOGGER = new HashMap<>(); private static int LOGGERINSTANCE = 0; - public static void SaveLogResults(String traceOutputLocation) { + public static void SaveLogResults() { int mainPadding = 1; - String logFileName = String.format("%s%sgilesi.instrumentation_%d.log", traceOutputLocation, File.separatorChar, mainPadding); + String logFileName = String.format("%s%sgilesi.instrumentation_%d.log", Agent.generatedLogsFolderPath, File.separatorChar, mainPadding); while (Files.exists(Paths.get(logFileName))) { - logFileName = String.format("%s%sgilesi.instrumentation_%d.log", traceOutputLocation, File.separatorChar, ++mainPadding); + logFileName = String.format("%s%sgilesi.instrumentation_%d.log", Agent.generatedLogsFolderPath, File.separatorChar, ++mainPadding); } ArrayList logLines = new ArrayList<>(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java index 4cbe12d2..4888f220 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/RunMilestoneService.java @@ -8,15 +8,15 @@ import java.util.List; public class RunMilestoneService { - public static void writeMarker(String traceOutputLocation) { + public static void writeMarker() { RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); List arguments = runtimeMxBean.getInputArguments(); int mainPadding = 1; - String tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", traceOutputLocation, File.separatorChar, mainPadding); + String tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", Agent.generatedMarkersFolderPath, File.separatorChar, mainPadding); while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", traceOutputLocation, File.separatorChar, ++mainPadding); + tracesFileName = String.format("%s%sgilesi.instrumentation_loaded_%d.marker", Agent.generatedMarkersFolderPath, File.separatorChar, ++mainPadding); } try { diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java index 5f4df818..f2a11ff7 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceCollector.java @@ -1,97 +1,21 @@ package com.github.gilesi.instrumentation; +import com.fasterxml.jackson.core.JsonProcessingException; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; -import java.io.File; -import java.io.FileWriter; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.ArrayList; -import java.util.Collection; - public class TraceCollector { - // Storage for traces collected so far - private static final ArrayList TRACES = new ArrayList<>(); - public static void addMethodTrace(String currentTestMethod, Trace trace) { - for (TestTraceResults testTraceResults : TRACES) { - if (testTraceResults.Test.equals(currentTestMethod)) { - testTraceResults.Traces.add(trace); - return; - } - } - TestTraceResults testTraceResults = new TestTraceResults(); testTraceResults.Test = currentTestMethod; - testTraceResults.Traces = new ArrayList<>(); - testTraceResults.Traces.add(trace); - TRACES.add(testTraceResults); - } - - /** - * This method returns the complete list of every cached complete method traces - * during program execution. - * - * @return The list of every cached trace during program execution - */ - public static Collection getMethodTraces() { - return TRACES; - } - - /** - * Generates the tracing results text file on disk - */ - public static void SaveTraceResults(String traceOutputLocation) { - Collection results = TraceCollector.getMethodTraces(); - if (results.isEmpty()) { - return; - } - System.out.println("Saving trace results in progress..."); - - int mainPadding = 1; - String tracesFileName = String.format("%s%sMethodTraces_%d.json", traceOutputLocation, File.separatorChar, mainPadding); - - while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sMethodTraces_%d.json", traceOutputLocation, File.separatorChar, ++mainPadding); - } - - Path tracesPath = Paths.get(tracesFileName).toAbsolutePath(); - - System.out.printf("Output location: %s%n", tracesPath); + testTraceResults.Trace = trace; try { - String xmlOutputString = XmlUtils.getToJson(results); - FileWriter outputFile = new FileWriter(tracesFileName); - outputFile.write(xmlOutputString); - outputFile.close(); - } catch (Throwable e) { - System.err.println("ERROR"); + String content = XmlUtils.getToJson(testTraceResults); + XmlUtils.saveToUniquePath(Agent.generatedTracesFolderPath.toString(), "MethodTrace", "json", content); + } catch (JsonProcessingException e) { + System.err.println("ERROR while saving trace"); e.printStackTrace(); } - - for (TestTraceResults testTraceResults : results) { - int padding = 1; - String traceFileName = String.format("%s%s%s_%d_%d.json", traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, padding); - - while (Files.exists(Paths.get(traceFileName))) { - traceFileName = String.format("%s%s%s_%d_%d.json", traceOutputLocation, File.separatorChar, testTraceResults.Test, mainPadding, ++padding); - } - - Path tracePath = Paths.get(traceFileName).toAbsolutePath(); - - System.out.printf("Test Output location: %s%n", tracePath); - - try { - String xmlOutputString = XmlUtils.getToJson(testTraceResults.Traces); - FileWriter outputFile = new FileWriter(traceFileName); - outputFile.write(xmlOutputString); - outputFile.close(); - } catch (Throwable e) { - System.err.println("ERROR"); - e.printStackTrace(); - } - } } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java index e9953cfc..00e691fe 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java @@ -1,17 +1,8 @@ package com.github.gilesi.instrumentation; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TraceData; public class TraceDataFactory { - /*private static final ObjectMapper objectMapper = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS);*/ - public static TraceData valueOf(Object object, int nullInstanceId) { TraceData traceData = new TraceData(); @@ -37,6 +28,9 @@ public static TraceData valueOf(Object object, int nullInstanceId) { int instanceId = System.identityHashCode(object); String objectClassName = object.getClass().getTypeName(); + traceData.fullyQualifiedTypeName = objectClassName; + traceData.instanceId = instanceId; + String serializedString = null; try { @@ -46,19 +40,7 @@ public static TraceData valueOf(Object object, int nullInstanceId) { Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); } - /*String serializedJsonString = null; - - try { - serializedJsonString = objectMapper.writeValueAsString(object); - } catch (Throwable e) { - int loggerInstance = Logger.GetInstance(); - Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); - }*/ - - traceData.fullyQualifiedTypeName = objectClassName; traceData.dataAsXml = serializedString; - //traceData.dataAsJson = serializedJsonString; - traceData.instanceId = instanceId; return traceData; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java index d99dace2..3b46a7f2 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java @@ -5,32 +5,47 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.thoughtworks.xstream.XStream; import com.thoughtworks.xstream.io.xml.DomDriver; -import com.thoughtworks.xstream.security.AnyTypePermission; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.nio.file.Paths; public class XmlUtils { - @SuppressWarnings("unchecked") - public static T getFromXml(String xmlString) { - DomDriver domDriver = new DomDriver(); - XStream xStream = new XStream(domDriver); - xStream.addPermission(AnyTypePermission.ANY); - Object obj = xStream.fromXML(xmlString); - return (T) obj; - } - - public static String getToXml(Object obj) { - DomDriver domDriver = new DomDriver(); - XStream xStream = new XStream(domDriver); - return xStream.toXML(obj); - } - - private static final ObjectMapper objectMapper = new ObjectMapper() + private static DomDriver domDriver = new DomDriver(); + private static XStream xStream = new XStream(domDriver); + private static Object syncObj = new Object(); + public static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + public static String getToXml(Object obj) { + return xStream.toXML(obj); + } + public static String getToJson(Object obj) throws JsonProcessingException { return objectMapper.writeValueAsString(obj); } + + public static void saveToUniquePath(String basePath, String baseName, String baseExtension, String content) { + synchronized (syncObj) { + int padding = 1; + String finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, padding, baseExtension); + + while (Files.exists(Paths.get(finalFileName))) { + finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, ++padding, baseExtension); + } + + try { + FileWriter outputFile = new FileWriter(finalFileName); + outputFile.write(content); + outputFile.close(); + } catch (Throwable e) { + System.err.println("ERROR"); + e.printStackTrace(); + } + } + } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java index e88b2162..e277a415 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -1,8 +1,6 @@ package com.github.gilesi.instrumentation.models; -import java.util.List; - public class TestTraceResults { - public List Traces; + public Trace Trace; public String Test; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java index b10d47d2..621468b2 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/CommonAdvisor.java @@ -13,7 +13,7 @@ public class CommonAdvisor { private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; private static final String JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL = "org.junit.runners.model.FrameworkMethod$1.runReflectiveCall"; - private static final String UNKNOWN_TEST_METHOD_NAME = "Unknown"; + private static final String UNKNOWN_TEST_METHOD_NAME = "UnknownTestPackage.UnknownTestClass.Unknown"; private static final ArrayList StackTraces = new ArrayList<>(); public static Object commonEnter( diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java index ccc7654e..d20b7dd6 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -31,13 +31,13 @@ private static ElementMatcher.Junction getMethodElementMatche for (Method methodParameter : classParameter.ClassMethods) { ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); ElementMatcher.Junction descriptorMatcher = null; - for (String descriptorParameter : methodParameter.MethodDescriptors) { + /*for (String descriptorParameter : methodParameter.MethodDescriptors) { if (descriptorMatcher == null) { descriptorMatcher = hasDescriptor(descriptorParameter); } else { descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); } - } + }*/ if (descriptorMatcher != null) { methodMatcher = methodMatcher.and(descriptorMatcher); @@ -54,7 +54,7 @@ private static ElementMatcher.Junction getMethodElementMatche public static void instrumentClassForTracingAgent(Instrumentation inst, Class classParameter) { ElementMatcher.Junction methodMatcher = getMethodElementMatcherFromClassParameter(classParameter); - ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); + //ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); new AgentBuilder.Default() .type(named(classParameter.ClassName)) @@ -68,7 +68,7 @@ public static void instrumentClassForTracingAgent(Instrumentation inst, Class cl Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(methodMatcher)) ) .visit( - Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor()).and(constructorMatcher)) + Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor())/*.and(constructorMatcher)*/) ) ) .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java index e0474b05..ce231c24 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Orchestrator.java @@ -56,7 +56,7 @@ public static void handleProject(String clientLocation, String libraryLocation, executeMavenProjectTests(clientProjectPomFiles, clientLocation); executeGradleProjectTests(clientProjectGradleBuildFiles, clientLocation); - tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + TestGen.runTestGen(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); lastMinuteCleanup(allProjectFiles); @@ -209,14 +209,6 @@ public static void executeGradleProjectTests(ArrayList clientProjectGrad } } - public static void tracesToCode(String GilesiRepositoryLocation, String outputTestProject, String outputCodeDirectory) throws IOException, InterruptedException { - // Turn traces into Java files - ArrayList traceFiles = FileUtils.enumerateFiles(outputTestProject, "MethodTraces_.*\\.json", false); - for (String traceFile : traceFiles) { - TestGen.runTestGen(GilesiRepositoryLocation, traceFile, outputCodeDirectory); - } - } - public static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { // Last minute cleanup for (String clientBuildFile : allProjectFiles) { diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 0aca3da4..ed08f9cc 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -8,6 +8,7 @@ import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; import com.github.gilesi.maestro.tools.ConfGen; +import com.github.gilesi.maestro.tools.TestGen; import org.apache.maven.shared.invoker.MavenInvocationException; import java.io.File; @@ -79,11 +80,14 @@ public static void runOnDataset(String GilesiRepositoryLocation, String dataset, runOldOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { @Override public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException { - String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); - String libraryLocation = datasetOutputPath.resolve(incompatibility.id).resolve("lib-old").toString(); + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + String libraryLocation = incompatibilityFolderPath.resolve("lib-old").toString(); + Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); String clientLocation = oldDestinationProjectPath.toString(); - if (!incompatibility.id.equals("i-23")) { + // Heap + if (incompatibility.id.equals("i-23")) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return null; } @@ -128,18 +132,14 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin return null; } - FileUtils.deleteDirectoryIfExists(outputTestProject); - Path outputTestProjectPath = Path.of(outputTestProject); + FileUtils.deleteDirectoryIfExists(generatedFolderPath.toString()); Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - // Create the results directory - Files.createDirectories(outputTestProjectPath); - // Run ConfGen on Library first // TODO: Check how meta projects get handled here exactly... - ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), outputTestProject, libraryLocation); + ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), generatedFolderPath.toString(), libraryLocation); Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); @@ -153,7 +153,7 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); - String javaToolOptions = "";//= "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); + String javaToolOptions = "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); orchestrateGradleProjects(clientProjectGradleBuildFiles); @@ -162,17 +162,23 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin @Override public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger) throws IOException, InterruptedException { - String outputTestProject = datasetOutputPath.resolve(incompatibility.id).resolve("generated").toString(); - Path outputTestProjectPath = Path.of(outputTestProject); + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); + Path generatedTracesFolderPath = generatedFolderPath.resolve("traces"); + Path generatedCodeFolderPath = generatedFolderPath.resolve("tests"); + Path generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); + + Files.createDirectories(generatedCodeFolderPath); + String dependencyName = incompatibility.lib; String dependencyVersion = incompatibility.old; - if (!Files.exists(Path.of(outputTestProject).resolve("gilesi.instrumentation_loaded.marker"))) { + if (!Files.exists(generatedMarkersFolderPath.resolve("gilesi.instrumentation_loaded_1.marker"))) { Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO LOAD OUR AGENT: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return; } - tracesToCode(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString()); + TestGen.runTestGen(GilesiRepositoryLocation, generatedTracesFolderPath.toString(), generatedCodeFolderPath.resolve("src").resolve("test").resolve("java").toString()); String clientLocation = oldDestinationProjectPath.toString(); @@ -212,9 +218,9 @@ testImplementation platform('org.junit:junit-bom:5.10.0') useJUnitPlatform() }""".formatted(dependencyName, dependencyVersion); - Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), generatedCodeFolderPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), generatedCodeFolderPath.resolve("gradlew.bat")); } }); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java index e419c06c..e277a415 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -1,6 +1,6 @@ package com.github.gilesi.instrumentation.models; public class TestTraceResults { - public Trace[] Traces; + public Trace Trace; public String Test; } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index f0296a08..ef3ba986 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -2,6 +2,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.instrumentation.models.PartialTrace; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; @@ -25,27 +26,50 @@ public class Main { .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - private static TestTraceResults[] readTraces(String filePathStr) throws IOException { - /*XStream xstream = new XStream(new DomDriver()); - xstream.addPermission(AnyTypePermission.ANY); - String xmlContent = Files.readString(Path.of(filePathStr)); - return ((ArrayList) xstream.fromXML(xmlContent)).toArray(TestTraceResults[]::new);*/ - return objectMapper.readValue(new File(filePathStr), TestTraceResults[].class); + private static Map> readTraces(String traceXmlFolder) throws IOException { + Map> traces = new HashMap(); + for (Path testTraceFile : Files.list(Path.of(traceXmlFolder)).sorted().toList()) { + try { + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), TestTraceResults.class); + if (traces.containsKey(testTraceResults.Test)) { + traces.get(testTraceResults.Test).add(testTraceResults.Trace); + } else { + traces.put(testTraceResults.Test, new ArrayList()); + traces.get(testTraceResults.Test).add(testTraceResults.Trace); + } + } catch (Exception e) { + System.out.println("ERROR while deserializing a trace!"); + e.printStackTrace(); + } + } + + return traces; } public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { - String traceXml = args[0]; + String traceXmlFolder = args[0]; String testPath = args[1]; - TestTraceResults[] testTraceResultsList = readTraces(traceXml); - + Map> testTraceResultsList = readTraces(traceXmlFolder); Map>> packageTraceResults = new HashMap<>(); - for (TestTraceResults testTraceResults : testTraceResultsList) { - String[] splitTestName = testTraceResults.Test.split("\\."); + for (String Test : testTraceResultsList.keySet()) { + String[] splitTestName = Test.split("\\."); + List Traces = testTraceResultsList.get(Test); + + Traces.sort(Comparator.comparingLong(PartialTrace::getTimeStampEntry)); + + for (var el : Traces) { + System.out.println(el.getTimeStampEntry()); + } + + String packageName = ""; + String className = ""; + if (splitTestName.length > 1) { + packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); + className = splitTestName[splitTestName.length - 2]; + } - String packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); - String className = splitTestName[splitTestName.length - 2]; String testName = splitTestName[splitTestName.length - 1]; if (!packageTraceResults.containsKey(packageName)) { @@ -57,7 +81,7 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine } if (!packageTraceResults.get(packageName).get(className).containsKey(testName)) { - packageTraceResults.get(packageName).get(className).put(testName, testTraceResults.Traces); + packageTraceResults.get(packageName).get(className).put(testName, Traces.toArray(Trace[]::new)); } } @@ -121,11 +145,17 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine for (int i = 0; i < methodTraces.length; i++) { Trace trace = methodTraces[i]; - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); - stringBuilder.append("%s\n".formatted(traceCode)); - if (i != methodTraces.length - 1) { - stringBuilder.append("\n"); + try { + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); + stringBuilder.append("%s\n".formatted(traceCode)); + + if (i != methodTraces.length - 1) { + stringBuilder.append("\n"); + } + } catch (Exception e) { + System.out.println("Unable to convert trace to code!"); + e.printStackTrace(); } } From f2e4785b1057d6ccca3058b3658f0a151d027a28 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 1 Jul 2024 16:09:01 +0200 Subject: [PATCH 144/244] fixes --- .../gilesi/maestro/compsuite/CompSuite.java | 10 ++++++ .../gilesi/samples/sampleclient/C3.java | 10 ++++++ .../sampleclient/src/test/java/CTest.java | 12 +++++-- .../gilesi/samples/samplelibrary/A.java | 16 +++++++++ .../samplelibrary/src/test/java/CTest.java | 35 +++++++++++++++++++ .../testgenerator/SerializationUtils.java | 27 +++++++++++--- .../testgenerator/TestMethodGenerator.java | 26 ++++++++------ run-test-workflow.sh | 7 ++-- 8 files changed, 121 insertions(+), 22 deletions(-) create mode 100644 Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C3.java create mode 100644 Samples/Gradle/samplelibrary/src/test/java/CTest.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index ed08f9cc..d286f7f9 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -216,11 +216,21 @@ testImplementation platform('org.junit:junit-bom:5.10.0') test { useJUnitPlatform() + jvmArgs = ["--add-opens=java.base/java.util=ALL-UNNAMED"] }""".formatted(dependencyName, dependencyVersion); Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); + Files.deleteIfExists(generatedCodeFolderPath.resolve("gradlew")); Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), generatedCodeFolderPath.resolve("gradlew")); + + Files.deleteIfExists(generatedCodeFolderPath.resolve("gradlew.bat")); Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), generatedCodeFolderPath.resolve("gradlew.bat")); + + FileUtils.deleteDirectoryIfExists(generatedCodeFolderPath.resolve("gradle").toString()); + Files.createDirectories(generatedCodeFolderPath.resolve("gradle").resolve("wrapper")); + + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties")); } }); } diff --git a/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C3.java b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C3.java new file mode 100644 index 00000000..5f344168 --- /dev/null +++ b/Samples/Gradle/sampleclient/src/main/java/com/github/gilesi/samples/sampleclient/C3.java @@ -0,0 +1,10 @@ +package com.github.gilesi.samples.sampleclient; + +import com.github.gilesi.samples.samplelibrary.A; + +public class C3 { + public static int Do(int i) { + A.A1 a = new A.A1(5); + return a.foo(1); + } +} diff --git a/Samples/Gradle/sampleclient/src/test/java/CTest.java b/Samples/Gradle/sampleclient/src/test/java/CTest.java index ee219cca..4563a098 100644 --- a/Samples/Gradle/sampleclient/src/test/java/CTest.java +++ b/Samples/Gradle/sampleclient/src/test/java/CTest.java @@ -1,4 +1,5 @@ import com.github.gilesi.samples.sampleclient.C1; +import com.github.gilesi.samples.sampleclient.C3; import com.github.gilesi.samples.samplelibrary.A2; import org.junit.jupiter.api.Test; @@ -9,7 +10,7 @@ public class CTest { public void Test() { C1 c1 = new C1(); int s = C1.Do(3); - assertEquals(s, 21); + assertEquals(21, s); } @Test @@ -17,6 +18,13 @@ public void ClientATest() { com.github.gilesi.samples.samplelibrary.A2 a = new A2(5); a = a.getOurselves(); int r = a.foo(1); - assertEquals(r, 11); + assertEquals(11, r); + } + + @Test + public void Test3() { + C3 c3 = new C3(); + int s = C3.Do(3); + assertEquals(7, s); } } diff --git a/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java index b9751faa..ab5da5d6 100644 --- a/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java +++ b/Samples/Gradle/samplelibrary/src/main/java/com/github/gilesi/samples/samplelibrary/A.java @@ -19,4 +19,20 @@ public void CallBack(IDoSomething doSomething) { doSomething.Do(); foo(2); } + + public static class A1 { + private final int j; + + public A1(int j) { + this.j = j; + } + + public int foo(int i) { + if (j == 42) { + return 69; + } + + return j + (i * 2); + } + } } diff --git a/Samples/Gradle/samplelibrary/src/test/java/CTest.java b/Samples/Gradle/samplelibrary/src/test/java/CTest.java new file mode 100644 index 00000000..c070a9b8 --- /dev/null +++ b/Samples/Gradle/samplelibrary/src/test/java/CTest.java @@ -0,0 +1,35 @@ +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import com.thoughtworks.xstream.security.AnyTypePermission; +import com.thoughtworks.xstream.XStreamException; +import org.junit.jupiter.api.Test; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertArrayEquals; + +public class CTest { + @Test + public void Test3() throws XStreamException { + java.lang.Integer var2 = 5; + com.github.gilesi.samples.samplelibrary.A.A1 var1 = new com.github.gilesi.samples.samplelibrary.A.A1(var2); + + java.lang.Integer var4 = 1; + java.lang.Integer var3 = var1.foo(var4); + assertEquals("7", getToXml(var3)); + } + + public static String getToXml(Object obj) { + DomDriver domDriver = new DomDriver(); + XStream xStream = new XStream(domDriver); + return xStream.toXML(obj); + } + + @SuppressWarnings("unchecked") + public static T getFromXml(String xmlString) { + DomDriver domDriver = new DomDriver(); + XStream xStream = new XStream(domDriver); + xStream.addPermission(AnyTypePermission.ANY); + Object obj = xStream.fromXML(xmlString); + return (T) obj; + } +} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 8b212e52..4b05e836 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -4,6 +4,9 @@ import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import org.apache.commons.text.StringEscapeUtils; +import java.util.ArrayList; +import java.util.List; + public class SerializationUtils { private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { return switch (name.charAt(0)) { @@ -36,12 +39,12 @@ public static String getCleanedType(String FQN) { currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || (currentCharacter == 'L' && FQN.endsWith(";"))) { try { - return JvmTypeToLangType(FQN); + return JvmTypeToLangType(FQN).replace("$", "."); } catch (UnsupportedJavaPrimitiveTypeException ignored) { } } - return FQN; + return FQN.replace("$", "."); } public static String serializableDataToJava(TraceData serializableData) { @@ -58,9 +61,23 @@ public static String serializableDataToJava(TraceData serializableData) { !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - // Casting is not needed if we only use this with variable assignments that are strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); - valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + if (serializableData.dataAsXml.length() > Math.pow(2, 16)) { + List sectionList = new ArrayList<>(); + + for (int i = 0; i < serializableData.dataAsXml.length(); i += (int) Math.pow(2, 16)) { + String sectionOfDataAsXml = serializableData.dataAsXml.substring(i, i + (int) Math.pow(2, 16)); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + String finalEscapedValue = String.join("+", sectionList.toArray(String[]::new)); + + valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); + } else { + // Casting is not needed if we only use this with variable assignments that are strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + } } else { valueToBeEqualTo = valueToBeEqualTo.split("[><]")[2]; diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index ca3f3fb6..e456731d 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -19,7 +19,7 @@ private static String serializableDataToCode(TraceData arg, VariableStackHandler return arg.dataAsXml; } String dataLine = SerializationUtils.serializableDataToJava(arg); - if (failOnLambdas && arg.fullyQualifiedTypeName.contains("$$Lambda/")) { + if (failOnLambdas && arg.fullyQualifiedTypeName.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } return dataLine; @@ -37,12 +37,15 @@ private static String getDataVariableDeclaration(TraceData serializableData, Var return variableStackHandler.getInstanceVariableName(serializableData.instanceId); } else { String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); - if (returnType.contains("$$Lambda/")) { + if (returnType.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - return "%s %s".formatted(returnType, instanceVariableName); + if (serializableData.dataAsXml.equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + } + return "%s %s".formatted("var", instanceVariableName); } } @@ -52,18 +55,21 @@ private static String getDataVariableDeclaration2(TraceData serializableData, Va } else { String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - return "%s %s".formatted(returnType, instanceVariableName); + if (serializableData.dataAsXml.equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + } + return "%s %s".formatted("var", instanceVariableName); } } private static String traceToMethodCall(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, InstanceAlreadyDefinedException { String methodName = methodTrace.getMethodSignature().split("\\(")[0]; - methodName = methodName.split(" ")[methodName.split(" ").length - 1]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); TraceData traceData = methodTrace.getInstance(); - boolean isConstructor = traceData != null && traceData.fullyQualifiedTypeName.equals(methodName); - boolean isInstanceCall = traceData != null && !traceData.fullyQualifiedTypeName.equals(methodName); + boolean isConstructor = traceData != null && traceData.fullyQualifiedTypeName.replace("$", ".").equals(methodName); + boolean isInstanceCall = traceData != null && !traceData.fullyQualifiedTypeName.replace("$", ".").equals(methodName); String methodCall = methodName; @@ -176,7 +182,7 @@ private static String getAssertionCodeLine(TraceData traceData, VariableStackHan return "assertEquals(null, %s);".formatted(instanceVarName); } - if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("$$Lambda/")) { + if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -230,8 +236,8 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, SerializationException { String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; - cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1]; - boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().fullyQualifiedTypeName.equals(cleanedMethodName); + cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1].replace("$", "."); + boolean isConstructor = methodTrace.getInstance() != null && methodTrace.getInstance().fullyQualifiedTypeName.replace("$", ".").equals(cleanedMethodName); TraceData traceData = methodTrace.getReturnedValue(); diff --git a/run-test-workflow.sh b/run-test-workflow.sh index fc87f958..c09b910e 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -23,7 +23,7 @@ echo Running ConfGen echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/Results/TestWorkflowConfiguration.json" "$PWD/Results" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" +"$JAVA_HOME/bin/java" -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/Results/TestWorkflowConfiguration.json" "$PWD/Results/generated" "$PWD/Samples/Gradle/samplelibrary" "$PWD/Samples/Gradle/sampleclient" echo @@ -46,7 +46,4 @@ echo Running TestGenerator echo =========================================================== echo -for file in $PWD/Results/MethodTraces_*.json; do - [ -f "$file" ] || continue - "$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$file" "$PWD/Results/TestGenerator.Output" -done +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Results/generated/traces" "$PWD/Results/generated/tests/src/test/java" \ No newline at end of file From e36295588238c80a4e2ea07184319dc09d49e594 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 2 Jul 2024 13:31:50 +0200 Subject: [PATCH 145/244] fixes --- .../com/github/gilesi/maestro/RunResult.java | 14 ++ .../gilesi/maestro/compsuite/CompSuite.java | 171 ++++++++++++------ .../maestro/compsuite/CompSuiteRunnable.java | 3 +- .../testing/{surefire => }/ReportItem.java | 3 +- .../testing/{surefire => }/XmlParser.java | 4 +- .../maestro/testing/gradle/GradleHarness.java | 49 +++++ .../testing/{surefire => models}/Error.java | 2 +- .../{surefire => models}/Properties.java | 2 +- .../{surefire => models}/Property.java | 2 +- .../{surefire => models}/Testcase.java | 4 +- .../{surefire => models}/Testsuite.java | 2 +- .../{surefire => models}/Testsuites.java | 2 +- .../testing/surefire/SurefireHarness.java | 4 + .../com/github/gilesi/testgenerator/Main.java | 29 ++- .../testgenerator/SerializationUtils.java | 29 ++- .../testgenerator/TestMethodGenerator.java | 4 +- 16 files changed, 243 insertions(+), 81 deletions(-) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => }/ReportItem.java (94%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => }/XmlParser.java (85%) create mode 100644 Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Error.java (90%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Properties.java (80%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Property.java (86%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Testcase.java (82%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Testsuite.java (97%) rename Maestro/src/main/java/com/github/gilesi/maestro/testing/{surefire => models}/Testsuites.java (81%) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java b/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java new file mode 100644 index 00000000..02558c5e --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java @@ -0,0 +1,14 @@ +package com.github.gilesi.maestro; + +public class RunResult { + public String ProjectId = ""; + public boolean ProjectIsMissingLibrarySourceCode = false; + public boolean ProjectCannotBeReproduced = false; // TODO + public boolean ProjectCannotBeInstrumented = false; + public boolean ProjectFailedToLoadAgent = false; + public boolean ProjectIsMissingTraceFiles = false; + public boolean ProjectIsMissingSpecificTraces = false; + public boolean ProjectFailedToGenerateAnyTraceTestSrc = false; + public boolean ProjectFailedToCompileGeneratedTests = false; // TODO + public boolean ProjectFailedToExecuteGeneratedTests = false; // TODO +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index d286f7f9..7b3f54ab 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -4,8 +4,8 @@ import com.github.gilesi.maestro.Constants; import com.github.gilesi.maestro.FileUtils; import com.github.gilesi.maestro.Main; +import com.github.gilesi.maestro.RunResult; import com.github.gilesi.maestro.runners.maven.Log4JLogger; -import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; import com.github.gilesi.maestro.tools.ConfGen; import com.github.gilesi.maestro.tools.TestGen; @@ -16,6 +16,7 @@ import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; +import java.util.List; import static com.github.gilesi.maestro.Orchestrator.*; @@ -44,33 +45,108 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui Path datasetOutputPath = Path.of(datasetOutput); + List runResults = new ArrayList<>(); + for (CompSuiteIncompatibility incompatibility : incompatibilities) { printIncompatibility(incompatibility); + RunResult runResult = new RunResult(); + runResult.ProjectId = incompatibility.id; + Path oldDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("old"); if (!incompatibility.submodule.equals("N/A")) { oldDestinationProjectPath = oldDestinationProjectPath.resolve(incompatibility.submodule); } - String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); - if (!incompatibility.test_cmd.equals("N/A")) { - testCmd = incompatibility.test_cmd; - if (testCmd.startsWith("mvn ")) { - testCmd = testCmd.substring(4); - } + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + String libraryLocation = incompatibilityFolderPath.resolve("lib-old").toString(); + if (!Files.exists(Path.of(libraryLocation))) { + runResult.ProjectIsMissingLibrarySourceCode = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Heap + if (incompatibility.id.equals("i-23")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert + if (incompatibility.id.equals("i-1")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Exception loop during testing + if (incompatibility.id.equals("i-6")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; } - String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); - if (javaToolOptions == null) { + // Assert + if (incompatibility.id.equals("i-19")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); continue; } - Main.logger.info("Testing old project"); + // Assert v2 + if (incompatibility.id.equals("i-22")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Hangs and never finishes + if (incompatibility.id.equals("i-41")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + } + + // Hangs and never finishes + if (incompatibility.id.equals("i-45")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + //String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + //if (!incompatibility.test_cmd.equals("N/A")) { + // testCmd = incompatibility.test_cmd; + // if (testCmd.startsWith("mvn ")) { + // testCmd = testCmd.substring(4); + // } + //} + + //String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + //if (javaToolOptions == null) { + // continue; + //} + + //Main.logger.info("Testing old project"); TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + //ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + + actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger, runResult); + runResults.add(runResult); + } - actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger); + System.out.println("ProjectId,ProjectIsMissingLibrarySourceCode,ProjectCannotBeReproduced,ProjectCannotBeInstrumented,ProjectFailedToLoadAgent,ProjectIsMissingTraceFiles,ProjectIsMissingSpecificTraces,ProjectFailedToGenerateAnyTraceTestSrc,ProjectFailedToCompileGeneratedTests,ProjectFailedToExecuteGeneratedTests"); + for (RunResult runResult : runResults) { + Main.logger.info("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s".formatted(runResult.ProjectId, runResult.ProjectIsMissingLibrarySourceCode, runResult.ProjectCannotBeReproduced, runResult.ProjectCannotBeInstrumented, runResult.ProjectFailedToLoadAgent, runResult.ProjectIsMissingTraceFiles, runResult.ProjectIsMissingSpecificTraces, runResult.ProjectFailedToGenerateAnyTraceTestSrc, runResult.ProjectFailedToCompileGeneratedTests, runResult.ProjectFailedToExecuteGeneratedTests)); } } @@ -85,53 +161,6 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); String clientLocation = oldDestinationProjectPath.toString(); - // Heap - if (incompatibility.id.equals("i-23")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Assert - if (incompatibility.id.equals("i-1")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Exception loop during testing - if (incompatibility.id.equals("i-6")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Assert - if (incompatibility.id.equals("i-19")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Assert v2 - if (incompatibility.id.equals("i-22")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Hangs and never finishes - if (incompatibility.id.equals("i-41")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - // Hangs and never finishes - if (incompatibility.id.equals("i-45")) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - - if (!Files.exists(Path.of(libraryLocation))) { - Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - return null; - } - FileUtils.deleteDirectoryIfExists(generatedFolderPath.toString()); Path libraryLocationPath = Path.of(libraryLocation); @@ -161,25 +190,47 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin } @Override - public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger) throws IOException, InterruptedException { + public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException { Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); Path generatedTracesFolderPath = generatedFolderPath.resolve("traces"); Path generatedCodeFolderPath = generatedFolderPath.resolve("tests"); Path generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); + FileUtils.deleteDirectoryIfExists(generatedCodeFolderPath.toString()); Files.createDirectories(generatedCodeFolderPath); String dependencyName = incompatibility.lib; String dependencyVersion = incompatibility.old; if (!Files.exists(generatedMarkersFolderPath.resolve("gilesi.instrumentation_loaded_1.marker"))) { + runResult.ProjectFailedToLoadAgent = true; Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO LOAD OUR AGENT: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return; } + boolean generatedTestTraces = !FileUtils.enumerateFiles(generatedTracesFolderPath.toString(), ".*\\.json", true).isEmpty(); + if (!generatedTestTraces) { + runResult.ProjectIsMissingTraceFiles = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO GENERATE TEST TRACES: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + TestGen.runTestGen(GilesiRepositoryLocation, generatedTracesFolderPath.toString(), generatedCodeFolderPath.resolve("src").resolve("test").resolve("java").toString()); + boolean hadGenerationFailures = !FileUtils.enumerateFiles(generatedCodeFolderPath.toString(), ".*\\.marker", true).isEmpty(); + if (!hadGenerationFailures) { + runResult.ProjectIsMissingSpecificTraces = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS MISSING SPECIFIC TRACE FILES: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + } + + boolean generatedTestSrc = !FileUtils.enumerateFiles(generatedCodeFolderPath.toString(), ".*\\.java", true).isEmpty(); + if (!generatedTestSrc) { + runResult.ProjectFailedToGenerateAnyTraceTestSrc = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO GENERATE TEST SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + String clientLocation = oldDestinationProjectPath.toString(); // Modify Client Build System to use the instrumentation agent diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java index b54a87d2..51f96ee8 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java @@ -1,5 +1,6 @@ package com.github.gilesi.maestro.compsuite; +import com.github.gilesi.maestro.RunResult; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; import java.io.IOException; @@ -7,5 +8,5 @@ public interface CompSuiteRunnable { String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException; - void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger) throws IOException, InterruptedException; + void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException; } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/ReportItem.java similarity index 94% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/ReportItem.java index 226d1e93..ecf527ae 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/ReportItem.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/ReportItem.java @@ -1,6 +1,7 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing; import com.github.gilesi.maestro.Constants; +import com.github.gilesi.maestro.testing.models.Testcase; public class ReportItem { public String Name; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/XmlParser.java similarity index 85% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/XmlParser.java index 19764689..f65889df 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/XmlParser.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/XmlParser.java @@ -1,7 +1,9 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.github.gilesi.maestro.testing.models.Testsuite; +import com.github.gilesi.maestro.testing.models.Testsuites; import java.io.File; import java.io.IOException; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java new file mode 100644 index 00000000..c85173d1 --- /dev/null +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java @@ -0,0 +1,49 @@ +package com.github.gilesi.maestro.testing.gradle; + +import com.github.gilesi.maestro.FileUtils; +import com.github.gilesi.maestro.Main; +import com.github.gilesi.maestro.testing.ReportItem; +import com.github.gilesi.maestro.testing.XmlParser; +import com.github.gilesi.maestro.testing.models.Testcase; +import com.github.gilesi.maestro.testing.models.Testsuite; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class GradleHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%stest-results%stest".formatted(targetLocation, File.separator, File.separator); + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, String buildGradleFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path buildGradleFilePath = Path.of(buildGradleFileLocation); + String targetLocation = "%s%sbuild".formatted(buildGradleFilePath.getParent().toAbsolutePath(), File.separator); + + if (Files.isDirectory(Path.of(targetLocation))) { + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + Main.logger.info(e); + } + } + + return reportItems; + } +} diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Error.java similarity index 90% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Error.java index 07daea4b..61196123 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Error.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Error.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Properties.java similarity index 80% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Properties.java index 6ad465bc..cb262086 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Properties.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Properties.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; public class Properties { private Property[] property; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Property.java similarity index 86% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Property.java index 170d6864..71425334 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Property.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Property.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; public class Property { private String name; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testcase.java similarity index 82% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testcase.java index 9b0f3a89..9894c929 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testcase.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testcase.java @@ -1,10 +1,10 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; public class Testcase { @JacksonXmlElementWrapper(localName = "error") - public Error Error; + public com.github.gilesi.maestro.testing.models.Error Error; @JacksonXmlElementWrapper(localName = "failure") public Error Failure; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuite.java similarity index 97% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuite.java index 691e2ccf..4e820cec 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuite.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; public class Testsuite { private Properties properties; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuites.java similarity index 81% rename from Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java rename to Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuites.java index 2cd38e61..b614caa9 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/Testsuites.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/models/Testsuites.java @@ -1,4 +1,4 @@ -package com.github.gilesi.maestro.testing.surefire; +package com.github.gilesi.maestro.testing.models; public class Testsuites { private Testsuite[] testsuites; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java index 98dac4ba..b2ebc523 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/surefire/SurefireHarness.java @@ -2,6 +2,10 @@ import com.github.gilesi.maestro.FileUtils; import com.github.gilesi.maestro.Main; +import com.github.gilesi.maestro.testing.ReportItem; +import com.github.gilesi.maestro.testing.models.Testcase; +import com.github.gilesi.maestro.testing.models.Testsuite; +import com.github.gilesi.maestro.testing.XmlParser; import java.io.File; import java.io.IOException; diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index ef3ba986..42518c91 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -14,8 +14,11 @@ import java.io.File; import java.io.IOException; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; import java.nio.file.Files; import java.nio.file.Path; +import java.nio.file.Paths; import java.util.*; public class Main { @@ -46,6 +49,22 @@ private static Map> readTraces(String traceXmlFolder) t return traces; } + public static void writeMarker(List failure, String output) { + int mainPadding = 1; + String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, ++mainPadding); + } + + try { + Files.write(new File(tracesFileName).toPath(), failure); + } catch (Throwable e) { + System.err.println("ERROR while saving marker"); + e.printStackTrace(); + } + } + public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { String traceXmlFolder = args[0]; String testPath = args[1]; @@ -53,16 +72,17 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine Map> testTraceResultsList = readTraces(traceXmlFolder); Map>> packageTraceResults = new HashMap<>(); + if (testTraceResultsList.isEmpty()) { + System.out.println("No traces found!"); + } + + for (String Test : testTraceResultsList.keySet()) { String[] splitTestName = Test.split("\\."); List Traces = testTraceResultsList.get(Test); Traces.sort(Comparator.comparingLong(PartialTrace::getTimeStampEntry)); - for (var el : Traces) { - System.out.println(el.getTimeStampEntry()); - } - String packageName = ""; String className = ""; if (splitTestName.length > 1) { @@ -156,6 +176,7 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine } catch (Exception e) { System.out.println("Unable to convert trace to code!"); e.printStackTrace(); + writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 4b05e836..c2397683 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -1,6 +1,7 @@ package com.github.gilesi.testgenerator; import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.testgenerator.exceptions.SerializationException; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import org.apache.commons.text.StringEscapeUtils; @@ -47,7 +48,7 @@ public static String getCleanedType(String FQN) { return FQN.replace("$", "."); } - public static String serializableDataToJava(TraceData serializableData) { + public static String serializableDataToJava(TraceData serializableData) throws SerializationException { String valueToBeEqualTo = serializableData.dataAsXml; String FQN = getCleanedType(serializableData.fullyQualifiedTypeName); @@ -61,11 +62,18 @@ public static String serializableDataToJava(TraceData serializableData) { !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - if (serializableData.dataAsXml.length() > Math.pow(2, 16)) { + int maxStringSize = (int) Math.pow(2, 16); + + if (serializableData.dataAsXml.length() > maxStringSize) { List sectionList = new ArrayList<>(); - for (int i = 0; i < serializableData.dataAsXml.length(); i += (int) Math.pow(2, 16)) { - String sectionOfDataAsXml = serializableData.dataAsXml.substring(i, i + (int) Math.pow(2, 16)); + for (int start = 0; start < serializableData.dataAsXml.length(); start += maxStringSize) { + int end = start + maxStringSize; + if (start + maxStringSize > serializableData.dataAsXml.length()) { + end = serializableData.dataAsXml.length(); + } + + String sectionOfDataAsXml = serializableData.dataAsXml.substring(start, end); String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } @@ -80,7 +88,18 @@ public static String serializableDataToJava(TraceData serializableData) { } } else { - valueToBeEqualTo = valueToBeEqualTo.split("[><]")[2]; + int start = valueToBeEqualTo.indexOf(">"); + int end = valueToBeEqualTo.lastIndexOf(" valueToBeEqualTo.length() - 1 - 3) { + throw new SerializationException("Malformed XML data"); + } + + valueToBeEqualTo = valueToBeEqualTo.substring(start + 1, end); if (FQN.equals("java.lang.Character")) { valueToBeEqualTo = "'%s'".formatted(valueToBeEqualTo); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index e456731d..9bb8a2dd 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -42,8 +42,8 @@ private static String getDataVariableDeclaration(TraceData serializableData, Var } String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - if (serializableData.dataAsXml.equals("null")) { - return "%s %s".formatted(returnType, instanceVariableName); + if (serializableData.dataAsXml == null || serializableData.dataAsXml.equals("null")) { + return "%s %s".formatted(returnType, "null"); } return "%s %s".formatted("var", instanceVariableName); } From 8a3bb682baee58433ee29476449c1baec39a5ec3 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 3 Jul 2024 22:43:27 +0200 Subject: [PATCH 146/244] fixes --- .../github/gilesi/maestro/ProcessUtils.java | 4 +- .../com/github/gilesi/maestro/RunResult.java | 12 +- .../gilesi/maestro/compsuite/CompSuite.java | 158 +++++++++++++++- .../com/github/gilesi/testgenerator/Main.java | 175 +++++++----------- .../testgenerator/SerializationUtils.java | 37 +++- .../testgenerator/TestMethodGenerator.java | 54 +++++- 6 files changed, 312 insertions(+), 128 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java index 26f71819..42fd75ff 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/ProcessUtils.java @@ -6,7 +6,7 @@ import java.io.InputStreamReader; public class ProcessUtils { - public static void runExternalCommand(String[] command, File directory, org.apache.logging.log4j.Logger logger) throws IOException, InterruptedException { + public static int runExternalCommand(String[] command, File directory, org.apache.logging.log4j.Logger logger) throws IOException, InterruptedException { ProcessBuilder pb = new ProcessBuilder(command); if (directory != null) { pb.directory(directory); @@ -21,6 +21,6 @@ public static void runExternalCommand(String[] command, File directory, org.apac logger.info(line); } - p.waitFor(); + return p.waitFor(); } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java b/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java index 02558c5e..477843a4 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/RunResult.java @@ -1,5 +1,9 @@ package com.github.gilesi.maestro; +import com.github.gilesi.maestro.testing.ReportItem; + +import java.util.ArrayList; + public class RunResult { public String ProjectId = ""; public boolean ProjectIsMissingLibrarySourceCode = false; @@ -9,6 +13,10 @@ public class RunResult { public boolean ProjectIsMissingTraceFiles = false; public boolean ProjectIsMissingSpecificTraces = false; public boolean ProjectFailedToGenerateAnyTraceTestSrc = false; - public boolean ProjectFailedToCompileGeneratedTests = false; // TODO - public boolean ProjectFailedToExecuteGeneratedTests = false; // TODO + public boolean ProjectFailedToCompileGeneratedTests = false; + public boolean ProjectFailedToExecuteGeneratedTests = false; + public boolean ProjectFailedToCompileGeneratedTestsWithNewVersion = false; + public boolean ProjectFailedToExecuteGeneratedTestsWithNewVersion = false; + public ArrayList TestExecutionReportWithOldVersion; + public ArrayList TestExecutionReportWithNewVersion; } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 7b3f54ab..17ed2b0f 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -1,12 +1,11 @@ package com.github.gilesi.maestro.compsuite; import com.fasterxml.jackson.databind.ObjectMapper; -import com.github.gilesi.maestro.Constants; -import com.github.gilesi.maestro.FileUtils; -import com.github.gilesi.maestro.Main; -import com.github.gilesi.maestro.RunResult; +import com.github.gilesi.maestro.*; import com.github.gilesi.maestro.runners.maven.Log4JLogger; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; +import com.github.gilesi.maestro.testing.ReportItem; +import com.github.gilesi.maestro.testing.gradle.GradleHarness; import com.github.gilesi.maestro.tools.ConfGen; import com.github.gilesi.maestro.tools.TestGen; import org.apache.maven.shared.invoker.MavenInvocationException; @@ -144,9 +143,69 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui runResults.add(runResult); } - System.out.println("ProjectId,ProjectIsMissingLibrarySourceCode,ProjectCannotBeReproduced,ProjectCannotBeInstrumented,ProjectFailedToLoadAgent,ProjectIsMissingTraceFiles,ProjectIsMissingSpecificTraces,ProjectFailedToGenerateAnyTraceTestSrc,ProjectFailedToCompileGeneratedTests,ProjectFailedToExecuteGeneratedTests"); + Main.logger.info("ProjectId,ProjectIsMissingLibrarySourceCode,ProjectCannotBeReproduced,ProjectCannotBeInstrumented,ProjectFailedToLoadAgent,ProjectIsMissingTraceFiles,ProjectIsMissingSpecificTraces,ProjectFailedToGenerateAnyTraceTestSrc,ProjectFailedToCompileGeneratedTests,ProjectFailedToExecuteGeneratedTests,ProjectFailedToCompileGeneratedTestsWithNewVersion,ProjectFailedToExecuteGeneratedTestsWithNewVersion"); for (RunResult runResult : runResults) { - Main.logger.info("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s".formatted(runResult.ProjectId, runResult.ProjectIsMissingLibrarySourceCode, runResult.ProjectCannotBeReproduced, runResult.ProjectCannotBeInstrumented, runResult.ProjectFailedToLoadAgent, runResult.ProjectIsMissingTraceFiles, runResult.ProjectIsMissingSpecificTraces, runResult.ProjectFailedToGenerateAnyTraceTestSrc, runResult.ProjectFailedToCompileGeneratedTests, runResult.ProjectFailedToExecuteGeneratedTests)); + Main.logger.info("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s".formatted( + runResult.ProjectId, + runResult.ProjectIsMissingLibrarySourceCode, + runResult.ProjectCannotBeReproduced, + runResult.ProjectCannotBeInstrumented, + runResult.ProjectFailedToLoadAgent, + runResult.ProjectIsMissingTraceFiles, + runResult.ProjectIsMissingSpecificTraces, + runResult.ProjectFailedToGenerateAnyTraceTestSrc, + runResult.ProjectFailedToCompileGeneratedTests, + runResult.ProjectFailedToExecuteGeneratedTests, + runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion, + runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion)); + } + + for (RunResult runResult : runResults) { + Main.logger.info("-----------------------------------"); + Main.logger.info("Id: %s".formatted(runResult.ProjectId)); + Main.logger.info("IsMissingLibrarySourceCode: %s".formatted(runResult.ProjectIsMissingLibrarySourceCode)); + if (runResult.ProjectIsMissingLibrarySourceCode) + continue; + Main.logger.info("CannotBeReproduced: %s".formatted(runResult.ProjectCannotBeReproduced)); + if (runResult.ProjectCannotBeReproduced) + continue; + Main.logger.info("CannotBeInstrumented: %s".formatted(runResult.ProjectCannotBeInstrumented)); + if (runResult.ProjectCannotBeInstrumented) + continue; + Main.logger.info("FailedToLoadAgent: %s".formatted(runResult.ProjectFailedToLoadAgent)); + if (runResult.ProjectFailedToLoadAgent) + continue; + Main.logger.info("IsMissingTraceFiles: %s".formatted(runResult.ProjectIsMissingTraceFiles)); + if (runResult.ProjectIsMissingTraceFiles) + continue; + Main.logger.info("IsMissingSpecificTraces: %s".formatted(runResult.ProjectIsMissingSpecificTraces)); + Main.logger.info("FailedToGenerateAnyTraceTestSrc: %s".formatted(runResult.ProjectFailedToGenerateAnyTraceTestSrc)); + if (runResult.ProjectFailedToGenerateAnyTraceTestSrc) + continue; + + Main.logger.info("FailedToCompileGeneratedTests: %s".formatted(runResult.ProjectFailedToCompileGeneratedTests)); + if (runResult.ProjectFailedToCompileGeneratedTests) + continue; + + Main.logger.info("FailedToExecuteGeneratedTests: %s".formatted(runResult.ProjectFailedToExecuteGeneratedTests)); + Main.logger.info("FailedToCompileGeneratedTestsWithNewVersion: %s".formatted(runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion)); + Main.logger.info("FailedToExecuteGeneratedTestsWithNewVersion: %s".formatted(runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion)); + Main.logger.info("TestExecutionReportWithOldVersion:"); + + if (runResult.TestExecutionReportWithOldVersion != null) { + for (ReportItem item : runResult.TestExecutionReportWithOldVersion) { + Main.logger.info("\"%s\",\"%s\",\"%s\",\"%s\"".formatted(item.Name, item.Version, item.getTestName(), item.getTestResult())); + } + } + + Main.logger.info("TestExecutionReportWithNewVersion:"); + if (runResult.TestExecutionReportWithNewVersion != null) { + for (ReportItem item : runResult.TestExecutionReportWithNewVersion) { + Main.logger.info("\"%s\",\"%s\",\"%s\",\"%s\"".formatted(item.Name, item.Version, item.getTestName(), item.getTestResult())); + } + } + + Main.logger.info("-----------------------------------"); } } @@ -219,7 +278,7 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina TestGen.runTestGen(GilesiRepositoryLocation, generatedTracesFolderPath.toString(), generatedCodeFolderPath.resolve("src").resolve("test").resolve("java").toString()); boolean hadGenerationFailures = !FileUtils.enumerateFiles(generatedCodeFolderPath.toString(), ".*\\.marker", true).isEmpty(); - if (!hadGenerationFailures) { + if (hadGenerationFailures) { runResult.ProjectIsMissingSpecificTraces = true; Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS MISSING SPECIFIC TRACE FILES: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); } @@ -282,6 +341,91 @@ testImplementation platform('org.junit:junit-bom:5.10.0') Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar")); Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties")); + + int returnCode = ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(generatedCodeFolderPath), + "compileTestJava", + "--warning-mode", + "all" + }, generatedCodeFolderPath.toFile(), Main.logger); + + runResult.ProjectFailedToCompileGeneratedTests = returnCode != 0; + + if (runResult.ProjectFailedToCompileGeneratedTests) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO COMPILE GENERATED TEST SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + + returnCode = ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(generatedCodeFolderPath), + "test", + "--warning-mode", + "all" + }, generatedCodeFolderPath.toFile(), Main.logger); + + runResult.ProjectFailedToExecuteGeneratedTests = returnCode != 0; + runResult.TestExecutionReportWithOldVersion = GradleHarness.getProjectTestReports(dependencyName, dependencyVersion, generatedCodeFolderPath.resolve("build.gradle").toString()); + + Files.delete(generatedCodeFolderPath.resolve("build.gradle")); + + buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + jvmArgs = ["--add-opens=java.base/java.util=ALL-UNNAMED"] + }""".formatted(dependencyName, incompatibility._new); + + Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); + + returnCode = ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(generatedCodeFolderPath), + "compileTestJava", + "--warning-mode", + "all" + }, generatedCodeFolderPath.toFile(), Main.logger); + + runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion = returnCode != 0; + + if (runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion) { + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO COMPILE GENERATED TEST2 SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + + returnCode = ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + "%s/gradlew".formatted(generatedCodeFolderPath), + "test", + "--warning-mode", + "all" + }, generatedCodeFolderPath.toFile(), Main.logger); + + runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion = returnCode != 0; + runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedCodeFolderPath.resolve("build.gradle").toString()); } }); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 42518c91..277e9512 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -29,17 +29,21 @@ public class Main { .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - private static Map> readTraces(String traceXmlFolder) throws IOException { - Map> traces = new HashMap(); - for (Path testTraceFile : Files.list(Path.of(traceXmlFolder)).sorted().toList()) { + // This is ugly, I know + private static int GetTraceNumber(Path i) { + return Integer.valueOf(i.getFileName().toString().split("_") + [1].replace(".json", "")); + } + + private static ArrayList readTraces(String traceXmlFolder) throws IOException { + ArrayList traces = new ArrayList(); + + List traceFiles = Files.list(Path.of(traceXmlFolder)).sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); + + for (Path testTraceFile : traceFiles) { try { TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), TestTraceResults.class); - if (traces.containsKey(testTraceResults.Test)) { - traces.get(testTraceResults.Test).add(testTraceResults.Trace); - } else { - traces.put(testTraceResults.Test, new ArrayList()); - traces.get(testTraceResults.Test).add(testTraceResults.Trace); - } + traces.add(testTraceResults.Trace); } catch (Exception e) { System.out.println("ERROR while deserializing a trace!"); e.printStackTrace(); @@ -69,125 +73,82 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine String traceXmlFolder = args[0]; String testPath = args[1]; - Map> testTraceResultsList = readTraces(traceXmlFolder); - Map>> packageTraceResults = new HashMap<>(); + ArrayList methodTraces = readTraces(traceXmlFolder); - if (testTraceResultsList.isEmpty()) { + if (methodTraces.isEmpty()) { System.out.println("No traces found!"); } - - for (String Test : testTraceResultsList.keySet()) { - String[] splitTestName = Test.split("\\."); - List Traces = testTraceResultsList.get(Test); - - Traces.sort(Comparator.comparingLong(PartialTrace::getTimeStampEntry)); - - String packageName = ""; - String className = ""; - if (splitTestName.length > 1) { - packageName = String.join(".", Arrays.stream(splitTestName).limit(splitTestName.length - 2).toArray(String[]::new)); - className = splitTestName[splitTestName.length - 2]; - } - - String testName = splitTestName[splitTestName.length - 1]; - - if (!packageTraceResults.containsKey(packageName)) { - packageTraceResults.put(packageName, new HashMap<>()); - } - - if (!packageTraceResults.get(packageName).containsKey(className)) { - packageTraceResults.get(packageName).put(className, new HashMap<>()); - } - - if (!packageTraceResults.get(packageName).get(className).containsKey(testName)) { - packageTraceResults.get(packageName).get(className).put(testName, Traces.toArray(Trace[]::new)); - } - } - Path mainOutputPath = Path.of(testPath).toAbsolutePath(); if (!Files.isDirectory(mainOutputPath)) { Files.createDirectories(mainOutputPath); } - for (Map.Entry>> packageTraces : packageTraceResults.entrySet()) { - String packageName = packageTraces.getKey(); - - Path packageOutputPath = mainOutputPath.toAbsolutePath(); + String packageName = "com.gilesi.testgen.generated"; + Path packageOutputPath = mainOutputPath.toAbsolutePath(); - if (!packageName.isEmpty()) { - for (String element : packageName.split("\\.")) { - packageOutputPath = packageOutputPath.resolve(element); - } - - if (!Files.isDirectory(packageOutputPath)) { - Files.createDirectories(packageOutputPath); - } + if (!packageName.isEmpty()) { + for (String element : packageName.split("\\.")) { + packageOutputPath = packageOutputPath.resolve(element); } - Set>> classTracesForPackage = packageTraces.getValue().entrySet(); - - for (Map.Entry> classTraces : classTracesForPackage) { - String className = classTraces.getKey(); - - Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); + if (!Files.isDirectory(packageOutputPath)) { + Files.createDirectories(packageOutputPath); + } + } - StringBuilder stringBuilder = new StringBuilder(); + String className = "GilesiGeneratedTestClass"; - if (!packageName.isEmpty()) { - stringBuilder.append("package %s;\n\n".formatted(packageName)); - } + Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); - stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); - stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); - stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); - stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); - stringBuilder.append("import org.junit.jupiter.api.Test;\n"); - stringBuilder.append("\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); - stringBuilder.append("\n"); + StringBuilder stringBuilder = new StringBuilder(); - stringBuilder.append("public class %s {\n".formatted(className)); + if (!packageName.isEmpty()) { + stringBuilder.append("package %s;\n\n".formatted(packageName)); + } - Map.Entry[] testTracesForClass = classTraces.getValue().entrySet().toArray(Map.Entry[]::new); + stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); + stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); + stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); + stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); + stringBuilder.append("import org.junit.jupiter.api.Test;\n"); + stringBuilder.append("import java.lang.Throwable;\n"); + stringBuilder.append("\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); + stringBuilder.append("\n"); - for (int j = 0; j < testTracesForClass.length; j++) { - Map.Entry testTraces = testTracesForClass[j]; - String testName = testTraces.getKey(); + stringBuilder.append("public class %s {\n".formatted(className)); - stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws XStreamException {\n".formatted(testName)); + String testName = "ClientSourcedGeneratedTest"; - VariableStackHandler variableStackHandler = new VariableStackHandler(); + stringBuilder.append("\t@Test\n"); + stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(testName)); - Trace[] methodTraces = testTraces.getValue(); + VariableStackHandler variableStackHandler = new VariableStackHandler(); - for (int i = 0; i < methodTraces.length; i++) { - Trace trace = methodTraces[i]; + for (int i = 0; i < methodTraces.size(); i++) { + Trace trace = methodTraces.get(i); - try { - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); - stringBuilder.append("%s\n".formatted(traceCode)); + try { + String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); + stringBuilder.append("%s\n".formatted(traceCode)); - if (i != methodTraces.length - 1) { - stringBuilder.append("\n"); - } - } catch (Exception e) { - System.out.println("Unable to convert trace to code!"); - e.printStackTrace(); - writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - } - } + if (i != methodTraces.size() - 1) { + stringBuilder.append("\n"); + } + } catch (Exception e) { + System.out.println("Unable to convert trace to code!"); + e.printStackTrace(); + writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - stringBuilder.append("\t}\n"); + stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodSignature())); + } + } - if (j != testTracesForClass.length - 1) { - stringBuilder.append("\n"); - } - } + stringBuilder.append("\t}\n"); - stringBuilder.append(""" + stringBuilder.append(""" \tpublic static String getToXml(Object obj) { \t\tDomDriver domDriver = new DomDriver(); @@ -196,7 +157,7 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine \t} """); - stringBuilder.append(""" + stringBuilder.append(""" \t@SuppressWarnings("unchecked") \tpublic static T getFromXml(String xmlString) { @@ -208,12 +169,10 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine \t} """); - stringBuilder.append("}\n"); - stringBuilder.append("\n"); + stringBuilder.append("}\n"); + stringBuilder.append("\n"); - Files.deleteIfExists(classOutputPath); - Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); - } - } + Files.deleteIfExists(classOutputPath); + Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index c2397683..7de5b663 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -62,7 +62,10 @@ public static String serializableDataToJava(TraceData serializableData) throws S !FQN.equals("java.lang.Float") && !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - int maxStringSize = (int) Math.pow(2, 16); + + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; if (serializableData.dataAsXml.length() > maxStringSize) { List sectionList = new ArrayList<>(); @@ -103,9 +106,39 @@ public static String serializableDataToJava(TraceData serializableData) throws S if (FQN.equals("java.lang.Character")) { valueToBeEqualTo = "'%s'".formatted(valueToBeEqualTo); + if (valueToBeEqualTo.equals("''")) { + valueToBeEqualTo = "java.lang.Character.MIN_VALUE"; + } } else if (FQN.equals("java.lang.String")) { - valueToBeEqualTo = "\"%s\"".formatted(valueToBeEqualTo); + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueToBeEqualTo.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueToBeEqualTo.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueToBeEqualTo.length()) { + end2 = valueToBeEqualTo.length(); + } + + String sectionOfDataAsXml = valueToBeEqualTo.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueToBeEqualTo = String.join("+", sectionList.toArray(String[]::new)); + } else { + valueToBeEqualTo = "\"%s\"".formatted(valueToBeEqualTo); + } + } + else if (FQN.equals("java.lang.Float")) { + valueToBeEqualTo = "%sF".formatted(valueToBeEqualTo); + } + else if (FQN.equals("java.lang.Long")) { + valueToBeEqualTo = "%sL".formatted(valueToBeEqualTo); } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index 9bb8a2dd..d7c5459a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -22,6 +22,7 @@ private static String serializableDataToCode(TraceData arg, VariableStackHandler if (failOnLambdas && arg.fullyQualifiedTypeName.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } + return dataLine; } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { return variableStackHandler.getInstanceVariableName(arg.instanceId); @@ -41,11 +42,30 @@ private static String getDataVariableDeclaration(TraceData serializableData, Var throw new SerializationException("We cannot handle lamdas at the moment!"); } - String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - if (serializableData.dataAsXml == null || serializableData.dataAsXml.equals("null")) { - return "%s %s".formatted(returnType, "null"); + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; } - return "%s %s".formatted("var", instanceVariableName); + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); + //if (serializableData.dataAsXml == null || serializableData.dataAsXml.equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + //} + //return "%s %s".formatted("var", instanceVariableName); } } @@ -54,11 +74,31 @@ private static String getDataVariableDeclaration2(TraceData serializableData, Va return variableStackHandler.getInstanceVariableName(serializableData.instanceId); } else { String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - if (serializableData.dataAsXml.equals("null")) { + //if (serializableData.dataAsXml.equals("null")) { return "%s %s".formatted(returnType, instanceVariableName); - } - return "%s %s".formatted("var", instanceVariableName); + //} + //return "%s %s".formatted("var", instanceVariableName); } } From ace3a2428fee9f3dcca7e9d2462e9a1002576d01 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 8 Jul 2024 09:54:12 +0200 Subject: [PATCH 147/244] Push the beginning of the test generator rewrite into the repo --- .../gilesi/maestro/compsuite/CompSuite.java | 27 +- .../testgenerator/SerializationUtils.java | 10 +- .../testgenerator/TestMethodGenerator.java | 151 ++++++++--- TestGenerator2/.gitignore | 39 +++ TestGenerator2/build.gradle | 77 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + TestGenerator2/gradlew | 246 ++++++++++++++++++ TestGenerator2/gradlew.bat | 91 +++++++ .../instrumentation/models/PartialTrace.java | 57 ++++ .../models/TestTraceResults.java | 6 + .../gilesi/instrumentation/models/Trace.java | 74 ++++++ .../instrumentation/models/TraceData.java | 8 + .../com/github/gilesi/testgenerator/Main.java | 167 ++++++++++++ 14 files changed, 913 insertions(+), 47 deletions(-) create mode 100644 TestGenerator2/.gitignore create mode 100644 TestGenerator2/build.gradle create mode 100644 TestGenerator2/gradle/wrapper/gradle-wrapper.jar create mode 100644 TestGenerator2/gradle/wrapper/gradle-wrapper.properties create mode 100644 TestGenerator2/gradlew create mode 100644 TestGenerator2/gradlew.bat create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 17ed2b0f..addd44b6 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -3,6 +3,7 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.github.gilesi.maestro.*; import com.github.gilesi.maestro.runners.maven.Log4JLogger; +import com.github.gilesi.maestro.runners.maven.ProjectRunner; import com.github.gilesi.maestro.runners.maven.TestAssertedLogger; import com.github.gilesi.maestro.testing.ReportItem; import com.github.gilesi.maestro.testing.gradle.GradleHarness; @@ -122,22 +123,22 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui continue; } - //String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); - //if (!incompatibility.test_cmd.equals("N/A")) { - // testCmd = incompatibility.test_cmd; - // if (testCmd.startsWith("mvn ")) { - // testCmd = testCmd.substring(4); - // } - //} + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } - //String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); - //if (javaToolOptions == null) { - // continue; - //} + String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + if (javaToolOptions == null) { + continue; + } - //Main.logger.info("Testing old project"); + Main.logger.info("Testing old project"); TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); - //ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger, runResult); runResults.add(runResult); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 7de5b663..9f699680 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -76,12 +76,12 @@ public static String serializableDataToJava(TraceData serializableData) throws S end = serializableData.dataAsXml.length(); } - String sectionOfDataAsXml = serializableData.dataAsXml.substring(start, end); + String sectionOfDataAsXml = "SNIP";//serializableData.dataAsXml.substring(start, end); String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } - String finalEscapedValue = String.join("+", sectionList.toArray(String[]::new)); + String finalEscapedValue = String.join(" + ", sectionList.toArray(String[]::new)); valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); } else { @@ -124,14 +124,14 @@ else if (FQN.equals("java.lang.String")) { end2 = valueToBeEqualTo.length(); } - String sectionOfDataAsXml = valueToBeEqualTo.substring(start2, end2); + String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } - valueToBeEqualTo = String.join("+", sectionList.toArray(String[]::new)); + valueToBeEqualTo = String.join(" + ", sectionList.toArray(String[]::new)); } else { - valueToBeEqualTo = "\"%s\"".formatted(valueToBeEqualTo); + valueToBeEqualTo = "\"%s\"".formatted(StringEscapeUtils.escapeJava(valueToBeEqualTo)); } } else if (FQN.equals("java.lang.Float")) { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index d7c5459a..05060b92 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -165,14 +165,17 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler } private static String traceToCode(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { - String methodCall = traceToMethodCall(methodTrace, variableStackHandler); - List preCallArguments = new ArrayList<>(); List variableList = new ArrayList<>(); boolean commentItAll = false; for (TraceData preCallArgument : methodTrace.getPreCallArguments()) { + if (preCallArgument.instanceId < 0 && preCallArgument.fullyQualifiedTypeName.equals("Object") && preCallArgument.dataAsXml.equals("null")) { + preCallArguments.add("null"); + continue; + } + String argumentValue; try { argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, true); @@ -189,19 +192,31 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab catch (SerializationException e) { argumentVariable = getDataVariableDeclaration2(preCallArgument, variableStackHandler); commentItAll = true; + // todo: problem here... } String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); + // Has to be defined already so no need to check here preCallArguments.add(variableStackHandler.getInstanceVariableName(preCallArgument.instanceId)); // Define the variable before the method variableList.add("%s;".formatted(argumentDeclaration)); } - String argumentParameters = String.join(", ", preCallArguments); - String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); - variableList.add(methodCallCode); + try { + String methodCall = traceToMethodCall(methodTrace, variableStackHandler); + + String argumentParameters = String.join(", ", preCallArguments); + String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); + variableList.add(methodCallCode); + } catch (InstanceNotDefinedException e) { + String methodCall = "// %s".formatted(e.getMessage());//traceToMethodCall(methodTrace, variableStackHandler); + + String argumentParameters = String.join(", ", preCallArguments); + String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); + variableList.add(methodCallCode); + } String code = String.join("\n%s".formatted(indentationPrefix), variableList); if (commentItAll) { @@ -211,37 +226,110 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab return code; } - private static String getAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { + private static String getReturnAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { int instanceId = traceData.instanceId; String dataAsXml = traceData.dataAsXml; if (dataAsXml != null) { - String instanceVarName = variableStackHandler.getInstanceVariableName(instanceId); + try { + String instanceVarName = variableStackHandler.getInstanceVariableName(instanceId); - if (dataAsXml.equals("null")) { - return "assertEquals(null, %s);".formatted(instanceVarName); - } + if (dataAsXml.equals("null")) { + return "assertEquals(null, %s);".formatted(instanceVarName); + } - if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); - } + if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } - String assertionLine; + String assertionLine; - if (useAltAssertionMode) { - String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); + if (useAltAssertionMode) { + String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); - if (valueAsCode.endsWith("[].class)")) { - assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + if (valueAsCode.endsWith("[].class)")) { + assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } else { + assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } } else { - assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); + + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueAsCode.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueAsCode = String.join("+", sectionList.toArray(String[]::new)); + } + + assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); } - } else { - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); - } - return assertionLine; + return assertionLine; + } catch (InstanceNotDefinedException e) { + String instanceVarName = String.valueOf(instanceId); + + if (dataAsXml.equals("null")) { + return "// assertEquals(null, %s);".formatted(instanceVarName); + } + + if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } + + String assertionLine; + + if (useAltAssertionMode) { + String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); + + if (valueAsCode.endsWith("[].class)")) { + assertionLine = "// assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } else { + assertionLine = "// assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } + } else { + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); + + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueAsCode.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueAsCode = String.join("+", sectionList.toArray(String[]::new)); + } + + assertionLine = "// assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); + } + + return assertionLine; + } } else if (variableStackHandler.isInstanceVariableNameDefined(instanceId)) { return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId)); } else if (failOnLambdas) { @@ -256,17 +344,22 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan for (TraceData traceData : methodTrace.getPostCallArguments()) { if (traceData == null) { - argList.add("null"); + //argList.add("null"); + continue; + } + + if (traceData.instanceId < 0 && traceData.fullyQualifiedTypeName.equals("Object") && traceData.dataAsXml.equals("null")) { + //argList.add("null"); continue; } // We return a value that we managed to serialize String assertionCodeLine; try { - assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); + assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); } argList.add(assertionCodeLine); } @@ -284,10 +377,10 @@ private static String traceToAssert(Trace methodTrace, VariableStackHandler vari if (!isConstructor && traceData != null) { String assertionCodeLine; try { - assertionCodeLine = getAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); + assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); } return assertionCodeLine; } diff --git a/TestGenerator2/.gitignore b/TestGenerator2/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/TestGenerator2/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/TestGenerator2/build.gradle b/TestGenerator2/build.gradle new file mode 100644 index 00000000..1d5a16fb --- /dev/null +++ b/TestGenerator2/build.gradle @@ -0,0 +1,77 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'com.github.gilesi.testgenerator' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() + mavenLocal() + maven { + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.14.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.0' + implementation 'com.fasterxml.jackson:jackson-base:2.14.0' + implementation 'org.apache.commons:commons-text:1.11.0' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' +} + +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.testgenerator.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.testgenerator.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.testgenerator') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.testgenerator' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=2G" + ] +} \ No newline at end of file diff --git a/TestGenerator2/gradle/wrapper/gradle-wrapper.jar b/TestGenerator2/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/TestGenerator2/gradlew.bat b/TestGenerator2/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/TestGenerator2/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java new file mode 100644 index 00000000..c4304c77 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -0,0 +1,57 @@ +package com.github.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PartialTrace { + private String methodSignature; + private TraceData instance; + private List preCallArguments; + private long timeStampEntry; + + @JsonCreator + public PartialTrace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("timeStampEntry") long timeStampEntry) { + this.methodSignature = methodSignature; + this.instance = instance; + this.preCallArguments = preCallArguments; + this.timeStampEntry = timeStampEntry; + } + + public String getMethodSignature() { + return methodSignature; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public TraceData getInstance() { + return instance; + } + + public void setInstance(TraceData instance) { + this.instance = instance; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } +} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java new file mode 100644 index 00000000..e277a415 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -0,0 +1,6 @@ +package com.github.gilesi.instrumentation.models; + +public class TestTraceResults { + public Trace Trace; + public String Test; +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java new file mode 100644 index 00000000..f6d78710 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -0,0 +1,74 @@ +package com.github.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class Trace extends PartialTrace { + private List postCallArguments; + private TraceData returnedValue; + private long timeStampExit; + private TraceData exceptionThrown; + private String[] stackTrace; + + @JsonCreator + public Trace( + @JsonProperty("methodSignature") String methodSignature, + @JsonProperty("instance") TraceData instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("stackTrace") String[] stackTrace) { + super(methodSignature, instance, preCallArguments, timeStampEntry); + + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; + this.stackTrace = stackTrace; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public TraceData getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(TraceData returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } + + public TraceData getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(TraceData exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } + + public String[] getStackTrace() { + return stackTrace; + } + + public void setStackTrace(String[] stackTrace) { + this.stackTrace = stackTrace; + } +} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java new file mode 100644 index 00000000..05e1d05c --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -0,0 +1,8 @@ +package com.github.gilesi.instrumentation.models; + +public class TraceData { + public String fullyQualifiedTypeName; + public String dataAsXml; + public String dataAsJson; + public int instanceId; +} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java new file mode 100644 index 00000000..6c5cdd10 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -0,0 +1,167 @@ +package com.github.gilesi.testgenerator; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.instrumentation.models.TestTraceResults; +import com.github.gilesi.instrumentation.models.Trace; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; + +public class Main { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + // This is ugly, I know + private static int GetTraceNumber(Path i) { + return Integer.valueOf(i.getFileName().toString().split("_") + [1].replace(".json", "")); + } + + private static ArrayList readTraces(String traceXmlFolder) throws IOException { + ArrayList traces = new ArrayList(); + + List traceFiles = Files.list(Path.of(traceXmlFolder)).sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); + + for (Path testTraceFile : traceFiles) { + try { + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), TestTraceResults.class); + traces.add(testTraceResults.Trace); + } catch (Exception e) { + System.out.println("ERROR while deserializing a trace!"); + e.printStackTrace(); + } + } + + return traces; + } + + public static void writeMarker(List failure, String output) { + int mainPadding = 1; + String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, ++mainPadding); + } + + try { + Files.write(new File(tracesFileName).toPath(), failure); + } catch (Throwable e) { + System.err.println("ERROR while saving marker"); + e.printStackTrace(); + } + } + + public static void main(String[] args) throws IOException { + String traceXmlFolder = args[0]; + String testPath = args[1]; + + ArrayList methodTraces = readTraces(traceXmlFolder); + + if (methodTraces.isEmpty()) { + System.out.println("No traces found!"); + } + + Path mainOutputPath = Path.of(testPath).toAbsolutePath(); + if (!Files.isDirectory(mainOutputPath)) { + Files.createDirectories(mainOutputPath); + } + + String packageName = "com.gilesi.testgen.generated"; + Path packageOutputPath = mainOutputPath.toAbsolutePath(); + + if (!packageName.isEmpty()) { + for (String element : packageName.split("\\.")) { + packageOutputPath = packageOutputPath.resolve(element); + } + + if (!Files.isDirectory(packageOutputPath)) { + Files.createDirectories(packageOutputPath); + } + } + + String className = "GilesiGeneratedTestClass"; + + Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); + + StringBuilder stringBuilder = new StringBuilder(); + + if (!packageName.isEmpty()) { + stringBuilder.append("package %s;\n\n".formatted(packageName)); + } + + stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); + stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); + stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); + stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); + stringBuilder.append("import org.junit.jupiter.api.Test;\n"); + stringBuilder.append("import java.lang.Throwable;\n"); + stringBuilder.append("\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); + stringBuilder.append("\n"); + + stringBuilder.append("public class %s {\n".formatted(className)); + + String testName = "ClientSourcedGeneratedTest"; + + stringBuilder.append("\t@Test\n"); + stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(testName)); + + for (int i = 0; i < methodTraces.size(); i++) { + Trace trace = methodTraces.get(i); + + try { + String traceCode = "a"; + stringBuilder.append("%s\n".formatted(traceCode)); + + if (i != methodTraces.size() - 1) { + stringBuilder.append("\n"); + } + } catch (Exception e) { + System.out.println("Unable to convert trace to code!"); + e.printStackTrace(); + writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); + + stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodSignature())); + } + } + + stringBuilder.append("\t}\n"); + + stringBuilder.append(""" + + \tpublic static String getToXml(Object obj) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\treturn xStream.toXML(obj); + \t} + """); + + stringBuilder.append(""" + + \t@SuppressWarnings("unchecked") + \tpublic static T getFromXml(String xmlString) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\txStream.addPermission(AnyTypePermission.ANY); + \t\tObject obj = xStream.fromXML(xmlString); + \t\treturn (T) obj; + \t} + """); + + stringBuilder.append("}\n"); + stringBuilder.append("\n"); + + Files.deleteIfExists(classOutputPath); + Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); + } +} \ No newline at end of file From f6fd53e3fbea5944ea1f9fdbc2828da8489110d0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 8 Jul 2024 10:13:41 +0200 Subject: [PATCH 148/244] Add argument checks to the new test generator --- .idea/compiler.xml | 5 +- .idea/gilesi.iml | 4 +- .idea/misc.xml | 1 + .../Maestro__Sample_Project_.xml | 2 +- .../com/github/gilesi/testgenerator/Main.java | 18 + oldlogs/surefire.txt | 3284 +++++++++++++++++ 6 files changed, 3310 insertions(+), 4 deletions(-) create mode 100644 oldlogs/surefire.txt diff --git a/.idea/compiler.xml b/.idea/compiler.xml index 11fb55ae..ba3af781 100644 --- a/.idea/compiler.xml +++ b/.idea/compiler.xml @@ -11,8 +11,9 @@ - - + + + \ No newline at end of file diff --git a/.idea/gilesi.iml b/.idea/gilesi.iml index d6ebd480..b107a2dd 100644 --- a/.idea/gilesi.iml +++ b/.idea/gilesi.iml @@ -2,7 +2,9 @@ - + + + diff --git a/.idea/misc.xml b/.idea/misc.xml index 7b4dd477..fa8260ce 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -2,6 +2,7 @@ + diff --git a/.idea/runConfigurations/Maestro__Sample_Project_.xml b/.idea/runConfigurations/Maestro__Sample_Project_.xml index b031dd29..86ca14fc 100644 --- a/.idea/runConfigurations/Maestro__Sample_Project_.xml +++ b/.idea/runConfigurations/Maestro__Sample_Project_.xml @@ -9,7 +9,7 @@

+ * E.g. for a constructor: public com.github.gilesi.tests.legacy.Foo(java.lang.String) + * for a method: public static java.lang.String com.github.gilesi.tests.legacy.Foo.HelloEveryone(java.lang.String[]) + * + * @param origin The executable to get an origin name string from + * @return the origin name string matching the passed in executable + */ + private static String getOriginName(Executable origin) { + String originName; + + if (origin instanceof Method) { + Method method = (Method) origin; + originName = method.toGenericString(); + } else if (origin instanceof Constructor) { + Constructor constructor = (Constructor) origin; + originName = constructor.toGenericString(); + } else { + int loggerInstance = Logger.GetInstance(); + Logger.Log(loggerInstance, "BUGBUGBUG: Unknown Originating Executable Type!"); + System.err.println(origin.getClass().getName()); + originName = origin.toString(); + } + return originName; + } + + public String getMethodSignature() { + return methodSignature; + } + + public ClassReference[] getParameterTypes() { + return parameterTypes; + } + + public ClassReference getReturnType() { + return returnType; + } + + public boolean getIsConstructor() { + return isConstructor; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public void setParameterTypes(ClassReference[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public void setReturnType(ClassReference returnType) { + this.returnType = returnType; + } + + public void setIsConstructor(boolean isConstructor) { + this.isConstructor = isConstructor; + } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index c9c5a707..fea2d118 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -7,16 +7,22 @@ public class PartialTrace { private TraceData instance; private List preCallArguments; private long timeStampEntry; + private InstanceReference instanceReference; + private MethodReference methodReference; public PartialTrace( String methodSignature, TraceData instance, List preCallArguments, - long timeStampEntry) { + long timeStampEntry, + InstanceReference instanceReference, + MethodReference methodReference) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; + this.instanceReference = instanceReference; + this.methodReference = methodReference; } public String getMethodSignature() { @@ -50,4 +56,20 @@ public long getTimeStampEntry() { public void setTimeStampEntry(long timeStampEntry) { this.timeStampEntry = timeStampEntry; } + + public InstanceReference getInstanceReference() { + return instanceReference; + } + + public MethodReference getMethodReference() { + return methodReference; + } + + public void setInstanceReference(InstanceReference instanceReference) { + this.instanceReference = instanceReference; + } + + public void setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index dd41038c..40bf3d5f 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -26,8 +26,10 @@ public Trace( String confName, String[] confDescriptors, boolean isConstructor, - String[] parameterTypes) { - super(methodSignature, instance, preCallArguments, timeStampEntry); + String[] parameterTypes, + InstanceReference instanceReference, + MethodReference methodReference) { + super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index eda639c7..50b34ee4 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -7,4 +7,5 @@ public class TraceData { public String dataAsXml; public String dataAsJson; public int instanceId; + public InstanceReference instanceReference; } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java new file mode 100644 index 00000000..b4f67b0d --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -0,0 +1,31 @@ +package com.github.gilesi.instrumentation.models; + +public class ClassReference { + private String fullyQualifiedTypeName; + private ClassReference[] interfaces; + private ClassReference superClass; + + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public ClassReference[] getInterfaces() { + return interfaces; + } + + public ClassReference getSuperClass() { + return superClass; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public void setInterfaces(ClassReference[] interfaces) { + this.interfaces = interfaces; + } + + public void setSuperClass(ClassReference superClass) { + this.superClass = superClass; + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java new file mode 100644 index 00000000..2170cc86 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java @@ -0,0 +1,49 @@ +package com.github.gilesi.instrumentation.models; + +public class InstanceReference { + private int instanceId = -1; + private String valueAsXmlString = null; + private String valueAsJsonString = null; + private boolean isNull = true; + private ClassReference classReference = null; + + public int getInstanceId() { + return instanceId; + } + + public String getValueAsXmlString() { + return valueAsXmlString; + } + + public String getValueAsJsonString() { + return valueAsJsonString; + } + + public boolean getIsNull() { + return isNull; + } + + public ClassReference getClassReference() { + return classReference; + } + + public void setInstanceId(int instanceId) { + this.instanceId = instanceId; + } + + public void setValueAsXmlString(String valueAsXmlString) { + this.valueAsXmlString = valueAsXmlString; + } + + public void setValueAsJsonString(String valueAsJsonString) { + this.valueAsJsonString = valueAsJsonString; + } + + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } + + public void setClassReference(ClassReference classReference) { + this.classReference = classReference; + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java new file mode 100644 index 00000000..e972cfcc --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -0,0 +1,44 @@ +package com.github.gilesi.instrumentation.models; + +public class MethodReference { + private String methodSignature; + private ClassReference[] parameterTypes; + private ClassReference returnType; + private boolean isConstructor; + + public MethodReference() { + + } + + public String getMethodSignature() { + return methodSignature; + } + + public ClassReference[] getParameterTypes() { + return parameterTypes; + } + + public ClassReference getReturnType() { + return returnType; + } + + public boolean getIsConstructor() { + return isConstructor; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public void setParameterTypes(ClassReference[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public void setReturnType(ClassReference returnType) { + this.returnType = returnType; + } + + public void setIsConstructor(boolean isConstructor) { + this.isConstructor = isConstructor; + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index c4304c77..a2c44c49 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -10,17 +10,23 @@ public class PartialTrace { private TraceData instance; private List preCallArguments; private long timeStampEntry; + private InstanceReference instanceReference; + private MethodReference methodReference; @JsonCreator public PartialTrace( @JsonProperty("methodSignature") String methodSignature, @JsonProperty("instance") TraceData instance, @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("timeStampEntry") long timeStampEntry) { + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; + this.instanceReference = instanceReference; + this.methodReference = methodReference; } public String getMethodSignature() { @@ -54,4 +60,20 @@ public long getTimeStampEntry() { public void setTimeStampEntry(long timeStampEntry) { this.timeStampEntry = timeStampEntry; } + + public InstanceReference getInstanceReference() { + return instanceReference; + } + + public MethodReference getMethodReference() { + return methodReference; + } + + public void setInstanceReference(InstanceReference instanceReference) { + this.instanceReference = instanceReference; + } + + public void setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index e58c5973..a73f242a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -14,6 +14,7 @@ public class Trace extends PartialTrace { private String confName; private String[] confDescriptors; private boolean isConstructor; + private String[] parameterTypes; @JsonCreator public Trace( @@ -28,8 +29,11 @@ public Trace( @JsonProperty("stackTrace") String[] stackTrace, @JsonProperty("confName") String confName, @JsonProperty("confDescriptors") String[] confDescriptors, - @JsonProperty("isConstructor") boolean isConstructor) { - super(methodSignature, instance, preCallArguments, timeStampEntry); + @JsonProperty("isConstructor") boolean isConstructor, + @JsonProperty("parameterTypes") String[] parameterTypes, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { + super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; @@ -39,6 +43,7 @@ public Trace( this.confName = confName; this.confDescriptors = confDescriptors; this.isConstructor = isConstructor; + this.parameterTypes = parameterTypes; } public List getPostCallArguments() { @@ -104,4 +109,12 @@ public boolean getIsConstructor() { public void setIsConstructor(boolean isConstructor) { this.isConstructor = isConstructor; } + + public String[] getParameterTypes() { + return parameterTypes; + } + + public void setParameterTypes(String[] parameterTypes) { + this.parameterTypes = parameterTypes; + } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index eda639c7..50b34ee4 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -7,4 +7,5 @@ public class TraceData { public String dataAsXml; public String dataAsJson; public int instanceId; + public InstanceReference instanceReference; } \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java new file mode 100644 index 00000000..b4f67b0d --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -0,0 +1,31 @@ +package com.github.gilesi.instrumentation.models; + +public class ClassReference { + private String fullyQualifiedTypeName; + private ClassReference[] interfaces; + private ClassReference superClass; + + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public ClassReference[] getInterfaces() { + return interfaces; + } + + public ClassReference getSuperClass() { + return superClass; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public void setInterfaces(ClassReference[] interfaces) { + this.interfaces = interfaces; + } + + public void setSuperClass(ClassReference superClass) { + this.superClass = superClass; + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java new file mode 100644 index 00000000..2170cc86 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java @@ -0,0 +1,49 @@ +package com.github.gilesi.instrumentation.models; + +public class InstanceReference { + private int instanceId = -1; + private String valueAsXmlString = null; + private String valueAsJsonString = null; + private boolean isNull = true; + private ClassReference classReference = null; + + public int getInstanceId() { + return instanceId; + } + + public String getValueAsXmlString() { + return valueAsXmlString; + } + + public String getValueAsJsonString() { + return valueAsJsonString; + } + + public boolean getIsNull() { + return isNull; + } + + public ClassReference getClassReference() { + return classReference; + } + + public void setInstanceId(int instanceId) { + this.instanceId = instanceId; + } + + public void setValueAsXmlString(String valueAsXmlString) { + this.valueAsXmlString = valueAsXmlString; + } + + public void setValueAsJsonString(String valueAsJsonString) { + this.valueAsJsonString = valueAsJsonString; + } + + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } + + public void setClassReference(ClassReference classReference) { + this.classReference = classReference; + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java new file mode 100644 index 00000000..bc3c8f54 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -0,0 +1,35 @@ +package com.github.gilesi.instrumentation.models; + +public class MethodReference { + private String methodSignature; + private ClassReference[] parameterTypes; + private ClassReference returnType; + + public MethodReference() { + + } + + public String getMethodSignature() { + return methodSignature; + } + + public ClassReference[] getParameterTypes() { + return parameterTypes; + } + + public ClassReference getReturnType() { + return returnType; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public void setParameterTypes(ClassReference[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public void setReturnType(ClassReference returnType) { + this.returnType = returnType; + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index c4304c77..a2c44c49 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -10,17 +10,23 @@ public class PartialTrace { private TraceData instance; private List preCallArguments; private long timeStampEntry; + private InstanceReference instanceReference; + private MethodReference methodReference; @JsonCreator public PartialTrace( @JsonProperty("methodSignature") String methodSignature, @JsonProperty("instance") TraceData instance, @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("timeStampEntry") long timeStampEntry) { + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { this.methodSignature = methodSignature; this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; + this.instanceReference = instanceReference; + this.methodReference = methodReference; } public String getMethodSignature() { @@ -54,4 +60,20 @@ public long getTimeStampEntry() { public void setTimeStampEntry(long timeStampEntry) { this.timeStampEntry = timeStampEntry; } + + public InstanceReference getInstanceReference() { + return instanceReference; + } + + public MethodReference getMethodReference() { + return methodReference; + } + + public void setInstanceReference(InstanceReference instanceReference) { + this.instanceReference = instanceReference; + } + + public void setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + } } \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index e58c5973..a73f242a 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -14,6 +14,7 @@ public class Trace extends PartialTrace { private String confName; private String[] confDescriptors; private boolean isConstructor; + private String[] parameterTypes; @JsonCreator public Trace( @@ -28,8 +29,11 @@ public Trace( @JsonProperty("stackTrace") String[] stackTrace, @JsonProperty("confName") String confName, @JsonProperty("confDescriptors") String[] confDescriptors, - @JsonProperty("isConstructor") boolean isConstructor) { - super(methodSignature, instance, preCallArguments, timeStampEntry); + @JsonProperty("isConstructor") boolean isConstructor, + @JsonProperty("parameterTypes") String[] parameterTypes, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { + super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; @@ -39,6 +43,7 @@ public Trace( this.confName = confName; this.confDescriptors = confDescriptors; this.isConstructor = isConstructor; + this.parameterTypes = parameterTypes; } public List getPostCallArguments() { @@ -104,4 +109,12 @@ public boolean getIsConstructor() { public void setIsConstructor(boolean isConstructor) { this.isConstructor = isConstructor; } + + public String[] getParameterTypes() { + return parameterTypes; + } + + public void setParameterTypes(String[] parameterTypes) { + this.parameterTypes = parameterTypes; + } } \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java index eda639c7..50b34ee4 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java @@ -7,4 +7,5 @@ public class TraceData { public String dataAsXml; public String dataAsJson; public int instanceId; + public InstanceReference instanceReference; } \ No newline at end of file From b5a4aa8f0c2745405a34a1fbcc2030020d24b9a4 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 10 Jul 2024 10:12:34 +0200 Subject: [PATCH 160/244] Remove redundant data from traces --- .../instrumentation/TraceDataFactory.java | 82 ------------------- .../gilesi/instrumentation/TraceFactory.java | 47 +++++------ .../instrumentation/models/PartialTrace.java | 30 +------ .../gilesi/instrumentation/models/Trace.java | 52 ++++-------- .../instrumentation/models/TraceData.java | 11 --- .../instrumentation/models/PartialTrace.java | 30 +------ .../gilesi/instrumentation/models/Trace.java | 52 ++++-------- .../instrumentation/models/TraceData.java | 11 --- .../com/github/gilesi/testgenerator/Main.java | 2 +- .../testgenerator/SerializationUtils.java | 22 ++--- .../testgenerator/TestMethodGenerator.java | 82 +++++++++---------- .../instrumentation/models/PartialTrace.java | 16 ++-- .../gilesi/instrumentation/models/Trace.java | 28 +++---- .../instrumentation/models/TraceData.java | 11 --- .../com/github/gilesi/testgenerator/Main.java | 28 +++---- 15 files changed, 144 insertions(+), 360 deletions(-) delete mode 100644 Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java delete mode 100644 Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java delete mode 100644 TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java deleted file mode 100644 index 067d6a91..00000000 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceDataFactory.java +++ /dev/null @@ -1,82 +0,0 @@ -package com.github.gilesi.instrumentation; - -import java.util.ArrayList; -import java.util.List; - -import com.github.gilesi.instrumentation.models.InstanceReference; -import com.github.gilesi.instrumentation.models.TraceData; - -public class TraceDataFactory { - public static TraceData valueOf(Object object, int nullInstanceId) { - TraceData traceData = new TraceData(); - - if (object == null) { - traceData.fullyQualifiedTypeName = "Object"; - traceData.Interfaces = new String[] {}; - traceData.SuperClasses = new String[] {}; - traceData.dataAsXml = "null"; - traceData.dataAsJson = "null"; - traceData.instanceId = nullInstanceId; - traceData.instanceReference = new InstanceReference(null); - return traceData; - } - - // /!\ CAUTION - // - // The JVM Specification __clearly__ states that the hashcode returned by the Object implementation - // (the one obtained here) is not claimed to be valid, and is not an address in memory. - // Indeed, how come do we have 32-bit integers on a 64-bit addressable system...? - // While it's __unlikely__ to encounter the same value here for our purposes, the risk is NON 0, and - // we must always check other factors to know if a value is identical to one or another, like the - // fully qualified name, or the parameter list! You've been warned... - // - // PS: if you got a better idea, I'm all ears :) - // - int instanceId = System.identityHashCode(object); - String objectClassName = object.getClass().getTypeName(); - - traceData.fullyQualifiedTypeName = objectClassName; - traceData.Interfaces = getInterfaces(object.getClass()).stream().map(t -> t.getName()).toArray(String[]::new); - traceData.SuperClasses = getSuperclasses(object.getClass()).stream().map(t -> t.getName()).toArray(String[]::new); - traceData.instanceId = instanceId; - - String serializedString = null; - - try { - serializedString = XmlUtils.getToXml(object); - } catch (Throwable e) { - int loggerInstance = Logger.GetInstance(); - Logger.Log(loggerInstance, "ERROR: Cannot serialize specific argument: " + e); - } - - traceData.dataAsXml = serializedString; - - traceData.instanceReference = new InstanceReference(object); - - return traceData; - } - - public static List> getInterfaces(Class clazz) { - ArrayList> interfaceNames = new ArrayList<>(); - - for (Class interfaze : clazz.getInterfaces()) { - interfaceNames.add(interfaze); - interfaceNames.addAll(getInterfaces(interfaze)); - } - - return interfaceNames; - } - - public static List> getSuperclasses(Class clazz) { - ArrayList> classNames = new ArrayList<>(); - - Class superclass = clazz.getSuperclass(); - while (superclass != null) { - classNames.add(superclass); - clazz = superclass; - superclass = clazz.getSuperclass(); - } - - return classNames; - } -} \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java index 500c3337..32033424 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/TraceFactory.java @@ -4,7 +4,6 @@ import com.github.gilesi.instrumentation.models.MethodReference; import com.github.gilesi.instrumentation.models.PartialTrace; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.instrumentation.models.TraceData; import java.lang.reflect.Constructor; import java.lang.reflect.Executable; @@ -45,11 +44,11 @@ private static String getOriginName(Executable origin) { return originName; } - private static List getArgumentsAsSerializableData(Object[] arguments) { - List argumentStrings = new ArrayList<>(); + private static List getArgumentsAsSerializableData(Object[] arguments) { + List argumentStrings = new ArrayList<>(); if (arguments != null) { - argumentStrings = Arrays.stream(arguments).map(t -> TraceDataFactory.valueOf(t, ++NullCounter * -1)).collect(Collectors.toList()); + argumentStrings = Arrays.stream(arguments).map(t -> new InstanceReference(t)).collect(Collectors.toList()); } return argumentStrings; @@ -69,19 +68,16 @@ private static List getArgumentsAsSerializableData(Object[] arguments * @param arguments The originating trace argument list on entry */ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arguments, Object instance) { - String methodSignature = getOriginName(origin); - TraceData serializableInstance = null; + InstanceReference serializableInstance = null; if (instance != null) { - serializableInstance = TraceDataFactory.valueOf(instance, ++NullCounter * -1); + serializableInstance = new InstanceReference(instance); } - List preCallArguments = getArgumentsAsSerializableData(arguments); + List preCallArguments = getArgumentsAsSerializableData(arguments); return new PartialTrace( - methodSignature, - serializableInstance, preCallArguments, 0, - new InstanceReference(instance), + serializableInstance, new MethodReference(origin)); } @@ -103,32 +99,31 @@ public static PartialTrace getPartialMethodTrace(Executable origin, Object[] arg * @param returned The data returned by the originating trace */ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object returned, Object instance, Throwable thrown, PartialTrace originatingTrace, String[] stackTrace, boolean isConstructor) { - - String methodSignature = getOriginName(origin); - TraceData serializableInstance = null; + InstanceReference serializableInstance = null; if (instance != null) { - serializableInstance = TraceDataFactory.valueOf(instance, ++NullCounter * -1); + serializableInstance = new InstanceReference(instance); } - List preCallArguments = originatingTrace.getPreCallArguments(); - List postCallArguments = getArgumentsAsSerializableData(arguments); + String methodSignature = getOriginName(origin); + List preCallArguments = originatingTrace.getPreCallArguments(); + List postCallArguments = getArgumentsAsSerializableData(arguments); // Every argument of a method should have the same instance id, in the case of null params, they will be different, so fix that for (int i = 0; i < preCallArguments.size(); i++) { - if (postCallArguments.get(i).instanceId < 0) { // Null ids are intentionally negative - postCallArguments.get(i).instanceId = preCallArguments.get(i).instanceId; + if (postCallArguments.get(i).getInstanceId() < 0) { // Null ids are intentionally negative + postCallArguments.get(i).setInstanceId(preCallArguments.get(i).getInstanceId()); } } - TraceData returnedValue = null; // TODO: Detect if the method returns nothing or not here! + InstanceReference returnedValue = null; // TODO: Detect if the method returns nothing or not here! if (returned != null) { - returnedValue = TraceDataFactory.valueOf(returned, ++NullCounter * -1); + returnedValue = new InstanceReference(returned); } long timeStampEntry = originatingTrace.getTimeStampEntry(); - TraceData exceptionThrown = null; + InstanceReference exceptionThrown = null; if (thrown != null) { - exceptionThrown = TraceDataFactory.valueOf(thrown, ++NullCounter * -1); + exceptionThrown = new InstanceReference(thrown); } String methodName = methodSignature.split("\\(")[0]; @@ -166,8 +161,6 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object } return new Trace( - methodSignature, - serializableInstance, preCallArguments, postCallArguments, returnedValue, @@ -177,9 +170,7 @@ public static Trace getMethodTrace(Executable origin, Object[] arguments, Object stackTrace, confName, confDescriptors, - isConstructor, - Arrays.asList(origin.getParameterTypes()).stream().map(t -> t.getName()).toArray(String[]::new), - new InstanceReference(instance), + serializableInstance, new MethodReference(origin)); } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index fea2d118..70713866 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -3,49 +3,27 @@ import java.util.List; public class PartialTrace { - private String methodSignature; - private TraceData instance; - private List preCallArguments; + private List preCallArguments; private long timeStampEntry; private InstanceReference instanceReference; private MethodReference methodReference; public PartialTrace( - String methodSignature, - TraceData instance, - List preCallArguments, + List preCallArguments, long timeStampEntry, InstanceReference instanceReference, MethodReference methodReference) { - this.methodSignature = methodSignature; - this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; this.instanceReference = instanceReference; this.methodReference = methodReference; } - public String getMethodSignature() { - return methodSignature; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public TraceData getInstance() { - return instance; - } - - public void setInstance(TraceData instance) { - this.instance = instance; - } - - public List getPreCallArguments() { + public List getPreCallArguments() { return preCallArguments; } - public void setPreCallArguments(List preCallArguments) { + public void setPreCallArguments(List preCallArguments) { this.preCallArguments = preCallArguments; } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index 40bf3d5f..f455ebde 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -3,33 +3,27 @@ import java.util.List; public class Trace extends PartialTrace { - private List postCallArguments; - private TraceData returnedValue; + private List postCallArguments; + private InstanceReference returnedValue; private long timeStampExit; - private TraceData exceptionThrown; + private InstanceReference exceptionThrown; private String[] stackTrace; private String confName; private String[] confDescriptors; - private boolean isConstructor; - private String[] parameterTypes; public Trace( - String methodSignature, - TraceData instance, - List preCallArguments, - List postCallArguments, - TraceData returnedValue, + List preCallArguments, + List postCallArguments, + InstanceReference returnedValue, long timeStampEntry, long timeStampExit, - TraceData exceptionThrown, + InstanceReference exceptionThrown, String[] stackTrace, String confName, String[] confDescriptors, - boolean isConstructor, - String[] parameterTypes, InstanceReference instanceReference, MethodReference methodReference) { - super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); + super(preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; @@ -38,23 +32,21 @@ public Trace( this.stackTrace = stackTrace; this.confName = confName; this.confDescriptors = confDescriptors; - this.isConstructor = isConstructor; - this.parameterTypes = parameterTypes; } - public List getPostCallArguments() { + public List getPostCallArguments() { return postCallArguments; } - public void setPostCallArguments(List postCallArguments) { + public void setPostCallArguments(List postCallArguments) { this.postCallArguments = postCallArguments; } - public TraceData getReturnedValue() { + public InstanceReference getReturnedValue() { return returnedValue; } - public void setReturnedValue(TraceData returnedValue) { + public void setReturnedValue(InstanceReference returnedValue) { this.returnedValue = returnedValue; } @@ -66,11 +58,11 @@ public void setTimeStampExit(long timeStampExit) { this.timeStampExit = timeStampExit; } - public TraceData getExceptionThrown() { + public InstanceReference getExceptionThrown() { return exceptionThrown; } - public void setExceptionThrown(TraceData exceptionThrown) { + public void setExceptionThrown(InstanceReference exceptionThrown) { this.exceptionThrown = exceptionThrown; } @@ -97,20 +89,4 @@ public String[] getConfDescriptors() { public void setConfDescriptors(String[] confDescriptors) { this.confDescriptors = confDescriptors; } - - public boolean getIsConstructor() { - return isConstructor; - } - - public void setIsConstructor(boolean isConstructor) { - this.isConstructor = isConstructor; - } - - public String[] getParameterTypes() { - return parameterTypes; - } - - public void setParameterTypes(String[] parameterTypes) { - this.parameterTypes = parameterTypes; - } } \ No newline at end of file diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java deleted file mode 100644 index 50b34ee4..00000000 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class TraceData { - public String fullyQualifiedTypeName; - public String[] Interfaces; - public String[] SuperClasses; - public String dataAsXml; - public String dataAsJson; - public int instanceId; - public InstanceReference instanceReference; -} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index a2c44c49..d2a7d482 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -6,50 +6,28 @@ import java.util.List; public class PartialTrace { - private String methodSignature; - private TraceData instance; - private List preCallArguments; + private List preCallArguments; private long timeStampEntry; private InstanceReference instanceReference; private MethodReference methodReference; @JsonCreator public PartialTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("preCallArguments") List preCallArguments, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("instanceReference") InstanceReference instanceReference, @JsonProperty("methodReference") MethodReference methodReference) { - this.methodSignature = methodSignature; - this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; this.instanceReference = instanceReference; this.methodReference = methodReference; } - public String getMethodSignature() { - return methodSignature; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public TraceData getInstance() { - return instance; - } - - public void setInstance(TraceData instance) { - this.instance = instance; - } - - public List getPreCallArguments() { + public List getPreCallArguments() { return preCallArguments; } - public void setPreCallArguments(List preCallArguments) { + public void setPreCallArguments(List preCallArguments) { this.preCallArguments = preCallArguments; } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index a73f242a..9dee5a0a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -6,34 +6,28 @@ import java.util.List; public class Trace extends PartialTrace { - private List postCallArguments; - private TraceData returnedValue; + private List postCallArguments; + private InstanceReference returnedValue; private long timeStampExit; - private TraceData exceptionThrown; + private InstanceReference exceptionThrown; private String[] stackTrace; private String confName; private String[] confDescriptors; - private boolean isConstructor; - private String[] parameterTypes; @JsonCreator public Trace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") InstanceReference returnedValue, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("exceptionThrown") InstanceReference exceptionThrown, @JsonProperty("stackTrace") String[] stackTrace, @JsonProperty("confName") String confName, @JsonProperty("confDescriptors") String[] confDescriptors, - @JsonProperty("isConstructor") boolean isConstructor, - @JsonProperty("parameterTypes") String[] parameterTypes, @JsonProperty("instanceReference") InstanceReference instanceReference, @JsonProperty("methodReference") MethodReference methodReference) { - super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); + super(preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; @@ -42,23 +36,21 @@ public Trace( this.stackTrace = stackTrace; this.confName = confName; this.confDescriptors = confDescriptors; - this.isConstructor = isConstructor; - this.parameterTypes = parameterTypes; } - public List getPostCallArguments() { + public List getPostCallArguments() { return postCallArguments; } - public void setPostCallArguments(List postCallArguments) { + public void setPostCallArguments(List postCallArguments) { this.postCallArguments = postCallArguments; } - public TraceData getReturnedValue() { + public InstanceReference getReturnedValue() { return returnedValue; } - public void setReturnedValue(TraceData returnedValue) { + public void setReturnedValue(InstanceReference returnedValue) { this.returnedValue = returnedValue; } @@ -70,11 +62,11 @@ public void setTimeStampExit(long timeStampExit) { this.timeStampExit = timeStampExit; } - public TraceData getExceptionThrown() { + public InstanceReference getExceptionThrown() { return exceptionThrown; } - public void setExceptionThrown(TraceData exceptionThrown) { + public void setExceptionThrown(InstanceReference exceptionThrown) { this.exceptionThrown = exceptionThrown; } @@ -101,20 +93,4 @@ public String[] getConfDescriptors() { public void setConfDescriptors(String[] confDescriptors) { this.confDescriptors = confDescriptors; } - - public boolean getIsConstructor() { - return isConstructor; - } - - public void setIsConstructor(boolean isConstructor) { - this.isConstructor = isConstructor; - } - - public String[] getParameterTypes() { - return parameterTypes; - } - - public void setParameterTypes(String[] parameterTypes) { - this.parameterTypes = parameterTypes; - } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java deleted file mode 100644 index 50b34ee4..00000000 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class TraceData { - public String fullyQualifiedTypeName; - public String[] Interfaces; - public String[] SuperClasses; - public String dataAsXml; - public String dataAsJson; - public int instanceId; - public InstanceReference instanceReference; -} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 277e9512..a581d393 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -142,7 +142,7 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine e.printStackTrace(); writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodSignature())); + stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 2d778b8c..8f1b0078 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -1,6 +1,6 @@ package com.github.gilesi.testgenerator; -import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.SerializationException; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import org.apache.commons.text.StringEscapeUtils; @@ -48,9 +48,9 @@ public static String getCleanedType(String FQN) { return FQN.replace("$", "."); } - public static String serializableDataToJava(TraceData serializableData) throws SerializationException { - String valueToBeEqualTo = serializableData.dataAsXml; - String FQN = getCleanedType(serializableData.fullyQualifiedTypeName); + public static String serializableDataToJava(InstanceReference serializableData) throws SerializationException { + String valueToBeEqualTo = serializableData.getValueAsXmlString(); + String FQN = getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && @@ -67,16 +67,16 @@ public static String serializableDataToJava(TraceData serializableData) throws S // TODO: Check why this still fails int maxStringSize = 1024; - if (serializableData.dataAsXml.length() > maxStringSize) { + if (serializableData.getValueAsXmlString().length() > maxStringSize) { List sectionList = new ArrayList<>(); - for (int start = 0; start < serializableData.dataAsXml.length(); start += maxStringSize) { + for (int start = 0; start < serializableData.getValueAsXmlString().length(); start += maxStringSize) { int end = start + maxStringSize; - if (start + maxStringSize > serializableData.dataAsXml.length()) { - end = serializableData.dataAsXml.length(); + if (start + maxStringSize > serializableData.getValueAsXmlString().length()) { + end = serializableData.getValueAsXmlString().length(); } - String sectionOfDataAsXml = "SNIP";//serializableData.dataAsXml.substring(start, end); + String sectionOfDataAsXml = "SNIP";//serializableData.getValueAsXmlString().substring(start, end); String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } @@ -86,8 +86,8 @@ public static String serializableDataToJava(TraceData serializableData) throws S valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); } else { // Casting is not needed if we only use this with variable assignments that are strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.dataAsXml)); - valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.dataAsXml)); + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); } } else { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java index acf664a2..eced2a8e 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java @@ -1,7 +1,7 @@ package com.github.gilesi.testgenerator; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; import com.github.gilesi.testgenerator.exceptions.SerializationException; @@ -13,31 +13,31 @@ public class TestMethodGenerator { private static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; - private static String serializableDataToCode(TraceData arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException, InstanceNotDefinedException { - if (arg.dataAsXml != null) { - if (arg.dataAsXml.equals("null")) { - return arg.dataAsXml; + private static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException, InstanceNotDefinedException { + if (arg.getValueAsXmlString() != null) { + if (arg.getValueAsXmlString().equals("null")) { + return arg.getValueAsXmlString(); } String dataLine = SerializationUtils.serializableDataToJava(arg); - if (failOnLambdas && arg.fullyQualifiedTypeName.contains("..Lambda/")) { + if (failOnLambdas && arg.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } return dataLine; - } else if (variableStackHandler.isInstanceVariableNameDefined(arg.instanceId)) { - return variableStackHandler.getInstanceVariableName(arg.instanceId); + } else if (variableStackHandler.isInstanceVariableNameDefined(arg.getInstanceId())) { + return variableStackHandler.getInstanceVariableName(arg.getInstanceId()); } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { - return "// Unserializable data with instance id: " + arg.instanceId; + return "// Unserializable data with instance id: " + arg.getInstanceId(); } } - private static String getDataVariableDeclaration(TraceData serializableData, VariableStackHandler variableStackHandler) throws SerializationException, InstanceNotDefinedException, InstanceAlreadyDefinedException { - if (variableStackHandler.isInstanceVariableNameDefined(serializableData.instanceId)) { - return variableStackHandler.getInstanceVariableName(serializableData.instanceId); + private static String getDataVariableDeclaration(InstanceReference serializableData, VariableStackHandler variableStackHandler) throws SerializationException, InstanceNotDefinedException, InstanceAlreadyDefinedException { + if (variableStackHandler.isInstanceVariableNameDefined(serializableData.getInstanceId())) { + return variableStackHandler.getInstanceVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); + String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); if (returnType.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -61,19 +61,19 @@ private static String getDataVariableDeclaration(TraceData serializableData, Var returnType = "var"; } - String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - //if (serializableData.dataAsXml == null || serializableData.dataAsXml.equals("null")) { + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.getInstanceId()); + //if (serializableData.getValueAsXmlString() == null || serializableData.getValueAsXmlString().equals("null")) { return "%s %s".formatted(returnType, instanceVariableName); //} //return "%s %s".formatted("var", instanceVariableName); } } - private static String getDataVariableDeclaration2(TraceData serializableData, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, InstanceAlreadyDefinedException { - if (variableStackHandler.isInstanceVariableNameDefined(serializableData.instanceId)) { - return variableStackHandler.getInstanceVariableName(serializableData.instanceId); + private static String getDataVariableDeclaration2(InstanceReference serializableData, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, InstanceAlreadyDefinedException { + if (variableStackHandler.isInstanceVariableNameDefined(serializableData.getInstanceId())) { + return variableStackHandler.getInstanceVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils.getCleanedType(serializableData.fullyQualifiedTypeName); + String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); try { var el = returnType.split("\\."); @@ -94,8 +94,8 @@ private static String getDataVariableDeclaration2(TraceData serializableData, Va returnType = "var"; } - String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.instanceId); - //if (serializableData.dataAsXml.equals("null")) { + String instanceVariableName = variableStackHandler.newInstanceVariableName(serializableData.getInstanceId()); + //if (serializableData.getValueAsXmlString().equals("null")) { return "%s %s".formatted(returnType, instanceVariableName); //} //return "%s %s".formatted("var", instanceVariableName); @@ -103,18 +103,18 @@ private static String getDataVariableDeclaration2(TraceData serializableData, Va } private static String traceToMethodCall(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, InstanceAlreadyDefinedException { - String methodName = methodTrace.getMethodSignature().split("\\(")[0]; + String methodName = methodTrace.getMethodReference().getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - TraceData traceData = methodTrace.getInstance(); + InstanceReference traceData = methodTrace.getInstanceReference(); - boolean isInstanceCall = traceData != null && !traceData.fullyQualifiedTypeName.replace("$", ".").equals(methodName); + boolean isInstanceCall = traceData != null && !traceData.getClassReference().getFullyQualifiedTypeName().replace("$", ".").equals(methodName); String methodCall = methodName; boolean commentItAll = false; - if (methodTrace.getIsConstructor()) { + if (methodTrace.getMethodReference().getIsConstructor()) { methodCall = "new %s".formatted(methodCall); // TODO: we need to fix the tracer so for constructors we get to return an instance, and instead leave instance field empty, to make more sense and simplify this part too!! @@ -136,11 +136,11 @@ private static String traceToMethodCall(Trace methodTrace, VariableStackHandler methodCall = "%s = %s".formatted(argumentVariable, methodCall); } else if (isInstanceCall) { String instanceMethodCallName = methodCall.split("\\.")[methodCall.split("\\.").length - 1]; - String instanceVariableName = variableStackHandler.getInstanceVariableName(traceData.instanceId); + String instanceVariableName = variableStackHandler.getInstanceVariableName(traceData.getInstanceId()); methodCall = "%s.%s".formatted(instanceVariableName, instanceMethodCallName); } - TraceData returnedValue = methodTrace.getReturnedValue(); + InstanceReference returnedValue = methodTrace.getReturnedValue(); if (returnedValue != null) { // We return a value that we managed to serialize String argumentVariable; @@ -169,8 +169,8 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab boolean commentItAll = false; - for (TraceData preCallArgument : methodTrace.getPreCallArguments()) { - if (preCallArgument.instanceId < 0 && preCallArgument.fullyQualifiedTypeName.equals("Object") && preCallArgument.dataAsXml.equals("null")) { + for (InstanceReference preCallArgument : methodTrace.getPreCallArguments()) { + if (preCallArgument.getInstanceId() < 0 && preCallArgument.getClassReference().getFullyQualifiedTypeName().equals("Object") && preCallArgument.getValueAsXmlString().equals("null")) { preCallArguments.add("null"); continue; } @@ -197,7 +197,7 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); // Has to be defined already so no need to check here - preCallArguments.add(variableStackHandler.getInstanceVariableName(preCallArgument.instanceId)); + preCallArguments.add(variableStackHandler.getInstanceVariableName(preCallArgument.getInstanceId())); // Define the variable before the method variableList.add("%s;".formatted(argumentDeclaration)); @@ -225,9 +225,9 @@ private static String traceToCode(Trace methodTrace, VariableStackHandler variab return code; } - private static String getReturnAssertionCodeLine(TraceData traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { - int instanceId = traceData.instanceId; - String dataAsXml = traceData.dataAsXml; + private static String getReturnAssertionCodeLine(InstanceReference traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { + int instanceId = traceData.getInstanceId(); + String dataAsXml = traceData.getValueAsXmlString(); if (dataAsXml != null) { try { @@ -237,7 +237,7 @@ private static String getReturnAssertionCodeLine(TraceData traceData, VariableSt return "assertEquals(null, %s);".formatted(instanceVarName); } - if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { + if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -286,7 +286,7 @@ private static String getReturnAssertionCodeLine(TraceData traceData, VariableSt return "// assertEquals(null, %s);".formatted(instanceVarName); } - if (failOnLambdas && traceData.fullyQualifiedTypeName.contains("..Lambda/")) { + if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -334,20 +334,20 @@ private static String getReturnAssertionCodeLine(TraceData traceData, VariableSt } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { - return "// Unserializable data with instance id: %d".formatted(traceData.instanceId); + return "// Unserializable data with instance id: %d".formatted(traceData.getInstanceId()); } } private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceNotDefinedException, SerializationException { List argList = new ArrayList<>(); - for (TraceData traceData : methodTrace.getPostCallArguments()) { + for (InstanceReference traceData : methodTrace.getPostCallArguments()) { if (traceData == null) { //argList.add("null"); continue; } - if (traceData.instanceId < 0 && traceData.fullyQualifiedTypeName.equals("Object") && traceData.dataAsXml.equals("null")) { + if (traceData.getInstanceId() < 0 && traceData.getClassReference().getFullyQualifiedTypeName().equals("Object") && traceData.getValueAsXmlString().equals("null")) { //argList.add("null"); continue; } @@ -367,12 +367,12 @@ private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHan } private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, SerializationException { - String cleanedMethodName = methodTrace.getMethodSignature().split("\\(")[0]; + String cleanedMethodName = methodTrace.getMethodReference().getMethodSignature().split("\\(")[0]; cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1].replace("$", "."); - TraceData traceData = methodTrace.getReturnedValue(); + InstanceReference traceData = methodTrace.getReturnedValue(); - if (!methodTrace.getIsConstructor() && traceData != null) { + if (!methodTrace.getMethodReference().getIsConstructor() && traceData != null) { String assertionCodeLine; try { assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index a2c44c49..fbb91824 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -7,8 +7,8 @@ public class PartialTrace { private String methodSignature; - private TraceData instance; - private List preCallArguments; + private InstanceReference instance; + private List preCallArguments; private long timeStampEntry; private InstanceReference instanceReference; private MethodReference methodReference; @@ -16,8 +16,8 @@ public class PartialTrace { @JsonCreator public PartialTrace( @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("instance") InstanceReference instance, + @JsonProperty("preCallArguments") List preCallArguments, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("instanceReference") InstanceReference instanceReference, @JsonProperty("methodReference") MethodReference methodReference) { @@ -37,19 +37,19 @@ public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } - public TraceData getInstance() { + public InstanceReference getInstance() { return instance; } - public void setInstance(TraceData instance) { + public void setInstance(InstanceReference instance) { this.instance = instance; } - public List getPreCallArguments() { + public List getPreCallArguments() { return preCallArguments; } - public void setPreCallArguments(List preCallArguments) { + public void setPreCallArguments(List preCallArguments) { this.preCallArguments = preCallArguments; } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index a73f242a..6a6571cb 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -6,10 +6,10 @@ import java.util.List; public class Trace extends PartialTrace { - private List postCallArguments; - private TraceData returnedValue; + private List postCallArguments; + private InstanceReference returnedValue; private long timeStampExit; - private TraceData exceptionThrown; + private InstanceReference exceptionThrown; private String[] stackTrace; private String confName; private String[] confDescriptors; @@ -19,13 +19,13 @@ public class Trace extends PartialTrace { @JsonCreator public Trace( @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") TraceData instance, - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") TraceData returnedValue, + @JsonProperty("instance") InstanceReference instance, + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") InstanceReference returnedValue, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") TraceData exceptionThrown, + @JsonProperty("exceptionThrown") InstanceReference exceptionThrown, @JsonProperty("stackTrace") String[] stackTrace, @JsonProperty("confName") String confName, @JsonProperty("confDescriptors") String[] confDescriptors, @@ -46,19 +46,19 @@ public Trace( this.parameterTypes = parameterTypes; } - public List getPostCallArguments() { + public List getPostCallArguments() { return postCallArguments; } - public void setPostCallArguments(List postCallArguments) { + public void setPostCallArguments(List postCallArguments) { this.postCallArguments = postCallArguments; } - public TraceData getReturnedValue() { + public InstanceReference getReturnedValue() { return returnedValue; } - public void setReturnedValue(TraceData returnedValue) { + public void setReturnedValue(InstanceReference returnedValue) { this.returnedValue = returnedValue; } @@ -70,11 +70,11 @@ public void setTimeStampExit(long timeStampExit) { this.timeStampExit = timeStampExit; } - public TraceData getExceptionThrown() { + public InstanceReference getExceptionThrown() { return exceptionThrown; } - public void setExceptionThrown(TraceData exceptionThrown) { + public void setExceptionThrown(InstanceReference exceptionThrown) { this.exceptionThrown = exceptionThrown; } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java deleted file mode 100644 index 50b34ee4..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TraceData.java +++ /dev/null @@ -1,11 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class TraceData { - public String fullyQualifiedTypeName; - public String[] Interfaces; - public String[] SuperClasses; - public String dataAsXml; - public String dataAsJson; - public int instanceId; - public InstanceReference instanceReference; -} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java index f5cab8a6..d6283a5e 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -4,7 +4,7 @@ import com.fasterxml.jackson.databind.SerializationFeature; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.instrumentation.models.TraceData; +import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import java.io.File; @@ -212,19 +212,19 @@ public static void main(String[] args) throws IOException { String methodName = trace.getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - TraceData instanceData = trace.getInstance(); + InstanceReference instanceData = trace.getInstance(); - boolean isInstanceCall = instanceData != null && !instanceData.fullyQualifiedTypeName.replace("$", ".").equals(methodName); + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference().getFullyQualifiedTypeName().replace("$", ".").equals(methodName); - TraceData returnData = trace.getReturnedValue(); + InstanceReference returnData = trace.getReturnedValue(); String returnVariableName = ""; if (returnData != null) { - returnVariableName = VariableStackHandler.getVariableName(returnData.instanceId); + returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); } String instanceVariableName = ""; if (instanceData != null) { - instanceVariableName = VariableStackHandler.getVariableName(instanceData.instanceId); + instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); } // TODO: Generate argument line. @@ -268,8 +268,8 @@ public static void main(String[] args) throws IOException { System.out.println(); if (trace.getIsConstructor()) { - if (!variableStackHandler.DoesVariableExist(instanceData.instanceId)) { - variableStackHandler.CreateNewVariable(instanceData.instanceId); + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); instanceVariableName = String.format("%s %s", methodName, instanceVariableName); } @@ -287,8 +287,8 @@ public static void main(String[] args) throws IOException { // If it does not exist, then we cannot generate this code // Log that, and comment out the code we would have generated. // And make sure we do not create a variable for the return value if a thing. - if (!variableStackHandler.DoesVariableExist(instanceData.instanceId)) { - String warnMessage = String.format("[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", i + 1, methodName, instanceData.instanceId, instanceData.fullyQualifiedTypeName); + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + String warnMessage = String.format("[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", i + 1, methodName, instanceData.getInstanceId(), instanceData.getClassReference().getFullyQualifiedTypeName()); // Log the warning to the current string builder and the console. System.out.println(warnMessage); @@ -303,18 +303,18 @@ public static void main(String[] args) throws IOException { } if (returnData != null) { - if (!variableStackHandler.DoesVariableExist(returnData.instanceId)) { + if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { if (!issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.instanceId); + variableStackHandler.CreateNewVariable(returnData.getInstanceId()); } else { - String warnMessage = String.format("[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", i + 1, returnData.instanceId); + String warnMessage = String.format("[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", i + 1, returnData.getInstanceId()); // Log the warning to the current string builder and the console. System.out.println(warnMessage); testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); } - String returnType = getCleanedVar(getCleanedType(returnData.fullyQualifiedTypeName)); + String returnType = getCleanedVar(getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); returnVariableName = String.format("%s %s", returnType, returnVariableName); } From 4df3fe3f5ec6942ca07e2ca58499c8a3473879a0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 10 Jul 2024 14:26:08 +0200 Subject: [PATCH 161/244] Add more data to traces (for generics) --- .../models/ClassReference.java | 14 +++++++- .../models/GenericReference.java | 34 +++++++++++++++++++ .../models/MethodReference.java | 11 ++++++ .../models/ClassReference.java | 15 +++++++- .../models/GenericReference.java | 26 ++++++++++++++ .../models/MethodReference.java | 9 +++++ .../models/ClassReference.java | 15 +++++++- .../models/GenericReference.java | 26 ++++++++++++++ .../models/MethodReference.java | 18 ++++++++++ 9 files changed, 165 insertions(+), 3 deletions(-) create mode 100644 Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java index abda2076..b9d7145d 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -1,17 +1,21 @@ package com.github.gilesi.instrumentation.models; import java.util.ArrayList; +import java.util.Arrays; public class ClassReference { private String fullyQualifiedTypeName; private ClassReference[] interfaces; private ClassReference superClass; + private GenericReference[] genericParameters; public ClassReference(Class clazz) { fullyQualifiedTypeName = clazz.getTypeName(); interfaces = getInterfaces(clazz); superClass = getSuperclass(clazz); + + genericParameters = Arrays.asList(clazz.getTypeParameters()).stream().map(t -> new GenericReference(t)).toArray(GenericReference[]::new); } public ClassReference() { @@ -48,7 +52,11 @@ public ClassReference[] getInterfaces() { public ClassReference getSuperClass() { return superClass; } - + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; } @@ -60,4 +68,8 @@ public void setInterfaces(ClassReference[] interfaces) { public void setSuperClass(ClassReference superClass) { this.superClass = superClass; } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java new file mode 100644 index 00000000..bd5d986b --- /dev/null +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java @@ -0,0 +1,34 @@ +package com.github.gilesi.instrumentation.models; + +import java.lang.reflect.TypeVariable; +import java.util.Arrays; + +public class GenericReference { + private String name; + private ClassReference[] classBounds; + + public GenericReference(TypeVariable typeVariable) { + name = typeVariable.getName(); + classBounds = Arrays.asList(typeVariable.getBounds()).stream().filter(t -> t instanceof Class).map(t -> new ClassReference((Class)t)).toArray(ClassReference[]::new); + } + + public GenericReference() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ClassReference[] getClassBounds() { + return classBounds; + } + + public void getClassBounds(ClassReference[] classBounds) { + this.classBounds = classBounds; + } +} diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index aa6a0d81..d55f15b2 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -12,6 +12,7 @@ public class MethodReference { private ClassReference[] parameterTypes; private ClassReference returnType; private boolean isConstructor; + private GenericReference[] genericParameters; public MethodReference(Executable executable) { methodSignature = getOriginName(executable); @@ -25,6 +26,8 @@ public MethodReference(Executable executable) { } else { isConstructor = false; } + + genericParameters = Arrays.asList(executable.getTypeParameters()).stream().map(t -> new GenericReference(t)).toArray(GenericReference[]::new); } public MethodReference() { @@ -74,6 +77,10 @@ public boolean getIsConstructor() { return isConstructor; } + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -89,4 +96,8 @@ public void setReturnType(ClassReference returnType) { public void setIsConstructor(boolean isConstructor) { this.isConstructor = isConstructor; } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java index b4f67b0d..9e25ea02 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -4,6 +4,11 @@ public class ClassReference { private String fullyQualifiedTypeName; private ClassReference[] interfaces; private ClassReference superClass; + private GenericReference[] genericParameters; + + public ClassReference() { + + } public String getFullyQualifiedTypeName() { return fullyQualifiedTypeName; @@ -16,7 +21,11 @@ public ClassReference[] getInterfaces() { public ClassReference getSuperClass() { return superClass; } - + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; } @@ -28,4 +37,8 @@ public void setInterfaces(ClassReference[] interfaces) { public void setSuperClass(ClassReference superClass) { this.superClass = superClass; } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java new file mode 100644 index 00000000..10eca61e --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java @@ -0,0 +1,26 @@ +package com.github.gilesi.instrumentation.models; + +public class GenericReference { + private String name; + private ClassReference[] classBounds; + + public GenericReference() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ClassReference[] getClassBounds() { + return classBounds; + } + + public void getClassBounds(ClassReference[] classBounds) { + this.classBounds = classBounds; + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index e972cfcc..21eb673a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -5,6 +5,7 @@ public class MethodReference { private ClassReference[] parameterTypes; private ClassReference returnType; private boolean isConstructor; + private GenericReference[] genericParameters; public MethodReference() { @@ -26,6 +27,10 @@ public boolean getIsConstructor() { return isConstructor; } + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -41,4 +46,8 @@ public void setReturnType(ClassReference returnType) { public void setIsConstructor(boolean isConstructor) { this.isConstructor = isConstructor; } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java index b4f67b0d..9e25ea02 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -4,6 +4,11 @@ public class ClassReference { private String fullyQualifiedTypeName; private ClassReference[] interfaces; private ClassReference superClass; + private GenericReference[] genericParameters; + + public ClassReference() { + + } public String getFullyQualifiedTypeName() { return fullyQualifiedTypeName; @@ -16,7 +21,11 @@ public ClassReference[] getInterfaces() { public ClassReference getSuperClass() { return superClass; } - + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { this.fullyQualifiedTypeName = fullyQualifiedTypeName; } @@ -28,4 +37,8 @@ public void setInterfaces(ClassReference[] interfaces) { public void setSuperClass(ClassReference superClass) { this.superClass = superClass; } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java new file mode 100644 index 00000000..10eca61e --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java @@ -0,0 +1,26 @@ +package com.github.gilesi.instrumentation.models; + +public class GenericReference { + private String name; + private ClassReference[] classBounds; + + public GenericReference() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ClassReference[] getClassBounds() { + return classBounds; + } + + public void getClassBounds(ClassReference[] classBounds) { + this.classBounds = classBounds; + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index bc3c8f54..21eb673a 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -4,6 +4,8 @@ public class MethodReference { private String methodSignature; private ClassReference[] parameterTypes; private ClassReference returnType; + private boolean isConstructor; + private GenericReference[] genericParameters; public MethodReference() { @@ -21,6 +23,14 @@ public ClassReference getReturnType() { return returnType; } + public boolean getIsConstructor() { + return isConstructor; + } + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -32,4 +42,12 @@ public void setParameterTypes(ClassReference[] parameterTypes) { public void setReturnType(ClassReference returnType) { this.returnType = returnType; } + + public void setIsConstructor(boolean isConstructor) { + this.isConstructor = isConstructor; + } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } } From fa1efb7c72bfe70b38844527876511870a1aeeca Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 10 Jul 2024 14:39:06 +0200 Subject: [PATCH 162/244] Add more generic info --- .../models/ClassReference.java | 8 ++--- .../models/GenericReference.java | 4 +-- .../models/MethodReference.java | 30 ++++++++++++++----- .../models/MethodReference.java | 9 ++++++ .../models/MethodReference.java | 9 ++++++ 5 files changed, 47 insertions(+), 13 deletions(-) diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java index b9d7145d..f7fd092e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -4,10 +4,10 @@ import java.util.Arrays; public class ClassReference { - private String fullyQualifiedTypeName; - private ClassReference[] interfaces; - private ClassReference superClass; - private GenericReference[] genericParameters; + private String fullyQualifiedTypeName = null; + private ClassReference[] interfaces = null; + private ClassReference superClass = null; + private GenericReference[] genericParameters = null; public ClassReference(Class clazz) { fullyQualifiedTypeName = clazz.getTypeName(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java index bd5d986b..fc061465 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java @@ -4,8 +4,8 @@ import java.util.Arrays; public class GenericReference { - private String name; - private ClassReference[] classBounds; + private String name = null; + private ClassReference[] classBounds = null; public GenericReference(TypeVariable typeVariable) { name = typeVariable.getName(); diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index d55f15b2..5069e434 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -4,15 +4,17 @@ import java.lang.reflect.Executable; import java.lang.reflect.Method; import java.util.Arrays; +import java.lang.reflect.Type; import com.github.gilesi.instrumentation.Logger; public class MethodReference { - private String methodSignature; - private ClassReference[] parameterTypes; - private ClassReference returnType; - private boolean isConstructor; - private GenericReference[] genericParameters; + private String methodSignature = null; + private ClassReference[] parameterTypes = null; + private ClassReference returnType = null; + private boolean isConstructor = false; + private GenericReference[] genericParameters = null; + private ClassReference genericReturn = null; public MethodReference(Executable executable) { methodSignature = getOriginName(executable); @@ -20,8 +22,14 @@ public MethodReference(Executable executable) { if (executable instanceof Method) { returnType = new ClassReference(((Method)executable).getReturnType()); isConstructor = false; - } else if (executable instanceof Constructor) { - returnType = new ClassReference(((Constructor)executable).getDeclaringClass()); + if (((Method)executable).getReturnType() != null) { + Type genericReturnType = ((Method)executable).getGenericReturnType(); + if (genericReturnType instanceof Class) { + genericReturn = new ClassReference((Class)genericReturnType); + } + } + } else if (executable instanceof Constructor) { + returnType = new ClassReference(((Constructor)executable).getDeclaringClass()); isConstructor = true; } else { isConstructor = false; @@ -81,6 +89,10 @@ public GenericReference[] getGenericParameters() { return genericParameters; } + public ClassReference getGenericReturn() { + return genericReturn; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -100,4 +112,8 @@ public void setIsConstructor(boolean isConstructor) { public void setGenericParameters(GenericReference[] genericParameters) { this.genericParameters = genericParameters; } + + public void setGenericReturn(ClassReference genericReturn) { + this.genericReturn = genericReturn; + } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index 21eb673a..94dc8eda 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -6,6 +6,7 @@ public class MethodReference { private ClassReference returnType; private boolean isConstructor; private GenericReference[] genericParameters; + private ClassReference genericReturn; public MethodReference() { @@ -31,6 +32,10 @@ public GenericReference[] getGenericParameters() { return genericParameters; } + public ClassReference getGenericReturn() { + return genericReturn; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -50,4 +55,8 @@ public void setIsConstructor(boolean isConstructor) { public void setGenericParameters(GenericReference[] genericParameters) { this.genericParameters = genericParameters; } + + public void setGenericReturn(ClassReference genericReturn) { + this.genericReturn = genericReturn; + } } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java index 21eb673a..94dc8eda 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -6,6 +6,7 @@ public class MethodReference { private ClassReference returnType; private boolean isConstructor; private GenericReference[] genericParameters; + private ClassReference genericReturn; public MethodReference() { @@ -31,6 +32,10 @@ public GenericReference[] getGenericParameters() { return genericParameters; } + public ClassReference getGenericReturn() { + return genericReturn; + } + public void setMethodSignature(String methodSignature) { this.methodSignature = methodSignature; } @@ -50,4 +55,8 @@ public void setIsConstructor(boolean isConstructor) { public void setGenericParameters(GenericReference[] genericParameters) { this.genericParameters = genericParameters; } + + public void setGenericReturn(ClassReference genericReturn) { + this.genericReturn = genericReturn; + } } From 0342484b97c52c0077deb40e72818ab30b7f513a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 14:36:28 +0200 Subject: [PATCH 163/244] Implement variable generator and return assertions (without proper types for now) --- .../instrumentation/models/PartialTrace.java | 22 --- .../gilesi/instrumentation/models/Trace.java | 26 +-- .../gilesi/testgenerator/ArgumentUtils.java | 163 ++++++++++++++++++ .../com/github/gilesi/testgenerator/Main.java | 36 ++-- .../testgenerator/SerializationUtils.java | 147 ++++++++++++++++ .../exceptions/SerializationException.java | 7 + 6 files changed, 344 insertions(+), 57 deletions(-) create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java index fbb91824..d2a7d482 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -6,8 +6,6 @@ import java.util.List; public class PartialTrace { - private String methodSignature; - private InstanceReference instance; private List preCallArguments; private long timeStampEntry; private InstanceReference instanceReference; @@ -15,36 +13,16 @@ public class PartialTrace { @JsonCreator public PartialTrace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") InstanceReference instance, @JsonProperty("preCallArguments") List preCallArguments, @JsonProperty("timeStampEntry") long timeStampEntry, @JsonProperty("instanceReference") InstanceReference instanceReference, @JsonProperty("methodReference") MethodReference methodReference) { - this.methodSignature = methodSignature; - this.instance = instance; this.preCallArguments = preCallArguments; this.timeStampEntry = timeStampEntry; this.instanceReference = instanceReference; this.methodReference = methodReference; } - public String getMethodSignature() { - return methodSignature; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public InstanceReference getInstance() { - return instance; - } - - public void setInstance(InstanceReference instance) { - this.instance = instance; - } - public List getPreCallArguments() { return preCallArguments; } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java index 6a6571cb..9dee5a0a 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -13,13 +13,9 @@ public class Trace extends PartialTrace { private String[] stackTrace; private String confName; private String[] confDescriptors; - private boolean isConstructor; - private String[] parameterTypes; @JsonCreator public Trace( - @JsonProperty("methodSignature") String methodSignature, - @JsonProperty("instance") InstanceReference instance, @JsonProperty("preCallArguments") List preCallArguments, @JsonProperty("postCallArguments") List postCallArguments, @JsonProperty("returnedValue") InstanceReference returnedValue, @@ -29,11 +25,9 @@ public Trace( @JsonProperty("stackTrace") String[] stackTrace, @JsonProperty("confName") String confName, @JsonProperty("confDescriptors") String[] confDescriptors, - @JsonProperty("isConstructor") boolean isConstructor, - @JsonProperty("parameterTypes") String[] parameterTypes, @JsonProperty("instanceReference") InstanceReference instanceReference, @JsonProperty("methodReference") MethodReference methodReference) { - super(methodSignature, instance, preCallArguments, timeStampEntry, instanceReference, methodReference); + super(preCallArguments, timeStampEntry, instanceReference, methodReference); this.postCallArguments = postCallArguments; this.returnedValue = returnedValue; @@ -42,8 +36,6 @@ public Trace( this.stackTrace = stackTrace; this.confName = confName; this.confDescriptors = confDescriptors; - this.isConstructor = isConstructor; - this.parameterTypes = parameterTypes; } public List getPostCallArguments() { @@ -101,20 +93,4 @@ public String[] getConfDescriptors() { public void setConfDescriptors(String[] confDescriptors) { this.confDescriptors = confDescriptors; } - - public boolean getIsConstructor() { - return isConstructor; - } - - public void setIsConstructor(boolean isConstructor) { - this.isConstructor = isConstructor; - } - - public String[] getParameterTypes() { - return parameterTypes; - } - - public void setParameterTypes(String[] parameterTypes) { - this.parameterTypes = parameterTypes; - } } \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java new file mode 100644 index 00000000..0a7a902a --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -0,0 +1,163 @@ +package com.github.gilesi.testgenerator; + +import java.util.ArrayList; +import java.util.List; + +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.exceptions.SerializationException; + +public class ArgumentUtils { + private static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { + if (arg.getValueAsXmlString() != null) { + if (arg.getValueAsXmlString().equals("null")) { + return arg.getValueAsXmlString(); + } + String dataLine = SerializationUtils.serializableDataToJava(arg); + if (failOnLambdas && arg.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } + + return dataLine; + } else if (variableStackHandler.DoesVariableExist(arg.getInstanceId())) { + return VariableStackHandler.getVariableName(arg.getInstanceId()); + } else if (failOnLambdas) { + throw new SerializationException("We cannot serialize this!"); + } else { + return "// Unserializable data with instance id: " + arg.getInstanceId(); + } + } + + private static String getDataVariableDeclaration(InstanceReference serializableData, VariableStackHandler variableStackHandler) throws SerializationException { + if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { + return VariableStackHandler.getVariableName(serializableData.getInstanceId()); + } else { + String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + if (returnType.contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); + String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); + //if (serializableData.getValueAsXmlString() == null || serializableData.getValueAsXmlString().equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + //} + //return "%s %s".formatted("var", instanceVariableName); + } + } + + private static String getDataVariableDeclaration2(InstanceReference serializableData, VariableStackHandler variableStackHandler) { + if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { + return VariableStackHandler.getVariableName(serializableData.getInstanceId()); + } else { + String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); + String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); + //if (serializableData.getValueAsXmlString().equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + //} + //return "%s %s".formatted("var", instanceVariableName); + } + } + + public static class ArgLineGenerateResult { + public boolean Success; + public String line; + + public ArgLineGenerateResult(boolean Success, String line) { + this.Success = Success; + this.line = line; + } + } + + public static ArgLineGenerateResult GenerateArgLine(StringBuilder stringBuilder, Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { + List preCallArguments = new ArrayList<>(); + List variableList = new ArrayList<>(); + + boolean commentItAll = false; + + for (InstanceReference preCallArgument : methodTrace.getPreCallArguments()) { + if (preCallArgument.getInstanceId() < 0 && preCallArgument.getClassReference().getFullyQualifiedTypeName().equals("Object") && preCallArgument.getValueAsXmlString().equals("null")) { + preCallArguments.add("null"); + continue; + } + + String argumentValue; + try { + argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, true); + } + catch (SerializationException e) { + argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, false); + commentItAll = true; + } + + String argumentVariable; + try { + argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler); + } + catch (SerializationException e) { + argumentVariable = getDataVariableDeclaration2(preCallArgument, variableStackHandler); + commentItAll = true; + // todo: problem here... + } + + String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); + + // Has to be defined already so no need to check here + preCallArguments.add(VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + + // Define the variable before the method + variableList.add("%s;".formatted(argumentDeclaration)); + } + + String argumentParameters = String.join(", ", preCallArguments); + + String code = String.join("\n", variableList); + if (commentItAll) { + code = "/* " + code + " */"; + } + + stringBuilder.append(code); + + return new ArgLineGenerateResult(!commentItAll, argumentParameters); + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java index d6283a5e..d38bf861 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -5,6 +5,7 @@ import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import java.io.File; @@ -29,7 +30,7 @@ private static int GetTraceNumber(Path i) { } private static ArrayList readTraces(String traceXmlFolder) throws IOException { - ArrayList traces = new ArrayList(); + ArrayList traces = new ArrayList<>(); List traceFiles = Files.list(Path.of(traceXmlFolder)).sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); @@ -209,10 +210,10 @@ public static void main(String[] args) throws IOException { Trace trace = methodTraces.get(i); try { - String methodName = trace.getMethodSignature().split("\\(")[0]; + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - InstanceReference instanceData = trace.getInstance(); + InstanceReference instanceData = trace.getInstanceReference(); boolean isInstanceCall = instanceData != null && !instanceData.getClassReference().getFullyQualifiedTypeName().replace("$", ".").equals(methodName); @@ -227,8 +228,8 @@ public static void main(String[] args) throws IOException { instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); } - // TODO: Generate argument line. - String argumentLine = ""; + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(testMethodStringBuilder, trace, variableStackHandler); + String argumentLine = argLineResult.line; for (String descr : trace.getConfDescriptors()) { int startArg = descr.indexOf("("); @@ -267,13 +268,18 @@ public static void main(String[] args) throws IOException { } System.out.println(); - if (trace.getIsConstructor()) { + if (trace.getMethodReference().getIsConstructor()) { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); instanceVariableName = String.format("%s %s", methodName, instanceVariableName); } - testMethodStringBuilder.append(String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine)); + String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); + if (argLineResult.Success) { + testMethodStringBuilder.append(callLine); + } else { + testMethodStringBuilder.append("// " + callLine); + } } else { StringBuilder callStringBuilder = new StringBuilder(); @@ -318,9 +324,19 @@ public static void main(String[] args) throws IOException { returnVariableName = String.format("%s %s", returnType, returnVariableName); } - callStringBuilder.append(String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine)); + String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); + if (argLineResult.Success) { + callStringBuilder.append(callLine); + } else { + callStringBuilder.append("// " + callLine); + } } else { - callStringBuilder.append(String.format("%s(%s);\n", methodName, argumentLine)); + String callLine = String.format("%s(%s);\n", methodName, argumentLine); + if (argLineResult.Success) { + callStringBuilder.append(callLine); + } else { + callStringBuilder.append("// " + callLine); + } } // Append the method call to the current string builder. @@ -339,7 +355,7 @@ public static void main(String[] args) throws IOException { e.printStackTrace(); writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodSignature())); + stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); } } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java new file mode 100644 index 00000000..8f1b0078 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -0,0 +1,147 @@ +package com.github.gilesi.testgenerator; + +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.testgenerator.exceptions.SerializationException; +import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; +import org.apache.commons.text.StringEscapeUtils; + +import java.util.ArrayList; +import java.util.List; + +public class SerializationUtils { + private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static String getCleanedType(String FQN) { + int currentCharacterIndex = 0; + char currentCharacter = FQN.charAt(currentCharacterIndex); + while (currentCharacter == '[') { + currentCharacter = FQN.charAt(++currentCharacterIndex); + } + + if (((currentCharacter == 'I' || currentCharacter == 'V' || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + (currentCharacter == 'L' && FQN.endsWith(";"))) { + try { + return JvmTypeToLangType(FQN).replace("$", "."); + } catch (UnsupportedJavaPrimitiveTypeException ignored) { + + } + } + return FQN.replace("$", "."); + } + + public static String serializableDataToJava(InstanceReference serializableData) throws SerializationException { + String valueToBeEqualTo = serializableData.getValueAsXmlString(); + String FQN = getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + + if (!FQN.equals("java.lang.Integer") && + !FQN.equals("java.lang.Void") && + !FQN.equals("java.lang.Boolean") && + !FQN.equals("java.lang.Byte") && + !FQN.equals("java.lang.Character") && + !FQN.equals("java.lang.Short") && + !FQN.equals("java.lang.Double") && + !FQN.equals("java.lang.Float") && + !FQN.equals("java.lang.Long") && + !FQN.equals("java.lang.String")) { + + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: Check why this still fails + int maxStringSize = 1024; + + if (serializableData.getValueAsXmlString().length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start = 0; start < serializableData.getValueAsXmlString().length(); start += maxStringSize) { + int end = start + maxStringSize; + if (start + maxStringSize > serializableData.getValueAsXmlString().length()) { + end = serializableData.getValueAsXmlString().length(); + } + + String sectionOfDataAsXml = "SNIP";//serializableData.getValueAsXmlString().substring(start, end); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + String finalEscapedValue = String.join(" + ", sectionList.toArray(String[]::new)); + + valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); + } else { + // Casting is not needed if we only use this with variable assignments that are strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + } + } + else { + int start = valueToBeEqualTo.indexOf(">"); + int end = valueToBeEqualTo.lastIndexOf(" valueToBeEqualTo.length() - 1 - 3) { + throw new SerializationException("Malformed XML data"); + } + + valueToBeEqualTo = valueToBeEqualTo.substring(start + 1, end); + + if (FQN.equals("java.lang.Character")) { + valueToBeEqualTo = "'%s'".formatted(valueToBeEqualTo); + if (valueToBeEqualTo.equals("''")) { + valueToBeEqualTo = "java.lang.Character.MIN_VALUE"; + } + } + else if (FQN.equals("java.lang.String")) { + //int maxStringSize = (int) Math.pow(2, 16); + // TODO: Check why this still fails + int maxStringSize = 1024; + + if (valueToBeEqualTo.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueToBeEqualTo.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueToBeEqualTo.length()) { + end2 = valueToBeEqualTo.length(); + } + + String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueToBeEqualTo = String.join(" + ", sectionList.toArray(String[]::new)); + } else { + valueToBeEqualTo = "\"%s\"".formatted(StringEscapeUtils.escapeJava(valueToBeEqualTo)); + } + } + else if (FQN.equals("java.lang.Float")) { + valueToBeEqualTo = "%sF".formatted(valueToBeEqualTo); + } + else if (FQN.equals("java.lang.Long")) { + valueToBeEqualTo = "%sL".formatted(valueToBeEqualTo); + } + } + + return valueToBeEqualTo; + } +} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java new file mode 100644 index 00000000..e502a6b1 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java @@ -0,0 +1,7 @@ +package com.github.gilesi.testgenerator.exceptions; + +public class SerializationException extends Exception { + public SerializationException(String message) { + super(message); + } +} From 47606de4662bcab00bb26ace4cad6a0d580d7f84 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 14:50:56 +0200 Subject: [PATCH 164/244] Cleanup a tiny bit arg handling --- .../gilesi/testgenerator/ArgumentUtils.java | 32 ++++++++----------- .../com/github/gilesi/testgenerator/Main.java | 23 +++++++++++-- 2 files changed, 35 insertions(+), 20 deletions(-) diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java index 0a7a902a..48928c89 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -10,10 +10,12 @@ public class ArgumentUtils { private static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { if (arg.getValueAsXmlString() != null) { - if (arg.getValueAsXmlString().equals("null")) { - return arg.getValueAsXmlString(); + if (arg.getIsNull()) { + return "null"; } + String dataLine = SerializationUtils.serializableDataToJava(arg); + if (failOnLambdas && arg.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -101,22 +103,24 @@ private static String getDataVariableDeclaration2(InstanceReference serializable public static class ArgLineGenerateResult { public boolean Success; - public String line; + public String argumentsForMethodCall; + public List variableList; - public ArgLineGenerateResult(boolean Success, String line) { + public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { this.Success = Success; - this.line = line; + this.argumentsForMethodCall = argumentsForMethodCall; + this.variableList = variableList; } } - public static ArgLineGenerateResult GenerateArgLine(StringBuilder stringBuilder, Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { + public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { List preCallArguments = new ArrayList<>(); List variableList = new ArrayList<>(); boolean commentItAll = false; for (InstanceReference preCallArgument : methodTrace.getPreCallArguments()) { - if (preCallArgument.getInstanceId() < 0 && preCallArgument.getClassReference().getFullyQualifiedTypeName().equals("Object") && preCallArgument.getValueAsXmlString().equals("null")) { + if (preCallArgument.getIsNull()) { preCallArguments.add("null"); continue; } @@ -149,15 +153,7 @@ public static ArgLineGenerateResult GenerateArgLine(StringBuilder stringBuilder, variableList.add("%s;".formatted(argumentDeclaration)); } - String argumentParameters = String.join(", ", preCallArguments); - - String code = String.join("\n", variableList); - if (commentItAll) { - code = "/* " + code + " */"; - } - - stringBuilder.append(code); - - return new ArgLineGenerateResult(!commentItAll, argumentParameters); + // Return if we succeeded, the list of stuff to pass as method arguments, and the list of variable declarations to add if any + return new ArgLineGenerateResult(!commentItAll, String.join(", ", preCallArguments), variableList); } -} +} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java index d38bf861..efdac484 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -228,8 +228,8 @@ public static void main(String[] args) throws IOException { instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); } - ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(testMethodStringBuilder, trace, variableStackHandler); - String argumentLine = argLineResult.line; + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); + String argumentLine = argLineResult.argumentsForMethodCall; for (String descr : trace.getConfDescriptors()) { int startArg = descr.indexOf("("); @@ -276,8 +276,14 @@ public static void main(String[] args) throws IOException { String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("%s\n", str)); + } testMethodStringBuilder.append(callLine); } else { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("// %s\n", str)); + } testMethodStringBuilder.append("// " + callLine); } } else { @@ -326,15 +332,27 @@ public static void main(String[] args) throws IOException { String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } callStringBuilder.append(callLine); } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } callStringBuilder.append("// " + callLine); } } else { String callLine = String.format("%s(%s);\n", methodName, argumentLine); if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } callStringBuilder.append(callLine); } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } callStringBuilder.append("// " + callLine); } } @@ -387,6 +405,7 @@ public static void main(String[] args) throws IOException { stringBuilder.append("}\n"); stringBuilder.append("\n"); + System.out.println(classOutputPath); Files.deleteIfExists(classOutputPath); Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); } From 3174f8ef9c4446abe97f1e4d5f7aacee39add05b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 15:06:48 +0200 Subject: [PATCH 165/244] Enable assertions --- .../gilesi/testgenerator/ArgumentUtils.java | 2 +- .../gilesi/testgenerator/AssertionUtils.java | 133 ++++++++++++++++++ .../com/github/gilesi/testgenerator/Main.java | 57 +++++++- 3 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java index 48928c89..7a3163e3 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -8,7 +8,7 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { - private static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { + public static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { if (arg.getValueAsXmlString() != null) { if (arg.getIsNull()) { return "null"; diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java new file mode 100644 index 00000000..cc5a0720 --- /dev/null +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java @@ -0,0 +1,133 @@ +package com.github.gilesi.testgenerator; + +import java.util.ArrayList; +import java.util.List; + +import org.apache.commons.text.StringEscapeUtils; + +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.exceptions.SerializationException; + +public class AssertionUtils { + private static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; + + public static List traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { + List argList = new ArrayList<>(); + + for (InstanceReference traceData : methodTrace.getPostCallArguments()) { + if (traceData == null) { + // argList.add("null"); + continue; + } + + if (traceData.getIsNull() + && traceData.getClassReference().getFullyQualifiedTypeName().equals("Object") + && traceData.getValueAsXmlString().equals("null")) { + // argList.add("null"); + continue; + } + + // We return a value that we managed to serialize + String assertionCodeLine; + try { + assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, + USE_ALTERNATIVE_ASSERTION_MODE); + } catch (SerializationException e) { + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, + USE_ALTERNATIVE_ASSERTION_MODE)); + } + argList.add(assertionCodeLine); + } + + return argList; + } + + private static String getReturnAssertionCodeLine(InstanceReference traceData, + VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) + throws SerializationException { + int instanceId = traceData.getInstanceId(); + String dataAsXml = traceData.getValueAsXmlString(); + + if (dataAsXml != null) { + String instanceVarName = VariableStackHandler.getVariableName(instanceId); + + if (dataAsXml.equals("null")) { + return "assertEquals(null, %s);".formatted(instanceVarName); + } + + if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } + + String assertionLine; + + if (useAltAssertionMode) { + String valueAsCode = ArgumentUtils.serializableDataToCode(traceData, variableStackHandler, true); + + if (valueAsCode.endsWith("[].class)")) { + assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } else { + assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + } + } else { + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); + + // int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueAsCode.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = "SNIP";// valueToBeEqualTo.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueAsCode = String.join("+", sectionList.toArray(String[]::new)); + } + + assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); + } + + return assertionLine; + } else if (variableStackHandler.DoesVariableExist(instanceId)) { + return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));" + .formatted(VariableStackHandler.getVariableName(instanceId)); + } else if (failOnLambdas) { + throw new SerializationException("We cannot serialize this!"); + } else { + return "// Unserializable data with instance id: %d".formatted(traceData.getInstanceId()); + } + } + + public static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) + throws SerializationException { + String cleanedMethodName = methodTrace.getMethodReference().getMethodSignature().split("\\(")[0]; + cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1].replace("$", "."); + + InstanceReference traceData = methodTrace.getReturnedValue(); + + if (!methodTrace.getMethodReference().getIsConstructor() && traceData != null) { + String assertionCodeLine; + try { + assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, + USE_ALTERNATIVE_ASSERTION_MODE); + } catch (SerializationException e) { + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, + USE_ALTERNATIVE_ASSERTION_MODE)); + } + return assertionCodeLine; + } + + return null; + } +} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java index efdac484..46b08199 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -205,7 +205,7 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < methodTraces.size(); i++) { - System.out.println("==========================="); + //System.out.println("==========================="); Trace trace = methodTraces.get(i); @@ -230,8 +230,9 @@ public static void main(String[] args) throws IOException { ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); String argumentLine = argLineResult.argumentsForMethodCall; + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, variableStackHandler); - for (String descr : trace.getConfDescriptors()) { + /*for (String descr : trace.getConfDescriptors()) { int startArg = descr.indexOf("("); int endArg = descr.lastIndexOf(")"); @@ -266,7 +267,7 @@ public static void main(String[] args) throws IOException { System.out.println("Returns: " + returnValue); } } - System.out.println(); + System.out.println();*/ if (trace.getMethodReference().getIsConstructor()) { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { @@ -275,16 +276,35 @@ public static void main(String[] args) throws IOException { } String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (argLineResult.Success) { for (String str : argLineResult.variableList) { testMethodStringBuilder.append(String.format("%s\n", str)); } + testMethodStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append(varAssert + "\n"); + } } else { for (String str : argLineResult.variableList) { testMethodStringBuilder.append(String.format("// %s\n", str)); } + testMethodStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append("// " + varAssert + "\n"); + } } } else { StringBuilder callStringBuilder = new StringBuilder(); @@ -331,16 +351,35 @@ public static void main(String[] args) throws IOException { } String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (argLineResult.Success) { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("%s\n", str)); } + callStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } } else { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("// %s\n", str)); } + callStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } } } else { String callLine = String.format("%s(%s);\n", methodName, argumentLine); @@ -348,12 +387,22 @@ public static void main(String[] args) throws IOException { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("%s\n", str)); } + callStringBuilder.append(callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } } else { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("// %s\n", str)); } + callStringBuilder.append("// " + callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } } } @@ -378,7 +427,7 @@ public static void main(String[] args) throws IOException { } String padding = "\t\t"; - String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString().substring(0, testMethodStringBuilder.length() - 2).replace("\n", String.format("\n%s", padding))); + String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString().substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); stringBuilder.append(String.format("%s\n\t}\n", paddedString)); stringBuilder.append(""" From c5f723ce025ef613b6b4630366f309f573b10aa0 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 15:25:51 +0200 Subject: [PATCH 166/244] Improvements on code generation --- .../gilesi/testgenerator/ArgumentUtils.java | 59 ++++++---- .../gilesi/testgenerator/AssertionUtils.java | 60 ++++++---- .../com/github/gilesi/testgenerator/Main.java | 110 ++++++++++-------- .../testgenerator/SerializationUtils.java | 49 ++++---- 4 files changed, 163 insertions(+), 115 deletions(-) diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java index 7a3163e3..3fcf93f2 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -3,18 +3,20 @@ import java.util.ArrayList; import java.util.List; +import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { - public static String serializableDataToCode(InstanceReference arg, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { + public static String serializableDataToCode(InstanceReference arg, ClassReference argClass, + VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { if (arg.getValueAsXmlString() != null) { if (arg.getIsNull()) { return "null"; } - String dataLine = SerializationUtils.serializableDataToJava(arg); + String dataLine = SerializationUtils.serializableDataToJava(arg, argClass); if (failOnLambdas && arg.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); @@ -30,11 +32,13 @@ public static String serializableDataToCode(InstanceReference arg, VariableStack } } - private static String getDataVariableDeclaration(InstanceReference serializableData, VariableStackHandler variableStackHandler) throws SerializationException { + private static String getDataVariableDeclaration(InstanceReference serializableData, + VariableStackHandler variableStackHandler) throws SerializationException { if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { return VariableStackHandler.getVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + String returnType = SerializationUtils + .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); if (returnType.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } @@ -60,18 +64,21 @@ private static String getDataVariableDeclaration(InstanceReference serializableD variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); - //if (serializableData.getValueAsXmlString() == null || serializableData.getValueAsXmlString().equals("null")) { - return "%s %s".formatted(returnType, instanceVariableName); - //} - //return "%s %s".formatted("var", instanceVariableName); + // if (serializableData.getValueAsXmlString() == null || + // serializableData.getValueAsXmlString().equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + // } + // return "%s %s".formatted("var", instanceVariableName); } } - private static String getDataVariableDeclaration2(InstanceReference serializableData, VariableStackHandler variableStackHandler) { + private static String getDataVariableDeclaration2(InstanceReference serializableData, + VariableStackHandler variableStackHandler) { if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { return VariableStackHandler.getVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils.getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + String returnType = SerializationUtils + .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); try { var el = returnType.split("\\."); @@ -94,10 +101,10 @@ private static String getDataVariableDeclaration2(InstanceReference serializable variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); - //if (serializableData.getValueAsXmlString().equals("null")) { - return "%s %s".formatted(returnType, instanceVariableName); - //} - //return "%s %s".formatted("var", instanceVariableName); + // if (serializableData.getValueAsXmlString().equals("null")) { + return "%s %s".formatted(returnType, instanceVariableName); + // } + // return "%s %s".formatted("var", instanceVariableName); } } @@ -113,32 +120,37 @@ public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, Lis } } - public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { + public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableStackHandler variableStackHandler) + throws SerializationException { List preCallArguments = new ArrayList<>(); List variableList = new ArrayList<>(); boolean commentItAll = false; - for (InstanceReference preCallArgument : methodTrace.getPreCallArguments()) { + for (int i = 0; i < methodTrace.getPreCallArguments().size(); i++) { + InstanceReference preCallArgument = methodTrace.getPreCallArguments().get(i); + if (preCallArgument.getIsNull()) { preCallArguments.add("null"); continue; } + ClassReference correspondingMethodArg = methodTrace.getMethodReference().getParameterTypes()[i]; + String argumentValue; try { - argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, true); - } - catch (SerializationException e) { - argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, false); + argumentValue = serializableDataToCode(preCallArgument, correspondingMethodArg, variableStackHandler, + true); + } catch (SerializationException e) { + argumentValue = serializableDataToCode(preCallArgument, correspondingMethodArg, variableStackHandler, + false); commentItAll = true; } String argumentVariable; try { argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler); - } - catch (SerializationException e) { + } catch (SerializationException e) { argumentVariable = getDataVariableDeclaration2(preCallArgument, variableStackHandler); commentItAll = true; // todo: problem here... @@ -153,7 +165,8 @@ public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableS variableList.add("%s;".formatted(argumentDeclaration)); } - // Return if we succeeded, the list of stuff to pass as method arguments, and the list of variable declarations to add if any + // Return if we succeeded, the list of stuff to pass as method arguments, and + // the list of variable declarations to add if any return new ArgLineGenerateResult(!commentItAll, String.join(", ", preCallArguments), variableList); } } \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java index cc5a0720..cefb7790 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java @@ -5,6 +5,7 @@ import org.apache.commons.text.StringEscapeUtils; +import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.exceptions.SerializationException; @@ -12,29 +13,36 @@ public class AssertionUtils { private static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; - public static List traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { + public static List traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) + throws SerializationException { List argList = new ArrayList<>(); - for (InstanceReference traceData : methodTrace.getPostCallArguments()) { - if (traceData == null) { + for (int i = 0; i < methodTrace.getPostCallArguments().size(); i++) { + InstanceReference postCallArgument = methodTrace.getPostCallArguments().get(i); + + if (postCallArgument == null) { // argList.add("null"); continue; } - if (traceData.getIsNull() - && traceData.getClassReference().getFullyQualifiedTypeName().equals("Object") - && traceData.getValueAsXmlString().equals("null")) { + if (postCallArgument.getIsNull() + && postCallArgument.getClassReference().getFullyQualifiedTypeName().equals("Object") + && postCallArgument.getValueAsXmlString().equals("null")) { // argList.add("null"); continue; } + ClassReference correspondingMethodArg = methodTrace.getMethodReference().getParameterTypes()[i]; + // We return a value that we managed to serialize String assertionCodeLine; try { - assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, + assertionCodeLine = getReturnAssertionCodeLine(postCallArgument, correspondingMethodArg, + variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(postCallArgument, + correspondingMethodArg, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); } argList.add(assertionCodeLine); @@ -43,27 +51,30 @@ public static List traceArgumentsToAssert(Trace methodTrace, VariableSta return argList; } - private static String getReturnAssertionCodeLine(InstanceReference traceData, + private static String getReturnAssertionCodeLine(InstanceReference returnedValueInstance, + ClassReference returnClassReference, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws SerializationException { - int instanceId = traceData.getInstanceId(); - String dataAsXml = traceData.getValueAsXmlString(); + int returnedValueInstanceId = returnedValueInstance.getInstanceId(); + String returnedValueDataAsXml = returnedValueInstance.getValueAsXmlString(); - if (dataAsXml != null) { - String instanceVarName = VariableStackHandler.getVariableName(instanceId); + if (returnedValueDataAsXml != null) { + String instanceVarName = VariableStackHandler.getVariableName(returnedValueInstanceId); - if (dataAsXml.equals("null")) { + if (returnedValueDataAsXml.equals("null")) { return "assertEquals(null, %s);".formatted(instanceVarName); } - if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { + if (failOnLambdas + && returnedValueInstance.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } String assertionLine; if (useAltAssertionMode) { - String valueAsCode = ArgumentUtils.serializableDataToCode(traceData, variableStackHandler, true); + String valueAsCode = ArgumentUtils.serializableDataToCode(returnedValueInstance, + returnClassReference, variableStackHandler, true); if (valueAsCode.endsWith("[].class)")) { assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); @@ -71,7 +82,7 @@ private static String getReturnAssertionCodeLine(InstanceReference traceData, assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); } } else { - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(returnedValueDataAsXml)); // int maxStringSize = (int) Math.pow(2, 16); // TODO: CHeck why this still fails @@ -99,13 +110,13 @@ private static String getReturnAssertionCodeLine(InstanceReference traceData, } return assertionLine; - } else if (variableStackHandler.DoesVariableExist(instanceId)) { + } else if (variableStackHandler.DoesVariableExist(returnedValueInstanceId)) { return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));" - .formatted(VariableStackHandler.getVariableName(instanceId)); + .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)); } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { - return "// Unserializable data with instance id: %d".formatted(traceData.getInstanceId()); + return "// Unserializable data with instance id: %d".formatted(returnedValueInstance.getInstanceId()); } } @@ -119,11 +130,14 @@ public static String traceToAssert(Trace methodTrace, VariableStackHandler varia if (!methodTrace.getMethodReference().getIsConstructor() && traceData != null) { String assertionCodeLine; try { - assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, + assertionCodeLine = getReturnAssertionCodeLine(traceData, + methodTrace.getMethodReference().getReturnType(), variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, - USE_ALTERNATIVE_ASSERTION_MODE)); + assertionCodeLine = "// %s" + .formatted(getReturnAssertionCodeLine(traceData, + methodTrace.getMethodReference().getReturnType(), variableStackHandler, false, + USE_ALTERNATIVE_ASSERTION_MODE)); } return assertionCodeLine; } diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java index 46b08199..08f77c5d 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -18,25 +18,26 @@ public class Main { private static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) - //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); // This is ugly, I know private static int GetTraceNumber(Path i) { - return Integer.valueOf(i.getFileName().toString().split("_") - [1].replace(".json", "")); + return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); } private static ArrayList readTraces(String traceXmlFolder) throws IOException { ArrayList traces = new ArrayList<>(); - List traceFiles = Files.list(Path.of(traceXmlFolder)).sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); + List traceFiles = Files.list(Path.of(traceXmlFolder)) + .sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); for (Path testTraceFile : traceFiles) { try { - TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), TestTraceResults.class); + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), + TestTraceResults.class); traces.add(testTraceResults.Trace); } catch (Exception e) { System.out.println("ERROR while deserializing a trace!"); @@ -49,10 +50,12 @@ private static ArrayList readTraces(String traceXmlFolder) throws IOExcep public static void writeMarker(List failure, String output) { int mainPadding = 1; - String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, mainPadding); + String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + mainPadding); while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, ++mainPadding); + tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + ++mainPadding); } try { @@ -62,7 +65,7 @@ public static void writeMarker(List failure, String output) { e.printStackTrace(); } } - + private static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { if (name.length() == 0) { return 0; @@ -84,7 +87,6 @@ private static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiv }; } - private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { return switch (name.charAt(0)) { case 'I' -> "java.lang.Integer"; @@ -110,10 +112,10 @@ public static String getCleanedType(String FQN) { } if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN).replace("$", "."); @@ -126,8 +128,10 @@ public static String getCleanedType(String FQN) { public static void main(String[] args) throws IOException { - //args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; - args = new String[] {"/home/gus/Git/gilesi/Results/generated/traces", "/home/gus/Git/gilesi/Results/generated/tests"}; + // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", + // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", + "/home/gus/Git/gilesi/Results/generated/tests" }; if (args.length != 2) { System.out.println("Usage: "); @@ -138,12 +142,14 @@ public static void main(String[] args) throws IOException { String testPath = args[1]; if (!Files.exists(Path.of(traceXmlFolder)) || !Files.isDirectory(Path.of(traceXmlFolder))) { - System.out.println("Argument 1 is not a Folder containing trace files. It either does not exist or is not a directory."); + System.out.println( + "Argument 1 is not a Folder containing trace files. It either does not exist or is not a directory."); return; } if (!Files.exists(Path.of(testPath)) || !Files.isDirectory(Path.of(testPath))) { - System.out.println("Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); + System.out.println( + "Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); return; } @@ -205,7 +211,7 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < methodTraces.size(); i++) { - //System.out.println("==========================="); + // System.out.println("==========================="); Trace trace = methodTraces.get(i); @@ -215,7 +221,8 @@ public static void main(String[] args) throws IOException { InstanceReference instanceData = trace.getInstanceReference(); - boolean isInstanceCall = instanceData != null && !instanceData.getClassReference().getFullyQualifiedTypeName().replace("$", ".").equals(methodName); + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); InstanceReference returnData = trace.getReturnedValue(); String returnVariableName = ""; @@ -230,7 +237,8 @@ public static void main(String[] args) throws IOException { ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); String argumentLine = argLineResult.argumentsForMethodCall; - List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, variableStackHandler); + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, + variableStackHandler); /*for (String descr : trace.getConfDescriptors()) { int startArg = descr.indexOf("("); @@ -250,8 +258,7 @@ public static void main(String[] args) throws IOException { if (curArg.length() != 0) { arguments.add(getCleanedType(curArg)); } - } - while (length != 0); + } while (length != 0); if (!returns.equals("V")) { returnValue = getCleanedType(returns); @@ -267,7 +274,7 @@ public static void main(String[] args) throws IOException { System.out.println("Returns: " + returnValue); } } - System.out.println();*/ + System.out.println();/* */ if (trace.getMethodReference().getIsConstructor()) { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { @@ -275,7 +282,8 @@ public static void main(String[] args) throws IOException { instanceVariableName = String.format("%s %s", methodName, instanceVariableName); } - String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); + String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (argLineResult.Success) { for (String str : argLineResult.variableList) { @@ -310,17 +318,22 @@ public static void main(String[] args) throws IOException { StringBuilder callStringBuilder = new StringBuilder(); // Holds whenever or not an issue with instances was found - // If true, we should not create new variables and we should comment out the whole code. + // If true, we should not create new variables and we should comment out the + // whole code. // As the code simply is not generable. boolean issuesDetected = false; if (isInstanceCall) { - // When we have an instance dependent call, we need the instance the call is performed onto to exist + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist // If it does not exist, then we cannot generate this code // Log that, and comment out the code we would have generated. // And make sure we do not create a variable for the return value if a thing. if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - String warnMessage = String.format("[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", i + 1, methodName, instanceData.getInstanceId(), instanceData.getClassReference().getFullyQualifiedTypeName()); + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + i + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); // Log the warning to the current string builder and the console. System.out.println(warnMessage); @@ -329,7 +342,8 @@ public static void main(String[] args) throws IOException { issuesDetected = true; } - // An instance method call is not called by its fully qualified name (i.e. bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); } @@ -339,14 +353,17 @@ public static void main(String[] args) throws IOException { if (!issuesDetected) { variableStackHandler.CreateNewVariable(returnData.getInstanceId()); } else { - String warnMessage = String.format("[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", i + 1, returnData.getInstanceId()); + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + i + 1, returnData.getInstanceId()); // Log the warning to the current string builder and the console. System.out.println(warnMessage); testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); } - String returnType = getCleanedVar(getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); + String returnType = getCleanedVar( + getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); returnVariableName = String.format("%s %s", returnType, returnVariableName); } @@ -427,29 +444,30 @@ public static void main(String[] args) throws IOException { } String padding = "\t\t"; - String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString().substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); + String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString() + .substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); stringBuilder.append(String.format("%s\n\t}\n", paddedString)); stringBuilder.append(""" - \tpublic static String getToXml(Object obj) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\treturn xStream.toXML(obj); - \t} - """); + \tpublic static String getToXml(Object obj) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\treturn xStream.toXML(obj); + \t} + """); stringBuilder.append(""" - \t@SuppressWarnings("unchecked") - \tpublic static T getFromXml(String xmlString) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\txStream.addPermission(AnyTypePermission.ANY); - \t\tObject obj = xStream.fromXML(xmlString); - \t\treturn (T) obj; - \t} - """); + \t@SuppressWarnings("unchecked") + \tpublic static T getFromXml(String xmlString) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\txStream.addPermission(AnyTypePermission.ANY); + \t\tObject obj = xStream.fromXML(xmlString); + \t\treturn (T) obj; + \t} + """); stringBuilder.append("}\n"); stringBuilder.append("\n"); diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 8f1b0078..36ae4cb5 100644 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -1,5 +1,6 @@ package com.github.gilesi.testgenerator; +import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.SerializationException; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; @@ -34,10 +35,10 @@ public static String getCleanedType(String FQN) { } if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN).replace("$", "."); @@ -48,9 +49,10 @@ public static String getCleanedType(String FQN) { return FQN.replace("$", "."); } - public static String serializableDataToJava(InstanceReference serializableData) throws SerializationException { + public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) + throws SerializationException { String valueToBeEqualTo = serializableData.getValueAsXmlString(); - String FQN = getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + String FQN = getCleanedType(argClass.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && @@ -63,7 +65,7 @@ public static String serializableDataToJava(InstanceReference serializableData) !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - //int maxStringSize = (int) Math.pow(2, 16); + // int maxStringSize = (int) Math.pow(2, 16); // TODO: Check why this still fails int maxStringSize = 1024; @@ -76,8 +78,9 @@ public static String serializableDataToJava(InstanceReference serializableData) end = serializableData.getValueAsXmlString().length(); } - String sectionOfDataAsXml = "SNIP";//serializableData.getValueAsXmlString().substring(start, end); - String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + String sectionOfDataAsXml = "SNIP";// serializableData.getValueAsXmlString().substring(start, end); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } @@ -85,12 +88,14 @@ public static String serializableDataToJava(InstanceReference serializableData) valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); } else { - // Casting is not needed if we only use this with variable assignments that are strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + // Casting is not needed if we only use this with variable assignments that are + // strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, + // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + valueToBeEqualTo = "getFromXml(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); } - } - else { + } else { int start = valueToBeEqualTo.indexOf(">"); int end = valueToBeEqualTo.lastIndexOf(" Date: Thu, 11 Jul 2024 15:27:21 +0200 Subject: [PATCH 167/244] Cleanup --- .../gilesi/testgenerator/ArgumentUtils.java | 0 .../gilesi/testgenerator/AssertionUtils.java | 0 .../com/github/gilesi/testgenerator/Main.java | 400 +- .../testgenerator/SerializationUtils.java | 49 +- .../testgenerator/TestMethodGenerator.java | 415 --- .../testgenerator/VariableStackHandler.java | 33 +- .../InstanceAlreadyDefinedException.java | 7 - .../InstanceNotDefinedException.java | 7 - TestGenerator2/.gitignore | 39 - TestGenerator2/build.gradle | 77 - .../gradle/wrapper/gradle-wrapper.jar | Bin 63375 -> 0 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 - TestGenerator2/gradlew | 246 -- TestGenerator2/gradlew.bat | 91 - .../models/ClassReference.java | 44 - .../models/GenericReference.java | 26 - .../models/InstanceReference.java | 49 - .../models/MethodReference.java | 62 - .../instrumentation/models/PartialTrace.java | 57 - .../models/TestTraceResults.java | 6 - .../gilesi/instrumentation/models/Trace.java | 96 - .../com/github/gilesi/testgenerator/Main.java | 504 --- .../testgenerator/SerializationUtils.java | 150 - .../testgenerator/VariableStackHandler.java | 22 - .../exceptions/SerializationException.java | 7 - ...UnsupportedJavaPrimitiveTypeException.java | 7 - maracas-test.cmd | 44 - maracas-test.sh | 41 - oldlogs/surefire.txt | 3284 ----------------- 29 files changed, 399 insertions(+), 5371 deletions(-) rename {TestGenerator2 => TestGenerator}/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java (100%) rename {TestGenerator2 => TestGenerator}/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java (100%) delete mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/TestMethodGenerator.java delete mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java delete mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java delete mode 100644 TestGenerator2/.gitignore delete mode 100644 TestGenerator2/build.gradle delete mode 100644 TestGenerator2/gradle/wrapper/gradle-wrapper.jar delete mode 100644 TestGenerator2/gradle/wrapper/gradle-wrapper.properties delete mode 100644 TestGenerator2/gradlew delete mode 100644 TestGenerator2/gradlew.bat delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java delete mode 100644 TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java delete mode 100644 maracas-test.cmd delete mode 100755 maracas-test.sh delete mode 100644 oldlogs/surefire.txt diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java similarity index 100% rename from TestGenerator2/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java similarity index 100% rename from TestGenerator2/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index a581d393..08f77c5d 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -2,20 +2,14 @@ import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.databind.SerializationFeature; -import com.github.gilesi.instrumentation.models.PartialTrace; import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; -import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; -import com.github.gilesi.testgenerator.exceptions.SerializationException; -import com.thoughtworks.xstream.XStream; -import com.thoughtworks.xstream.io.xml.DomDriver; -import com.thoughtworks.xstream.security.AnyTypePermission; +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; +import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import java.io.File; import java.io.IOException; -import java.lang.management.ManagementFactory; -import java.lang.management.RuntimeMXBean; import java.nio.file.Files; import java.nio.file.Path; import java.nio.file.Paths; @@ -24,25 +18,26 @@ public class Main { private static final ObjectMapper objectMapper = new ObjectMapper() .enable(SerializationFeature.INDENT_OUTPUT) - //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); // This is ugly, I know private static int GetTraceNumber(Path i) { - return Integer.valueOf(i.getFileName().toString().split("_") - [1].replace(".json", "")); + return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); } private static ArrayList readTraces(String traceXmlFolder) throws IOException { - ArrayList traces = new ArrayList(); + ArrayList traces = new ArrayList<>(); - List traceFiles = Files.list(Path.of(traceXmlFolder)).sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); + List traceFiles = Files.list(Path.of(traceXmlFolder)) + .sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); for (Path testTraceFile : traceFiles) { try { - TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), TestTraceResults.class); + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), + TestTraceResults.class); traces.add(testTraceResults.Trace); } catch (Exception e) { System.out.println("ERROR while deserializing a trace!"); @@ -55,10 +50,12 @@ private static ArrayList readTraces(String traceXmlFolder) throws IOExcep public static void writeMarker(List failure, String output) { int mainPadding = 1; - String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, mainPadding); + String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + mainPadding); while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, ++mainPadding); + tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + ++mainPadding); } try { @@ -69,10 +66,93 @@ public static void writeMarker(List failure, String output) { } } - public static void main(String[] args) throws IOException, InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { + private static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { + if (name.length() == 0) { + return 0; + } + + return switch (name.charAt(0)) { + case 'I' -> 1; + case 'V' -> 1; + case 'Z' -> 1; + case 'B' -> 1; + case 'C' -> 1; + case 'S' -> 1; + case 'D' -> 1; + case 'F' -> 1; + case 'J' -> 1; + case 'L' -> name.indexOf(";") + 1; + case '[' -> getFirstArgLength(name.substring(1)) + 1; + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.length() - 1).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static String getCleanedType(String FQN) { + int currentCharacterIndex = 0; + char currentCharacter = FQN.charAt(currentCharacterIndex); + while (currentCharacter == '[') { + currentCharacter = FQN.charAt(++currentCharacterIndex); + } + + if (((currentCharacter == 'I' || currentCharacter == 'V' || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + (currentCharacter == 'L' && FQN.endsWith(";"))) { + try { + return JvmTypeToLangType(FQN).replace("$", "."); + } catch (UnsupportedJavaPrimitiveTypeException ignored) { + + } + } + return FQN.replace("$", "."); + } + + public static void main(String[] args) throws IOException { + + // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", + // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", + "/home/gus/Git/gilesi/Results/generated/tests" }; + + if (args.length != 2) { + System.out.println("Usage: "); + return; + } + String traceXmlFolder = args[0]; String testPath = args[1]; + if (!Files.exists(Path.of(traceXmlFolder)) || !Files.isDirectory(Path.of(traceXmlFolder))) { + System.out.println( + "Argument 1 is not a Folder containing trace files. It either does not exist or is not a directory."); + return; + } + + if (!Files.exists(Path.of(testPath)) || !Files.isDirectory(Path.of(testPath))) { + System.out.println( + "Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); + return; + } + ArrayList methodTraces = readTraces(traceXmlFolder); if (methodTraces.isEmpty()) { @@ -127,15 +207,232 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine VariableStackHandler variableStackHandler = new VariableStackHandler(); + StringBuilder testMethodStringBuilder = new StringBuilder(); + for (int i = 0; i < methodTraces.size(); i++) { + + // System.out.println("==========================="); + Trace trace = methodTraces.get(i); try { - String traceCode = TestMethodGenerator.getTraceAsCode(trace, variableStackHandler, "\t\t", false); - stringBuilder.append("%s\n".formatted(traceCode)); + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); + + InstanceReference instanceData = trace.getInstanceReference(); + + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); + + InstanceReference returnData = trace.getReturnedValue(); + String returnVariableName = ""; + if (returnData != null) { + returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); + } + + String instanceVariableName = ""; + if (instanceData != null) { + instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); + } + + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); + String argumentLine = argLineResult.argumentsForMethodCall; + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, + variableStackHandler); + + /*for (String descr : trace.getConfDescriptors()) { + int startArg = descr.indexOf("("); + int endArg = descr.lastIndexOf(")"); + + String returns = descr.substring(endArg + 1, descr.length()); + String argusStr = descr.substring(startArg + 1, endArg); + + int length = 1; + List arguments = new ArrayList<>(); + String returnValue = null; + + do { + length = getFirstArgLength(argusStr); + String curArg = argusStr.substring(0, length); + argusStr = argusStr.substring(length); + if (curArg.length() != 0) { + arguments.add(getCleanedType(curArg)); + } + } while (length != 0); + + if (!returns.equals("V")) { + returnValue = getCleanedType(returns); + } + + System.out.println("Descriptor: " + descr); + + if (arguments.size() != 0) { + System.out.println("Arguments: (%s)".formatted(String.join(", ", arguments))); + } + + if (returnValue != null) { + System.out.println("Returns: " + returnValue); + } + } + System.out.println();/* */ + + if (trace.getMethodReference().getIsConstructor()) { + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); + instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + } + + String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("%s\n", str)); + } + + testMethodStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("// %s\n", str)); + } + + testMethodStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append("// " + varAssert + "\n"); + } + } + } else { + StringBuilder callStringBuilder = new StringBuilder(); + + // Holds whenever or not an issue with instances was found + // If true, we should not create new variables and we should comment out the + // whole code. + // As the code simply is not generable. + boolean issuesDetected = false; + + if (isInstanceCall) { + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist + // If it does not exist, then we cannot generate this code + // Log that, and comment out the code we would have generated. + // And make sure we do not create a variable for the return value if a thing. + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + i + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); + + issuesDetected = true; + } + + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } + + if (returnData != null) { + if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { + if (!issuesDetected) { + variableStackHandler.CreateNewVariable(returnData.getInstanceId()); + } else { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + i + 1, returnData.getInstanceId()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); + } + + String returnType = getCleanedVar( + getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); + returnVariableName = String.format("%s %s", returnType, returnVariableName); + } + + String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + + callStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } + + callStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } + } + } else { + String callLine = String.format("%s(%s);\n", methodName, argumentLine); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + + callStringBuilder.append(callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } + + callStringBuilder.append("// " + callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } + } + } + + // Append the method call to the current string builder. + if (issuesDetected) { + testMethodStringBuilder.append(String.format("// %s", callStringBuilder.toString())); + } else { + testMethodStringBuilder.append(callStringBuilder.toString()); + } + } if (i != methodTraces.size() - 1) { - stringBuilder.append("\n"); + testMethodStringBuilder.append("\n"); } } catch (Exception e) { System.out.println("Unable to convert trace to code!"); @@ -146,33 +443,62 @@ public static void main(String[] args) throws IOException, InstanceAlreadyDefine } } - stringBuilder.append("\t}\n"); + String padding = "\t\t"; + String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString() + .substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); + stringBuilder.append(String.format("%s\n\t}\n", paddedString)); stringBuilder.append(""" - \tpublic static String getToXml(Object obj) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\treturn xStream.toXML(obj); - \t} - """); + \tpublic static String getToXml(Object obj) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\treturn xStream.toXML(obj); + \t} + """); stringBuilder.append(""" - \t@SuppressWarnings("unchecked") - \tpublic static T getFromXml(String xmlString) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\txStream.addPermission(AnyTypePermission.ANY); - \t\tObject obj = xStream.fromXML(xmlString); - \t\treturn (T) obj; - \t} - """); + \t@SuppressWarnings("unchecked") + \tpublic static T getFromXml(String xmlString) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\txStream.addPermission(AnyTypePermission.ANY); + \t\tObject obj = xStream.fromXML(xmlString); + \t\treturn (T) obj; + \t} + """); stringBuilder.append("}\n"); stringBuilder.append("\n"); + System.out.println(classOutputPath); Files.deleteIfExists(classOutputPath); Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); } + + public static String getCleanedVar(String fullyQualifiedTypeName) { + String returnType = fullyQualifiedTypeName.replace("$", "."); + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + return returnType; + } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 8f1b0078..36ae4cb5 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -1,5 +1,6 @@ package com.github.gilesi.testgenerator; +import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.SerializationException; import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; @@ -34,10 +35,10 @@ public static String getCleanedType(String FQN) { } if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN).replace("$", "."); @@ -48,9 +49,10 @@ public static String getCleanedType(String FQN) { return FQN.replace("$", "."); } - public static String serializableDataToJava(InstanceReference serializableData) throws SerializationException { + public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) + throws SerializationException { String valueToBeEqualTo = serializableData.getValueAsXmlString(); - String FQN = getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); + String FQN = getCleanedType(argClass.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && @@ -63,7 +65,7 @@ public static String serializableDataToJava(InstanceReference serializableData) !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - //int maxStringSize = (int) Math.pow(2, 16); + // int maxStringSize = (int) Math.pow(2, 16); // TODO: Check why this still fails int maxStringSize = 1024; @@ -76,8 +78,9 @@ public static String serializableDataToJava(InstanceReference serializableData) end = serializableData.getValueAsXmlString().length(); } - String sectionOfDataAsXml = "SNIP";//serializableData.getValueAsXmlString().substring(start, end); - String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + String sectionOfDataAsXml = "SNIP";// serializableData.getValueAsXmlString().substring(start, end); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); sectionList.add(readyToUseSection); } @@ -85,12 +88,14 @@ public static String serializableDataToJava(InstanceReference serializableData) valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); } else { - // Casting is not needed if we only use this with variable assignments that are strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - valueToBeEqualTo = "getFromXml(\"%s\")".formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + // Casting is not needed if we only use this with variable assignments that are + // strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, + // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + valueToBeEqualTo = "getFromXml(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); } - } - else { + } else { int start = valueToBeEqualTo.indexOf(">"); int end = valueToBeEqualTo.lastIndexOf(" preCallArguments = new ArrayList<>(); - List variableList = new ArrayList<>(); - - boolean commentItAll = false; - - for (InstanceReference preCallArgument : methodTrace.getPreCallArguments()) { - if (preCallArgument.getInstanceId() < 0 && preCallArgument.getClassReference().getFullyQualifiedTypeName().equals("Object") && preCallArgument.getValueAsXmlString().equals("null")) { - preCallArguments.add("null"); - continue; - } - - String argumentValue; - try { - argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, true); - } - catch (SerializationException e) { - argumentValue = serializableDataToCode(preCallArgument, variableStackHandler, false); - commentItAll = true; - } - - String argumentVariable; - try { - argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler); - } - catch (SerializationException e) { - argumentVariable = getDataVariableDeclaration2(preCallArgument, variableStackHandler); - commentItAll = true; - // todo: problem here... - } - - String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); - - // Has to be defined already so no need to check here - preCallArguments.add(variableStackHandler.getInstanceVariableName(preCallArgument.getInstanceId())); - - // Define the variable before the method - variableList.add("%s;".formatted(argumentDeclaration)); - } - - try { - String methodCall = traceToMethodCall(methodTrace, variableStackHandler); - - String argumentParameters = String.join(", ", preCallArguments); - String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); - variableList.add(methodCallCode); - } catch (InstanceNotDefinedException e) { - String methodCall = "// %s".formatted(e.getMessage());//traceToMethodCall(methodTrace, variableStackHandler); - - String argumentParameters = String.join(", ", preCallArguments); - String methodCallCode = "%s(%s);".formatted(methodCall, argumentParameters); - variableList.add(methodCallCode); - } - - String code = String.join("\n%s".formatted(indentationPrefix), variableList); - if (commentItAll) { - code = "/* " + code + " */"; - } - - return code; - } - - private static String getReturnAssertionCodeLine(InstanceReference traceData, VariableStackHandler variableStackHandler, boolean failOnLambdas, boolean useAltAssertionMode) throws InstanceNotDefinedException, SerializationException { - int instanceId = traceData.getInstanceId(); - String dataAsXml = traceData.getValueAsXmlString(); - - if (dataAsXml != null) { - try { - String instanceVarName = variableStackHandler.getInstanceVariableName(instanceId); - - if (dataAsXml.equals("null")) { - return "assertEquals(null, %s);".formatted(instanceVarName); - } - - if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); - } - - String assertionLine; - - if (useAltAssertionMode) { - String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); - - if (valueAsCode.endsWith("[].class)")) { - assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); - } else { - assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); - } - } else { - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - - //int maxStringSize = (int) Math.pow(2, 16); - // TODO: CHeck why this still fails - int maxStringSize = 1024; - - if (valueAsCode.length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueAsCode.length()) { - end2 = valueAsCode.length(); - } - - String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - valueAsCode = String.join("+", sectionList.toArray(String[]::new)); - } - - assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); - } - - return assertionLine; - } catch (InstanceNotDefinedException e) { - String instanceVarName = String.valueOf(instanceId); - - if (dataAsXml.equals("null")) { - return "// assertEquals(null, %s);".formatted(instanceVarName); - } - - if (failOnLambdas && traceData.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); - } - - String assertionLine; - - if (useAltAssertionMode) { - String valueAsCode = serializableDataToCode(traceData, variableStackHandler, true); - - if (valueAsCode.endsWith("[].class)")) { - assertionLine = "// assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); - } else { - assertionLine = "// assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); - } - } else { - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(dataAsXml)); - - //int maxStringSize = (int) Math.pow(2, 16); - // TODO: CHeck why this still fails - int maxStringSize = 1024; - - if (valueAsCode.length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueAsCode.length()) { - end2 = valueAsCode.length(); - } - - String sectionOfDataAsXml = "SNIP";//valueToBeEqualTo.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")".formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - valueAsCode = String.join("+", sectionList.toArray(String[]::new)); - } - - assertionLine = "// assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); - } - - return assertionLine; - } - } else if (variableStackHandler.isInstanceVariableNameDefined(instanceId)) { - return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));".formatted(variableStackHandler.getInstanceVariableName(instanceId)); - } else if (failOnLambdas) { - throw new SerializationException("We cannot serialize this!"); - } else { - return "// Unserializable data with instance id: %d".formatted(traceData.getInstanceId()); - } - } - - private static String traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler, String indentationPrefix) throws InstanceNotDefinedException, SerializationException { - List argList = new ArrayList<>(); - - for (InstanceReference traceData : methodTrace.getPostCallArguments()) { - if (traceData == null) { - //argList.add("null"); - continue; - } - - if (traceData.getInstanceId() < 0 && traceData.getClassReference().getFullyQualifiedTypeName().equals("Object") && traceData.getValueAsXmlString().equals("null")) { - //argList.add("null"); - continue; - } - - // We return a value that we managed to serialize - String assertionCodeLine; - try { - assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); - } - catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); - } - argList.add(assertionCodeLine); - } - - return String.join("\n%s".formatted(indentationPrefix), argList); - } - - private static String traceToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws InstanceNotDefinedException, SerializationException { - String cleanedMethodName = methodTrace.getMethodReference().getMethodSignature().split("\\(")[0]; - cleanedMethodName = cleanedMethodName.split(" ")[cleanedMethodName.split(" ").length - 1].replace("$", "."); - - InstanceReference traceData = methodTrace.getReturnedValue(); - - if (!methodTrace.getMethodReference().getIsConstructor() && traceData != null) { - String assertionCodeLine; - try { - assertionCodeLine = getReturnAssertionCodeLine(traceData, variableStackHandler, true, USE_ALTERNATIVE_ASSERTION_MODE); - } - catch (SerializationException e) { - assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(traceData, variableStackHandler, false, USE_ALTERNATIVE_ASSERTION_MODE)); - } - return assertionCodeLine; - } - - return null; - } - - public static String getTraceAsCode(Trace trace, VariableStackHandler variableStackHandler, String indentationPrefix, boolean addAssertsForArgumentsPostCall) throws InstanceAlreadyDefinedException, InstanceNotDefinedException, SerializationException { - String traceCode = ""; - - String methodCallLine = traceToCode(trace, variableStackHandler, indentationPrefix); - if (methodCallLine != null && !methodCallLine.isEmpty()) { - traceCode += "%s%s\n".formatted(indentationPrefix, methodCallLine); - } - - String returnAssertionLine = traceToAssert(trace, variableStackHandler); - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - traceCode += "%s%s\n".formatted(indentationPrefix, returnAssertionLine); - } - - if (addAssertsForArgumentsPostCall) { - String postCallParameterAssertionLine = traceArgumentsToAssert(trace, variableStackHandler, indentationPrefix); - if (!postCallParameterAssertionLine.isEmpty()) { - traceCode += "%s%s\n".formatted(indentationPrefix, postCallParameterAssertionLine); - } - } - - while (traceCode.endsWith("\n")) { - traceCode = traceCode.substring(0, traceCode.length() - 1); - } - - return traceCode; - } -} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java index 1ee2b1b6..5639022a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java @@ -1,35 +1,22 @@ package com.github.gilesi.testgenerator; -import com.github.gilesi.testgenerator.exceptions.InstanceAlreadyDefinedException; -import com.github.gilesi.testgenerator.exceptions.InstanceNotDefinedException; - -import java.util.HashMap; +import java.util.ArrayList; +import java.util.List; public class VariableStackHandler { - // The map of instance ids to variable indexes - private final HashMap mapOfInstancesToIndexes = new HashMap<>(); - // The currently free index for variables to define in our java source code - private int varIndex = 0; + private List variableInstances = new ArrayList<>(); - public String getInstanceVariableName(int instanceId) throws InstanceNotDefinedException { - if (isInstanceVariableNameDefined(instanceId)) { - return "var%d".formatted(mapOfInstancesToIndexes.get(instanceId)); + public void CreateNewVariable(int instanceId) { + if (!DoesVariableExist(instanceId)) { + variableInstances.add(instanceId); } - - throw new InstanceNotDefinedException(instanceId); } - public String newInstanceVariableName(int instanceId) throws InstanceAlreadyDefinedException { - if (!isInstanceVariableNameDefined(instanceId)) { - int i = ++varIndex; - mapOfInstancesToIndexes.put(instanceId, i); - return "var%d".formatted(i); - } - - throw new InstanceAlreadyDefinedException(instanceId); + public boolean DoesVariableExist(int instanceId) { + return variableInstances.contains(instanceId); } - public boolean isInstanceVariableNameDefined(int instanceId) { - return mapOfInstancesToIndexes.containsKey(instanceId); + public static String getVariableName(int instanceId) { + return String.format("var%d", instanceId); } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java deleted file mode 100644 index bad23d0e..00000000 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceAlreadyDefinedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.gilesi.testgenerator.exceptions; - -public class InstanceAlreadyDefinedException extends Exception { - public InstanceAlreadyDefinedException(Integer instanceId) { - super("Instance Id is already defined: " + instanceId); - } -} diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java deleted file mode 100644 index 71f8e677..00000000 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/exceptions/InstanceNotDefinedException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.gilesi.testgenerator.exceptions; - -public class InstanceNotDefinedException extends Exception { - public InstanceNotDefinedException(Integer instanceId) { - super("Instance Id is not already defined: " + instanceId); - } -} diff --git a/TestGenerator2/.gitignore b/TestGenerator2/.gitignore deleted file mode 100644 index d4c6a6aa..00000000 --- a/TestGenerator2/.gitignore +++ /dev/null @@ -1,39 +0,0 @@ -.gradle -build/ -!gradle/wrapper/gradle-wrapper.jar -!**/src/main/**/build/ -!**/src/test/**/build/ - -### IntelliJ IDEA ### -.idea/* -*.iws -*.iml -*.ipr -out/ -!**/src/main/**/out/ -!**/src/test/**/out/ - -### Eclipse ### -.apt_generated -.classpath -.factorypath -.project -.settings -.springBeans -.sts4-cache -bin/ -!**/src/main/**/bin/ -!**/src/test/**/bin/ - -### NetBeans ### -/nbproject/private/ -/nbbuild/ -/dist/ -/nbdist/ -/.nb-gradle/ - -### VS Code ### -.vscode/ - -### Mac OS ### -.DS_Store \ No newline at end of file diff --git a/TestGenerator2/build.gradle b/TestGenerator2/build.gradle deleted file mode 100644 index 1d5a16fb..00000000 --- a/TestGenerator2/build.gradle +++ /dev/null @@ -1,77 +0,0 @@ -plugins { - id 'application' - id 'com.github.johnrengelman.shadow' version '8.1.1' -} - -group 'com.github.gilesi.testgenerator' -version '1.0-SNAPSHOT' - - -compileJava { - options.encoding = 'UTF-8' -} - -tasks.withType(JavaCompile).configureEach { - options.encoding = 'UTF-8' -} - -repositories { - mavenCentral() - mavenLocal() - maven { - url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' - } -} - -dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.14.0' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.0' - implementation 'com.fasterxml.jackson:jackson-base:2.14.0' - implementation 'org.apache.commons:commons-text:1.11.0' - implementation 'com.thoughtworks.xstream:xstream:1.4.20' -} - -jar { - manifest { - attributes 'Main-Class': 'com.github.gilesi.testgenerator.Main', - 'Multi-Release': 'true' - } -} - -application { - mainClass = 'com.github.gilesi.testgenerator.Main' -} - -description = 'Main distribution.' - -shadowJar { - archiveBaseName.set('com.github.gilesi.testgenerator') - archiveClassifier.set('') - archiveVersion.set('') - mergeServiceFiles() -} - -distributions { - shadow { - distributionBaseName = 'com.github.gilesi.testgenerator' - } -} - -apply plugin: 'java' -apply plugin: 'idea' - -idea { - module { - downloadJavadoc = true - downloadSources = true - } -} - -run { - jvmArgs = [ - "-XX:InitialHeapSize=2G", - "-XX:MaxHeapSize=2G" - ] -} \ No newline at end of file diff --git a/TestGenerator2/gradle/wrapper/gradle-wrapper.jar b/TestGenerator2/gradle/wrapper/gradle-wrapper.jar deleted file mode 100644 index 033e24c4cdf41af1ab109bc7f253b2b887023340..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 63375 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≫L+crb^Bz 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 '} - case $link in #( - /*) app_path=$link ;; #( - *) app_path=$APP_HOME$link ;; - esac -done - -# This is normally unused -# shellcheck disable=SC2034 -APP_BASE_NAME=${0##*/} -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -# Use the maximum available, or set MAX_FD != -1 to use that value. -MAX_FD=maximum - -warn () { - echo "$*" -} >&2 - -die () { - echo - echo "$*" - echo - exit 1 -} >&2 - -# OS specific support (must be 'true' or 'false'). -cygwin=false -msys=false -darwin=false -nonstop=false -case "$( uname )" in #( - CYGWIN* ) cygwin=true ;; #( - Darwin* ) darwin=true ;; #( - MSYS* | MINGW* ) msys=true ;; #( - NONSTOP* ) nonstop=true ;; -esac - -CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar - -# Determine the Java command to use to start the JVM. -if [ -n "$JAVA_HOME" ] ; then - if [ -x "$JAVA_HOME/jre/sh/java" ] ; then - # IBM's JDK on AIX uses strange locations for the executables - JAVACMD=$JAVA_HOME/jre/sh/java - else - JAVACMD=$JAVA_HOME/bin/java - fi - if [ ! -x "$JAVACMD" ] ; then - die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -else - JAVACMD=java - if ! command -v java >/dev/null 2>&1 - then - die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. - -Please set the JAVA_HOME variable in your environment to match the -location of your Java installation." - fi -fi - -# Increase the maximum file descriptors if we can. -if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then - case $MAX_FD in #( - max*) - # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - MAX_FD=$( ulimit -H -n ) || - warn "Could not query maximum file descriptor limit" - esac - case $MAX_FD in #( - '' | soft) :;; #( - *) - # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. - # shellcheck disable=SC3045 - ulimit -n "$MAX_FD" || - warn "Could not set maximum file descriptor limit to $MAX_FD" - esac -fi - -# Collect all arguments for the java command, stacking in reverse order: -# * args from the command line -# * the main class name -# * -classpath -# * -D...appname settings -# * --module-path (only if needed) -# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. - -# For Cygwin or MSYS, switch paths to Windows format before running java -if "$cygwin" || "$msys" ; then - APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) - CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) - - JAVACMD=$( cygpath --unix "$JAVACMD" ) - - # Now convert the arguments - kludge to limit ourselves to /bin/sh - for arg do - if - case $arg in #( - -*) false ;; # don't mess with options #( - /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath - [ -e "$t" ] ;; #( - *) false ;; - esac - then - arg=$( cygpath --path --ignore --mixed "$arg" ) - fi - # Roll the args list around exactly as many times as the number of - # args, so each arg winds up back in the position where it started, but - # possibly modified. - # - # NB: a `for` loop captures its iteration list before it begins, so - # changing the positional parameters here affects neither the number of - # iterations, nor the values presented in `arg`. - shift # remove old arg - set -- "$@" "$arg" # push replacement arg - done -fi - -# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' - -# Collect all arguments for the java command; -# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of -# shell script including quotes and variable substitutions, so put them in -# double quotes to make sure that they get re-expanded; and -# * put everything else in single quotes, so that it's not re-expanded. - -set -- \ - "-Dorg.gradle.appname=$APP_BASE_NAME" \ - -classpath "$CLASSPATH" \ - org.gradle.wrapper.GradleWrapperMain \ - "$@" - -# Stop when "xargs" is not available. -if ! command -v xargs >/dev/null 2>&1 -then - die "xargs is not available" -fi - -# Use "xargs" to parse quoted args. -# -# With -n1 it outputs one arg per line, with the quotes and backslashes removed. -# -# In Bash we could simply go: -# -# readarray ARGS < <( xargs -n1 <<<"$var" ) && -# set -- "${ARGS[@]}" "$@" -# -# but POSIX shell has neither arrays nor command substitution, so instead we -# post-process each arg (as a line of input to sed) to backslash-escape any -# character that might be a shell metacharacter, then use eval to reverse -# that process (while maintaining the separation between arguments), and wrap -# the whole thing up as a single "set" statement. -# -# This will of course break if any of these variables contains a newline or -# an unmatched quote. -# - -eval "set -- $( - printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | - xargs -n1 | - sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | - tr '\n' ' ' - )" '"$@"' - -exec "$JAVACMD" "$@" diff --git a/TestGenerator2/gradlew.bat b/TestGenerator2/gradlew.bat deleted file mode 100644 index 4b4ef2d7..00000000 --- a/TestGenerator2/gradlew.bat +++ /dev/null @@ -1,91 +0,0 @@ -@rem -@rem Copyright 2015 the original author or authors. -@rem -@rem Licensed under the Apache License, Version 2.0 (the "License"); -@rem you may not use this file except in compliance with the License. -@rem You may obtain a copy of the License at -@rem -@rem https://www.apache.org/licenses/LICENSE-2.0 -@rem -@rem Unless required by applicable law or agreed to in writing, software -@rem distributed under the License is distributed on an "AS IS" BASIS, -@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -@rem See the License for the specific language governing permissions and -@rem limitations under the License. -@rem - -@if "%DEBUG%"=="" @echo off -@rem ########################################################################## -@rem -@rem Gradle startup script for Windows -@rem -@rem ########################################################################## - -@rem Set local scope for the variables with windows NT shell -if "%OS%"=="Windows_NT" setlocal - -set DIRNAME=%~dp0 -if "%DIRNAME%"=="" set DIRNAME=. -@rem This is normally unused -set APP_BASE_NAME=%~n0 -set APP_HOME=%DIRNAME% - -@rem Resolve any "." and ".." in APP_HOME to make it shorter. -for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi - -@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. -set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" - -@rem Find java.exe -if defined JAVA_HOME goto findJavaFromJavaHome - -set JAVA_EXE=java.exe -%JAVA_EXE% -version >NUL 2>&1 -if %ERRORLEVEL% equ 0 goto execute - -echo. -echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:findJavaFromJavaHome -set JAVA_HOME=%JAVA_HOME:"=% -set JAVA_EXE=%JAVA_HOME%/bin/java.exe - -if exist "%JAVA_EXE%" goto execute - -echo. -echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% -echo. -echo Please set the JAVA_HOME variable in your environment to match the -echo location of your Java installation. - -goto fail - -:execute -@rem Setup the command line - -set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar - -@rem Execute Gradle -"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* - -:end -@rem End local scope for the variables with windows NT shell -if %ERRORLEVEL% equ 0 goto mainEnd - -:fail -rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of -rem the _cmd.exe /c_ return code! -set EXIT_CODE=%ERRORLEVEL% -if %EXIT_CODE% equ 0 set EXIT_CODE=1 -if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% -exit /b %EXIT_CODE% - -:mainEnd -if "%OS%"=="Windows_NT" endlocal - -:omega diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java deleted file mode 100644 index 9e25ea02..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java +++ /dev/null @@ -1,44 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class ClassReference { - private String fullyQualifiedTypeName; - private ClassReference[] interfaces; - private ClassReference superClass; - private GenericReference[] genericParameters; - - public ClassReference() { - - } - - public String getFullyQualifiedTypeName() { - return fullyQualifiedTypeName; - } - - public ClassReference[] getInterfaces() { - return interfaces; - } - - public ClassReference getSuperClass() { - return superClass; - } - - public GenericReference[] getGenericParameters() { - return genericParameters; - } - - public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { - this.fullyQualifiedTypeName = fullyQualifiedTypeName; - } - - public void setInterfaces(ClassReference[] interfaces) { - this.interfaces = interfaces; - } - - public void setSuperClass(ClassReference superClass) { - this.superClass = superClass; - } - - public void setGenericParameters(GenericReference[] genericParameters) { - this.genericParameters = genericParameters; - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java deleted file mode 100644 index 10eca61e..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java +++ /dev/null @@ -1,26 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class GenericReference { - private String name; - private ClassReference[] classBounds; - - public GenericReference() { - - } - - public String getName() { - return name; - } - - public void setName(String name) { - this.name = name; - } - - public ClassReference[] getClassBounds() { - return classBounds; - } - - public void getClassBounds(ClassReference[] classBounds) { - this.classBounds = classBounds; - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java deleted file mode 100644 index 2170cc86..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java +++ /dev/null @@ -1,49 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class InstanceReference { - private int instanceId = -1; - private String valueAsXmlString = null; - private String valueAsJsonString = null; - private boolean isNull = true; - private ClassReference classReference = null; - - public int getInstanceId() { - return instanceId; - } - - public String getValueAsXmlString() { - return valueAsXmlString; - } - - public String getValueAsJsonString() { - return valueAsJsonString; - } - - public boolean getIsNull() { - return isNull; - } - - public ClassReference getClassReference() { - return classReference; - } - - public void setInstanceId(int instanceId) { - this.instanceId = instanceId; - } - - public void setValueAsXmlString(String valueAsXmlString) { - this.valueAsXmlString = valueAsXmlString; - } - - public void setValueAsJsonString(String valueAsJsonString) { - this.valueAsJsonString = valueAsJsonString; - } - - public void setIsNull(boolean isNull) { - this.isNull = isNull; - } - - public void setClassReference(ClassReference classReference) { - this.classReference = classReference; - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java deleted file mode 100644 index 94dc8eda..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java +++ /dev/null @@ -1,62 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class MethodReference { - private String methodSignature; - private ClassReference[] parameterTypes; - private ClassReference returnType; - private boolean isConstructor; - private GenericReference[] genericParameters; - private ClassReference genericReturn; - - public MethodReference() { - - } - - public String getMethodSignature() { - return methodSignature; - } - - public ClassReference[] getParameterTypes() { - return parameterTypes; - } - - public ClassReference getReturnType() { - return returnType; - } - - public boolean getIsConstructor() { - return isConstructor; - } - - public GenericReference[] getGenericParameters() { - return genericParameters; - } - - public ClassReference getGenericReturn() { - return genericReturn; - } - - public void setMethodSignature(String methodSignature) { - this.methodSignature = methodSignature; - } - - public void setParameterTypes(ClassReference[] parameterTypes) { - this.parameterTypes = parameterTypes; - } - - public void setReturnType(ClassReference returnType) { - this.returnType = returnType; - } - - public void setIsConstructor(boolean isConstructor) { - this.isConstructor = isConstructor; - } - - public void setGenericParameters(GenericReference[] genericParameters) { - this.genericParameters = genericParameters; - } - - public void setGenericReturn(ClassReference genericReturn) { - this.genericReturn = genericReturn; - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java deleted file mode 100644 index d2a7d482..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java +++ /dev/null @@ -1,57 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class PartialTrace { - private List preCallArguments; - private long timeStampEntry; - private InstanceReference instanceReference; - private MethodReference methodReference; - - @JsonCreator - public PartialTrace( - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("instanceReference") InstanceReference instanceReference, - @JsonProperty("methodReference") MethodReference methodReference) { - this.preCallArguments = preCallArguments; - this.timeStampEntry = timeStampEntry; - this.instanceReference = instanceReference; - this.methodReference = methodReference; - } - - public List getPreCallArguments() { - return preCallArguments; - } - - public void setPreCallArguments(List preCallArguments) { - this.preCallArguments = preCallArguments; - } - - public long getTimeStampEntry() { - return timeStampEntry; - } - - public void setTimeStampEntry(long timeStampEntry) { - this.timeStampEntry = timeStampEntry; - } - - public InstanceReference getInstanceReference() { - return instanceReference; - } - - public MethodReference getMethodReference() { - return methodReference; - } - - public void setInstanceReference(InstanceReference instanceReference) { - this.instanceReference = instanceReference; - } - - public void setMethodReference(MethodReference methodReference) { - this.methodReference = methodReference; - } -} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java deleted file mode 100644 index e277a415..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java +++ /dev/null @@ -1,6 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -public class TestTraceResults { - public Trace Trace; - public String Test; -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java deleted file mode 100644 index 9dee5a0a..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/instrumentation/models/Trace.java +++ /dev/null @@ -1,96 +0,0 @@ -package com.github.gilesi.instrumentation.models; - -import com.fasterxml.jackson.annotation.JsonCreator; -import com.fasterxml.jackson.annotation.JsonProperty; - -import java.util.List; - -public class Trace extends PartialTrace { - private List postCallArguments; - private InstanceReference returnedValue; - private long timeStampExit; - private InstanceReference exceptionThrown; - private String[] stackTrace; - private String confName; - private String[] confDescriptors; - - @JsonCreator - public Trace( - @JsonProperty("preCallArguments") List preCallArguments, - @JsonProperty("postCallArguments") List postCallArguments, - @JsonProperty("returnedValue") InstanceReference returnedValue, - @JsonProperty("timeStampEntry") long timeStampEntry, - @JsonProperty("timeStampExit") long timeStampExit, - @JsonProperty("exceptionThrown") InstanceReference exceptionThrown, - @JsonProperty("stackTrace") String[] stackTrace, - @JsonProperty("confName") String confName, - @JsonProperty("confDescriptors") String[] confDescriptors, - @JsonProperty("instanceReference") InstanceReference instanceReference, - @JsonProperty("methodReference") MethodReference methodReference) { - super(preCallArguments, timeStampEntry, instanceReference, methodReference); - - this.postCallArguments = postCallArguments; - this.returnedValue = returnedValue; - this.timeStampExit = timeStampExit; - this.exceptionThrown = exceptionThrown; - this.stackTrace = stackTrace; - this.confName = confName; - this.confDescriptors = confDescriptors; - } - - public List getPostCallArguments() { - return postCallArguments; - } - - public void setPostCallArguments(List postCallArguments) { - this.postCallArguments = postCallArguments; - } - - public InstanceReference getReturnedValue() { - return returnedValue; - } - - public void setReturnedValue(InstanceReference returnedValue) { - this.returnedValue = returnedValue; - } - - public long getTimeStampExit() { - return timeStampExit; - } - - public void setTimeStampExit(long timeStampExit) { - this.timeStampExit = timeStampExit; - } - - public InstanceReference getExceptionThrown() { - return exceptionThrown; - } - - public void setExceptionThrown(InstanceReference exceptionThrown) { - this.exceptionThrown = exceptionThrown; - } - - public String[] getStackTrace() { - return stackTrace; - } - - public void setStackTrace(String[] stackTrace) { - this.stackTrace = stackTrace; - } - - public String getConfName() { - return confName; - } - - public void setConfName(String confName) { - this.confName = confName; - } - - public String[] getConfDescriptors() { - return confDescriptors; - } - - public void setConfDescriptors(String[] confDescriptors) { - this.confDescriptors = confDescriptors; - } -} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java deleted file mode 100644 index 08f77c5d..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/Main.java +++ /dev/null @@ -1,504 +0,0 @@ -package com.github.gilesi.testgenerator; - -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.github.gilesi.instrumentation.models.TestTraceResults; -import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.instrumentation.models.InstanceReference; -import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; -import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; - -import java.io.File; -import java.io.IOException; -import java.nio.file.Files; -import java.nio.file.Path; -import java.nio.file.Paths; -import java.util.*; - -public class Main { - private static final ObjectMapper objectMapper = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - - // This is ugly, I know - private static int GetTraceNumber(Path i) { - return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); - } - - private static ArrayList readTraces(String traceXmlFolder) throws IOException { - ArrayList traces = new ArrayList<>(); - - List traceFiles = Files.list(Path.of(traceXmlFolder)) - .sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); - - for (Path testTraceFile : traceFiles) { - try { - TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), - TestTraceResults.class); - traces.add(testTraceResults.Trace); - } catch (Exception e) { - System.out.println("ERROR while deserializing a trace!"); - e.printStackTrace(); - } - } - - return traces; - } - - public static void writeMarker(List failure, String output) { - int mainPadding = 1; - String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, - mainPadding); - - while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, - ++mainPadding); - } - - try { - Files.write(new File(tracesFileName).toPath(), failure); - } catch (Throwable e) { - System.err.println("ERROR while saving marker"); - e.printStackTrace(); - } - } - - private static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { - if (name.length() == 0) { - return 0; - } - - return switch (name.charAt(0)) { - case 'I' -> 1; - case 'V' -> 1; - case 'Z' -> 1; - case 'B' -> 1; - case 'C' -> 1; - case 'S' -> 1; - case 'D' -> 1; - case 'F' -> 1; - case 'J' -> 1; - case 'L' -> name.indexOf(";") + 1; - case '[' -> getFirstArgLength(name.substring(1)) + 1; - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { - return switch (name.charAt(0)) { - case 'I' -> "java.lang.Integer"; - case 'V' -> "java.lang.Void"; - case 'Z' -> "java.lang.Boolean"; - case 'B' -> "java.lang.Byte"; - case 'C' -> "java.lang.Character"; - case 'S' -> "java.lang.Short"; - case 'D' -> "java.lang.Double"; - case 'F' -> "java.lang.Float"; - case 'J' -> "java.lang.Long"; - case 'L' -> name.substring(1, name.length() - 1).replace("/", "."); - case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - public static String getCleanedType(String FQN) { - int currentCharacterIndex = 0; - char currentCharacter = FQN.charAt(currentCharacterIndex); - while (currentCharacter == '[') { - currentCharacter = FQN.charAt(++currentCharacterIndex); - } - - if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || - (currentCharacter == 'L' && FQN.endsWith(";"))) { - try { - return JvmTypeToLangType(FQN).replace("$", "."); - } catch (UnsupportedJavaPrimitiveTypeException ignored) { - - } - } - return FQN.replace("$", "."); - } - - public static void main(String[] args) throws IOException { - - // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", - // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; - args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", - "/home/gus/Git/gilesi/Results/generated/tests" }; - - if (args.length != 2) { - System.out.println("Usage: "); - return; - } - - String traceXmlFolder = args[0]; - String testPath = args[1]; - - if (!Files.exists(Path.of(traceXmlFolder)) || !Files.isDirectory(Path.of(traceXmlFolder))) { - System.out.println( - "Argument 1 is not a Folder containing trace files. It either does not exist or is not a directory."); - return; - } - - if (!Files.exists(Path.of(testPath)) || !Files.isDirectory(Path.of(testPath))) { - System.out.println( - "Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); - return; - } - - ArrayList methodTraces = readTraces(traceXmlFolder); - - if (methodTraces.isEmpty()) { - System.out.println("No traces found!"); - } - - Path mainOutputPath = Path.of(testPath).toAbsolutePath(); - if (!Files.isDirectory(mainOutputPath)) { - Files.createDirectories(mainOutputPath); - } - - String packageName = "com.gilesi.testgen.generated"; - Path packageOutputPath = mainOutputPath.toAbsolutePath(); - - if (!packageName.isEmpty()) { - for (String element : packageName.split("\\.")) { - packageOutputPath = packageOutputPath.resolve(element); - } - - if (!Files.isDirectory(packageOutputPath)) { - Files.createDirectories(packageOutputPath); - } - } - - String className = "GilesiGeneratedTestClass"; - - Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); - - StringBuilder stringBuilder = new StringBuilder(); - - if (!packageName.isEmpty()) { - stringBuilder.append("package %s;\n\n".formatted(packageName)); - } - - stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); - stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); - stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); - stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); - stringBuilder.append("import org.junit.jupiter.api.Test;\n"); - stringBuilder.append("import java.lang.Throwable;\n"); - stringBuilder.append("\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); - stringBuilder.append("\n"); - - stringBuilder.append("public class %s {\n".formatted(className)); - - String testName = "ClientSourcedGeneratedTest"; - - stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(testName)); - - VariableStackHandler variableStackHandler = new VariableStackHandler(); - - StringBuilder testMethodStringBuilder = new StringBuilder(); - - for (int i = 0; i < methodTraces.size(); i++) { - - // System.out.println("==========================="); - - Trace trace = methodTraces.get(i); - - try { - String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; - methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - - InstanceReference instanceData = trace.getInstanceReference(); - - boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() - .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); - - InstanceReference returnData = trace.getReturnedValue(); - String returnVariableName = ""; - if (returnData != null) { - returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); - } - - String instanceVariableName = ""; - if (instanceData != null) { - instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); - } - - ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); - String argumentLine = argLineResult.argumentsForMethodCall; - List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, - variableStackHandler); - - /*for (String descr : trace.getConfDescriptors()) { - int startArg = descr.indexOf("("); - int endArg = descr.lastIndexOf(")"); - - String returns = descr.substring(endArg + 1, descr.length()); - String argusStr = descr.substring(startArg + 1, endArg); - - int length = 1; - List arguments = new ArrayList<>(); - String returnValue = null; - - do { - length = getFirstArgLength(argusStr); - String curArg = argusStr.substring(0, length); - argusStr = argusStr.substring(length); - if (curArg.length() != 0) { - arguments.add(getCleanedType(curArg)); - } - } while (length != 0); - - if (!returns.equals("V")) { - returnValue = getCleanedType(returns); - } - - System.out.println("Descriptor: " + descr); - - if (arguments.size() != 0) { - System.out.println("Arguments: (%s)".formatted(String.join(", ", arguments))); - } - - if (returnValue != null) { - System.out.println("Returns: " + returnValue); - } - } - System.out.println();/* */ - - if (trace.getMethodReference().getIsConstructor()) { - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); - instanceVariableName = String.format("%s %s", methodName, instanceVariableName); - } - - String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, - argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("%s\n", str)); - } - - testMethodStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append(returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("// %s\n", str)); - } - - testMethodStringBuilder.append("// " + callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append("// " + varAssert + "\n"); - } - } - } else { - StringBuilder callStringBuilder = new StringBuilder(); - - // Holds whenever or not an issue with instances was found - // If true, we should not create new variables and we should comment out the - // whole code. - // As the code simply is not generable. - boolean issuesDetected = false; - - if (isInstanceCall) { - // When we have an instance dependent call, we need the instance the call is - // performed onto to exist - // If it does not exist, then we cannot generate this code - // Log that, and comment out the code we would have generated. - // And make sure we do not create a variable for the return value if a thing. - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", - i + 1, methodName, instanceData.getInstanceId(), - instanceData.getClassReference().getFullyQualifiedTypeName()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - - issuesDetected = true; - } - - // An instance method call is not called by its fully qualified name (i.e. - // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. - String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); - } - - if (returnData != null) { - if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { - if (!issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.getInstanceId()); - } else { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", - i + 1, returnData.getInstanceId()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - } - - String returnType = getCleanedVar( - getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); - returnVariableName = String.format("%s %s", returnType, returnVariableName); - } - - String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - callStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append(returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } - - callStringBuilder.append("// " + callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append("// " + returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } - } - } else { - String callLine = String.format("%s(%s);\n", methodName, argumentLine); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - callStringBuilder.append(callLine); - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } - - callStringBuilder.append("// " + callLine); - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } - } - } - - // Append the method call to the current string builder. - if (issuesDetected) { - testMethodStringBuilder.append(String.format("// %s", callStringBuilder.toString())); - } else { - testMethodStringBuilder.append(callStringBuilder.toString()); - } - } - - if (i != methodTraces.size() - 1) { - testMethodStringBuilder.append("\n"); - } - } catch (Exception e) { - System.out.println("Unable to convert trace to code!"); - e.printStackTrace(); - writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - - stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); - } - } - - String padding = "\t\t"; - String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString() - .substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); - stringBuilder.append(String.format("%s\n\t}\n", paddedString)); - - stringBuilder.append(""" - - \tpublic static String getToXml(Object obj) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\treturn xStream.toXML(obj); - \t} - """); - - stringBuilder.append(""" - - \t@SuppressWarnings("unchecked") - \tpublic static T getFromXml(String xmlString) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\txStream.addPermission(AnyTypePermission.ANY); - \t\tObject obj = xStream.fromXML(xmlString); - \t\treturn (T) obj; - \t} - """); - - stringBuilder.append("}\n"); - stringBuilder.append("\n"); - - System.out.println(classOutputPath); - Files.deleteIfExists(classOutputPath); - Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); - } - - public static String getCleanedVar(String fullyQualifiedTypeName) { - String returnType = fullyQualifiedTypeName.replace("$", "."); - - try { - var el = returnType.split("\\."); - Integer.valueOf(el[el.length - 1]); - - // so this is a number, replace type with "var" as we have no idea. - returnType = "var"; - } catch (NumberFormatException e) { - // Not a number, continue - } - - if (returnType.contains("..")) { - // Bad type, use var - returnType = "var"; - } - - if (returnType.endsWith(".")) { - returnType = "var"; - } - - return returnType; - } -} \ No newline at end of file diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java deleted file mode 100644 index 36ae4cb5..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ /dev/null @@ -1,150 +0,0 @@ -package com.github.gilesi.testgenerator; - -import com.github.gilesi.instrumentation.models.ClassReference; -import com.github.gilesi.instrumentation.models.InstanceReference; -import com.github.gilesi.testgenerator.exceptions.SerializationException; -import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; -import org.apache.commons.text.StringEscapeUtils; - -import java.util.ArrayList; -import java.util.List; - -public class SerializationUtils { - private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { - return switch (name.charAt(0)) { - case 'I' -> "java.lang.Integer"; - case 'V' -> "java.lang.Void"; - case 'Z' -> "java.lang.Boolean"; - case 'B' -> "java.lang.Byte"; - case 'C' -> "java.lang.Character"; - case 'S' -> "java.lang.Short"; - case 'D' -> "java.lang.Double"; - case 'F' -> "java.lang.Float"; - case 'J' -> "java.lang.Long"; - case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); - case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - public static String getCleanedType(String FQN) { - int currentCharacterIndex = 0; - char currentCharacter = FQN.charAt(currentCharacterIndex); - while (currentCharacter == '[') { - currentCharacter = FQN.charAt(++currentCharacterIndex); - } - - if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || - (currentCharacter == 'L' && FQN.endsWith(";"))) { - try { - return JvmTypeToLangType(FQN).replace("$", "."); - } catch (UnsupportedJavaPrimitiveTypeException ignored) { - - } - } - return FQN.replace("$", "."); - } - - public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) - throws SerializationException { - String valueToBeEqualTo = serializableData.getValueAsXmlString(); - String FQN = getCleanedType(argClass.getFullyQualifiedTypeName()); - - if (!FQN.equals("java.lang.Integer") && - !FQN.equals("java.lang.Void") && - !FQN.equals("java.lang.Boolean") && - !FQN.equals("java.lang.Byte") && - !FQN.equals("java.lang.Character") && - !FQN.equals("java.lang.Short") && - !FQN.equals("java.lang.Double") && - !FQN.equals("java.lang.Float") && - !FQN.equals("java.lang.Long") && - !FQN.equals("java.lang.String")) { - - // int maxStringSize = (int) Math.pow(2, 16); - // TODO: Check why this still fails - int maxStringSize = 1024; - - if (serializableData.getValueAsXmlString().length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start = 0; start < serializableData.getValueAsXmlString().length(); start += maxStringSize) { - int end = start + maxStringSize; - if (start + maxStringSize > serializableData.getValueAsXmlString().length()) { - end = serializableData.getValueAsXmlString().length(); - } - - String sectionOfDataAsXml = "SNIP";// serializableData.getValueAsXmlString().substring(start, end); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - String finalEscapedValue = String.join(" + ", sectionList.toArray(String[]::new)); - - valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); - } else { - // Casting is not needed if we only use this with variable assignments that are - // strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, - // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - valueToBeEqualTo = "getFromXml(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - } - } else { - int start = valueToBeEqualTo.indexOf(">"); - int end = valueToBeEqualTo.lastIndexOf(" valueToBeEqualTo.length() - 1 - 3) { - throw new SerializationException("Malformed XML data"); - } - - valueToBeEqualTo = valueToBeEqualTo.substring(start + 1, end); - - if (FQN.equals("java.lang.Character")) { - valueToBeEqualTo = "'%s'".formatted(valueToBeEqualTo); - if (valueToBeEqualTo.equals("''")) { - valueToBeEqualTo = "java.lang.Character.MIN_VALUE"; - } - } else if (FQN.equals("java.lang.String")) { - // int maxStringSize = (int) Math.pow(2, 16); - // TODO: Check why this still fails - int maxStringSize = 1024; - - if (valueToBeEqualTo.length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueToBeEqualTo.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueToBeEqualTo.length()) { - end2 = valueToBeEqualTo.length(); - } - - String sectionOfDataAsXml = "SNIP";// valueToBeEqualTo.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - valueToBeEqualTo = String.join(" + ", sectionList.toArray(String[]::new)); - } else { - valueToBeEqualTo = "\"%s\"".formatted(StringEscapeUtils.escapeJava(valueToBeEqualTo)); - } - } else if (FQN.equals("java.lang.Float")) { - valueToBeEqualTo = "%sF".formatted(valueToBeEqualTo); - } else if (FQN.equals("java.lang.Long")) { - valueToBeEqualTo = "%sL".formatted(valueToBeEqualTo); - } - } - - return valueToBeEqualTo; - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java deleted file mode 100644 index 5639022a..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java +++ /dev/null @@ -1,22 +0,0 @@ -package com.github.gilesi.testgenerator; - -import java.util.ArrayList; -import java.util.List; - -public class VariableStackHandler { - private List variableInstances = new ArrayList<>(); - - public void CreateNewVariable(int instanceId) { - if (!DoesVariableExist(instanceId)) { - variableInstances.add(instanceId); - } - } - - public boolean DoesVariableExist(int instanceId) { - return variableInstances.contains(instanceId); - } - - public static String getVariableName(int instanceId) { - return String.format("var%d", instanceId); - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java deleted file mode 100644 index e502a6b1..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/SerializationException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.gilesi.testgenerator.exceptions; - -public class SerializationException extends Exception { - public SerializationException(String message) { - super(message); - } -} diff --git a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java b/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java deleted file mode 100644 index 47ae435c..00000000 --- a/TestGenerator2/src/main/java/com/github/gilesi/testgenerator/exceptions/UnsupportedJavaPrimitiveTypeException.java +++ /dev/null @@ -1,7 +0,0 @@ -package com.github.gilesi.testgenerator.exceptions; - -public class UnsupportedJavaPrimitiveTypeException extends Exception { - public UnsupportedJavaPrimitiveTypeException(String primitive) { - super("Unsupported primitive type: %s".formatted(primitive)); - } -} diff --git a/maracas-test.cmd b/maracas-test.cmd deleted file mode 100644 index ddbda5d4..00000000 --- a/maracas-test.cmd +++ /dev/null @@ -1,44 +0,0 @@ -@echo off - -call run-clean-workflow.cmd -call compile.cmd - -set JAVA_HOME=C:\Users\Gus\.jdks\openjdk-21.0.2 -set MAVEN_HOME=C:\Users\Gus\AppData\Local\Programs\IntelliJ IDEA Ultimate\plugins\maven\lib\maven3 - - -echo. -echo =========================================================== -echo Running ConfGen -echo =========================================================== -echo. - -%JAVA_HOME%\bin\java.exe -jar "%CD%\ConfGen\build\libs\com.github.gilesi.confgen.jar" "%CD%\MaracasConfiguration.json" "%CD%\Traces.Output" "C:\Users\Gus\Documents\GitHub\maracas\core" "C:\Users\Gus\Documents\GitHub\maracas\forges" - -echo. -echo =========================================================== -echo Running Maracas Forges' Test Suite with Agent -echo =========================================================== -echo. - -set CURRENT_DIR=%CD% -cd C:\Users\Gus\Documents\GitHub\maracas\forges -call "%MAVEN_HOME%\bin\mvn" surefire:test -cd %CURRENT_DIR% - - -echo. -echo =========================================================== -echo Running TestGenerator -echo =========================================================== -echo. - -%JAVA_HOME%\bin\java.exe -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Traces.Output\MethodTraces.json" "%CD%\TestGenerator.Output" - -mkdir Results - -move %CD%\MaracasConfiguration.json Results\ -move %CD%\Traces.Output\gilesi.instrumentation.log Results\ -move %CD%\Traces.Output\MethodTraces.json Results\ -move %CD%\Traces.Output\*.json Results\ -move %CD%\TestGenerator.Output Results\ diff --git a/maracas-test.sh b/maracas-test.sh deleted file mode 100755 index 8ce4a79c..00000000 --- a/maracas-test.sh +++ /dev/null @@ -1,41 +0,0 @@ -#!/bin/bash - -sh run-clean-workflow.sh -sh compile.sh - - -echo -echo =========================================================== -echo Running ConfGen -echo =========================================================== -echo - -$JAVA_HOME/bin/java -jar "$PWD/ConfGen/build/libs/com.github.gilesi.confgen.jar" "$PWD/MaracasConfiguration.json" "$PWD/Traces.Output" "/mnt/c/Users/Gus/Documents/GitHub/maracas/core" "/mnt/c/Users/Gus/Documents/GitHub/maracas/forges" - -echo -echo =========================================================== -echo $'Running Maracas Forges\' Test Suite with Agent' -echo =========================================================== -echo - -CURRENT_DIR=$PWD -cd /mnt/c/Users/Gus/Documents/GitHub/maracas/forges -sh "$MAVEN_HOME/bin/mvn" surefire:test -cd $CURRENT_DIR - - -echo -echo =========================================================== -echo Running TestGenerator -echo =========================================================== -echo - -$JAVA_HOME/bin/java -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Traces.Output/MethodTraces.json" "$PWD/TestGenerator.Output" - -mkdir Results - -mv $PWD/MaracasConfiguration.json Results/ -mv $PWD/Traces.Output/gilesi.instrumentation.log Results/ -mv $PWD/Traces.Output/MethodTraces.json Results/ -mv $PWD/Traces.Output/*.json Results/ -mv $PWD/TestGenerator.Output Results/ diff --git a/oldlogs/surefire.txt b/oldlogs/surefire.txt deleted file mode 100644 index 2c0dc28b..00000000 --- a/oldlogs/surefire.txt +++ /dev/null @@ -1,3284 +0,0 @@ -22:17:56.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit --- -22:17:56.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:17:56.276 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:17:56.316 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:17:56.332 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:17:56.349 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:17:56.457 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:17:56.478 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:17:57.625 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:17:57.687 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:17:57.701 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:17:57.715 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:17:58.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:17:58.478 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:17:58.491 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:17:58.509 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:17:58.527 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:17:58.547 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:05.695 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit --- -22:18:05.901 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:18:05.947 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:18:05.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:18:05.978 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:18:05.993 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:18:06.101 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:18:06.119 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:18:07.218 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:18:07.284 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:18:07.293 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:18:07.303 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:18:07.764 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:18:07.775 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:18:07.787 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:18:07.798 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:18:07.811 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:18:07.826 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:14.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit --- -22:18:14.954 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:18:14.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:18:15.001 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:18:15.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:18:15.035 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:18:15.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:18:15.150 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:18:16.224 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:18:16.292 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:18:16.300 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:18:16.309 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:18:16.318 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:18:16.328 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:18:16.337 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:18:16.856 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:18:16.869 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:18:16.884 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:23.365 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit --- -22:18:23.573 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:18:23.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:18:23.620 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:18:23.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:18:23.644 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:18:23.725 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:18:23.735 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:18:24.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:18:24.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:18:24.930 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:18:24.939 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:18:24.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:18:24.959 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:18:24.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:18:25.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:18:25.419 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:18:25.436 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:31.851 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit --- -22:18:32.079 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:18:32.665 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:18:32.678 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:18:32.691 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:18:32.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:18:32.800 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:18:32.809 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:18:33.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:18:33.923 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:18:33.931 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:18:33.940 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:18:33.949 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:18:33.959 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:18:33.969 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:18:33.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:18:33.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:18:34.007 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:38.864 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-guava --- -22:18:39.321 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-java8 --- -22:18:39.339 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava --- -22:18:39.355 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-rxjava2 --- -22:18:39.369 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ adapter-scala --- -22:18:39.470 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-gson --- -22:18:39.477 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-guava --- -22:18:40.383 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-protobuf --- -22:18:40.443 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jackson --- -22:18:40.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-java8 --- -22:18:40.457 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-wire --- -22:18:40.465 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-simplexml --- -22:18:40.473 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-scalars --- -22:18:40.486 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-moshi --- -22:18:40.498 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ converter-jaxb --- -22:18:40.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ retrofit-mock --- -22:18:40.515 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ samples --- -22:18:42.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:18:42.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:18:43.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:18:44.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:18:45.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:18:46.161 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:18:46.304 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:18:46.414 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:18:47.817 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:18:47.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:18:48.058 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:18:48.155 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:18:49.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:18:50.254 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:18:51.164 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:18:53.110 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:18:54.275 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:18:54.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:18:54.643 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:18:54.747 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:18:56.260 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:18:56.403 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:18:56.583 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:18:56.697 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:18:58.664 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:18:58.994 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:19:00.033 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:19:00.905 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:19:01.915 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:19:02.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:19:02.292 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:19:02.436 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:19:03.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:19:04.091 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:19:04.198 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:19:04.287 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:19:09.247 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:19:09.525 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:19:10.393 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:19:11.115 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:19:12.059 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:19:12.251 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:19:12.389 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:19:12.515 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:19:13.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:19:14.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:19:14.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:19:14.265 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:19:19.309 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:19:19.653 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:19:20.568 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:19:21.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:19:22.384 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:19:30.013 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:19:30.160 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:19:30.271 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:19:31.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:19:32.010 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:19:32.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:19:32.204 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:19:33.894 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-buildtools --- -22:19:34.263 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-core --- -22:19:35.312 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-client --- -22:19:36.219 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-common --- -22:19:37.150 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-biz --- -22:19:48.358 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-configservice --- -22:19:48.509 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-adminservice --- -22:19:48.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-openapi --- -22:19:50.000 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-portal --- -22:19:50.156 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-assembly --- -22:19:50.268 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-demo --- -22:19:50.352 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ apollo-mockserver --- -22:19:52.374 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ druid --- -22:19:55.135 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ druid --- -22:19:57.227 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18:test (default-test) @ webmagic-saxon --- -22:19:58.744 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18:test (default-test) @ webmagic-saxon --- -22:20:01.140 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-core --- -22:20:01.230 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-en --- -22:20:01.254 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fa --- -22:20:01.281 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fr --- -22:20:01.319 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de --- -22:20:01.344 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pl --- -22:20:01.370 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ca --- -22:20:01.393 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-it --- -22:20:01.413 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-br --- -22:20:01.435 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-nl --- -22:20:01.461 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pt --- -22:20:01.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ru --- -22:20:01.507 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ast --- -22:20:01.528 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-be --- -22:20:01.553 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-zh --- -22:20:01.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-da --- -22:20:01.602 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-eo --- -22:20:01.624 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-gl --- -22:20:01.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-el --- -22:20:01.681 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-is --- -22:20:01.712 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ja --- -22:20:01.737 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-km --- -22:20:01.762 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-lt --- -22:20:01.783 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ml --- -22:20:01.808 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ro --- -22:20:01.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sk --- -22:20:01.853 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sl --- -22:20:01.876 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-es --- -22:20:01.914 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sv --- -22:20:01.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ta --- -22:20:01.957 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-tl --- -22:20:01.981 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-uk --- -22:20:02.001 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de-DE-x-simple-language --- -22:20:02.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-all --- -22:20:02.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-gui-commons --- -22:20:02.074 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-commandline --- -22:20:02.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-server --- -22:20:02.157 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-tools --- -22:20:02.225 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-standalone --- -22:20:02.277 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-office-extension --- -22:20:02.281 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ hunspell-native-libs --- -22:20:02.357 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-wikipedia --- -22:20:03.491 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-http-client --- -22:20:03.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-dev --- -22:20:03.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool --- -22:20:05.606 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-core --- -22:20:05.694 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-en --- -22:20:05.717 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fa --- -22:20:05.744 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fr --- -22:20:05.780 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de --- -22:20:05.805 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pl --- -22:20:05.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ca --- -22:20:05.854 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-it --- -22:20:05.875 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-br --- -22:20:05.897 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-nl --- -22:20:05.922 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pt --- -22:20:05.957 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ru --- -22:20:05.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ast --- -22:20:05.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-be --- -22:20:06.022 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-zh --- -22:20:06.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-da --- -22:20:06.069 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-eo --- -22:20:06.091 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-gl --- -22:20:06.111 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-el --- -22:20:06.126 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-is --- -22:20:06.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ja --- -22:20:06.164 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-km --- -22:20:06.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-lt --- -22:20:06.206 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ml --- -22:20:06.231 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ro --- -22:20:06.253 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sk --- -22:20:06.273 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sl --- -22:20:06.296 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-es --- -22:20:06.317 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sv --- -22:20:06.345 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ta --- -22:20:06.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-tl --- -22:20:06.390 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-uk --- -22:20:06.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de-DE-x-simple-language --- -22:20:06.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-all --- -22:20:06.437 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-gui-commons --- -22:20:06.488 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-commandline --- -22:20:06.562 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-server --- -22:20:06.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-tools --- -22:20:06.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-standalone --- -22:20:06.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-office-extension --- -22:20:06.706 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ hunspell-native-libs --- -22:20:06.809 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-wikipedia --- -22:20:07.614 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-http-client --- -22:20:07.707 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-dev --- -22:20:07.719 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool --- -22:20:10.284 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-core --- -22:20:11.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-en --- -22:20:11.074 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fa --- -22:20:11.097 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fr --- -22:20:11.130 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de --- -22:20:11.168 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pl --- -22:20:11.193 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ca --- -22:20:11.213 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-it --- -22:20:11.233 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-br --- -22:20:11.256 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-nl --- -22:20:11.285 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pt --- -22:20:11.307 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ru --- -22:20:11.325 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ast --- -22:20:11.342 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-be --- -22:20:11.361 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-zh --- -22:20:11.383 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-da --- -22:20:11.409 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-eo --- -22:20:11.428 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-gl --- -22:20:11.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-el --- -22:20:11.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-is --- -22:20:11.492 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ja --- -22:20:11.523 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-km --- -22:20:11.559 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-lt --- -22:20:11.606 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ml --- -22:20:11.635 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ro --- -22:20:11.658 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sk --- -22:20:11.677 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sl --- -22:20:11.698 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-es --- -22:20:11.718 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sv --- -22:20:11.737 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ta --- -22:20:11.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-tl --- -22:20:11.780 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-uk --- -22:20:11.801 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de-DE-x-simple-language --- -22:20:11.810 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-all --- -22:20:11.826 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-gui-commons --- -22:20:11.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-commandline --- -22:20:11.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-server --- -22:20:11.985 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-tools --- -22:20:12.058 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-standalone --- -22:20:12.128 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-office-extension --- -22:20:12.137 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ hunspell-native-libs --- -22:20:12.237 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-wikipedia --- -22:20:12.271 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-http-client --- -22:20:12.331 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-dev --- -22:20:12.337 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool --- -22:20:14.487 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-core --- -22:20:15.216 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-en --- -22:20:15.243 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fa --- -22:20:15.267 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-fr --- -22:20:15.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de --- -22:20:15.324 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pl --- -22:20:15.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ca --- -22:20:15.387 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-it --- -22:20:15.406 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-br --- -22:20:15.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-nl --- -22:20:15.453 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-pt --- -22:20:15.475 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ru --- -22:20:15.492 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ast --- -22:20:15.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-be --- -22:20:15.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-zh --- -22:20:15.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-da --- -22:20:15.573 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-eo --- -22:20:15.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-gl --- -22:20:15.613 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-el --- -22:20:15.630 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-is --- -22:20:15.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ja --- -22:20:15.674 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-km --- -22:20:15.693 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-lt --- -22:20:15.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ml --- -22:20:15.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ro --- -22:20:15.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sk --- -22:20:15.782 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sl --- -22:20:15.801 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-es --- -22:20:15.821 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-sv --- -22:20:15.839 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-ta --- -22:20:15.857 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-tl --- -22:20:15.881 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-uk --- -22:20:15.907 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-de-DE-x-simple-language --- -22:20:15.916 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ language-all --- -22:20:15.932 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-gui-commons --- -22:20:15.983 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-commandline --- -22:20:16.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-server --- -22:20:16.067 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-tools --- -22:20:16.140 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-standalone --- -22:20:16.204 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-office-extension --- -22:20:16.208 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ hunspell-native-libs --- -22:20:16.287 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-wikipedia --- -22:20:16.317 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-http-client --- -22:20:16.375 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool-dev --- -22:20:16.381 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ languagetool --- -22:20:18.681 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd --- -22:20:19.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-webserver --- -22:20:19.816 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-samples --- -22:20:19.893 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-websocket --- -22:20:19.931 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-webserver-markdown-plugin --- -22:20:19.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-nanolets --- -22:20:20.013 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-apache-fileupload --- -22:20:22.100 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd --- -22:20:22.938 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-webserver --- -22:20:22.976 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-samples --- -22:20:23.043 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-websocket --- -22:20:23.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-webserver-markdown-plugin --- -22:20:23.126 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-nanolets --- -22:20:23.171 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ nanohttpd-apache-fileupload --- -22:20:25.413 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-filesystem --- -22:20:27.235 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-common --- -22:20:27.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-transport --- -22:20:32.277 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-core --- -22:20:34.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-server --- -22:20:35.815 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-controller --- -22:20:37.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-broker --- -22:20:38.650 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-api --- -22:20:39.352 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop --- -22:20:40.263 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-tools --- -22:20:41.377 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-minion --- -22:20:44.087 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-integration-tests --- -22:20:46.027 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-perf --- -22:20:47.327 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop-filesystem --- -22:20:47.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-azure-filesystem --- -22:20:51.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-filesystem --- -22:20:54.290 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-transport --- -22:20:57.504 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-server --- -22:20:58.596 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-controller --- -22:20:59.106 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-broker --- -22:20:59.786 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-api --- -22:21:00.340 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop --- -22:21:00.670 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-tools --- -22:21:01.117 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-minion --- -22:21:03.050 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-integration-tests --- -22:21:04.374 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-perf --- -22:21:05.209 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop-filesystem --- -22:21:05.372 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-azure-filesystem --- -22:21:08.848 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-filesystem --- -22:21:10.422 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-common --- -22:21:10.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-transport --- -22:21:15.375 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-core --- -22:21:17.034 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-server --- -22:21:18.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-controller --- -22:21:20.405 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-broker --- -22:21:21.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-api --- -22:21:22.173 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop --- -22:21:23.161 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-tools --- -22:21:24.218 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-minion --- -22:21:25.448 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-integration-tests --- -22:21:33.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-perf --- -22:21:34.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop-filesystem --- -22:21:35.120 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-azure-filesystem --- -22:21:39.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-filesystem --- -22:21:41.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-common --- -22:21:42.417 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-transport --- -22:21:48.850 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-server --- -22:21:50.529 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-controller --- -22:21:51.654 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-broker --- -22:21:52.757 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-api --- -22:21:53.552 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop --- -22:21:54.537 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-tools --- -22:21:55.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-minion --- -22:21:56.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-integration-tests --- -22:22:01.273 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-perf --- -22:22:02.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-hadoop-filesystem --- -22:22:02.678 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ pinot-azure-filesystem --- -22:22:06.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ core --- -22:22:06.620 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ datastore-specific-descriptor --- -22:22:07.269 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.6-binding --- -22:22:07.749 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.7-binding --- -22:22:08.263 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.8-binding --- -22:22:08.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ aerospike-binding --- -22:22:09.010 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ arangodb-binding --- -22:22:09.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ asynchbase-binding --- -22:22:09.981 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.8:test (default-test) @ cassandra-binding --- -22:22:10.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cloudspanner-binding --- -22:22:10.971 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchbase-binding --- -22:22:11.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchbase2-binding --- -22:22:11.738 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ crail-binding --- -22:22:12.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ azurecosmos-binding --- -22:22:12.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ azuretablestorage-binding --- -22:22:13.265 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dynamodb-binding --- -22:22:13.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ elasticsearch-binding --- -22:22:14.847 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ foundationdb-binding --- -22:22:15.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ geode-binding --- -22:22:15.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ googledatastore-binding --- -22:22:16.088 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ googlebigtable-binding --- -22:22:16.445 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ griddb-binding --- -22:22:16.833 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase098-binding --- -22:22:17.237 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase10-binding --- -22:22:17.542 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase12-binding --- -22:22:17.859 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase14-binding --- -22:22:18.195 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase20-binding --- -22:22:18.553 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hypertable-binding --- -22:22:19.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ignite-binding --- -22:22:19.388 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ infinispan-binding --- -22:22:19.811 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jdbc-binding --- -22:22:20.184 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ kudu-binding --- -22:22:20.534 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ memcached-binding --- -22:22:21.132 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ maprjsondb-binding --- -22:22:21.657 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nosqldb-binding --- -22:22:22.031 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ orientdb-binding --- -22:22:22.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ postgrenosql-binding --- -22:22:22.723 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rados-binding --- -22:22:23.051 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ redis-binding --- -22:22:23.469 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rest-binding --- -22:22:27.434 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ riak-binding --- -22:22:27.817 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocksdb-binding --- -22:22:28.178 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ s3-binding --- -22:22:28.570 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ solr-binding --- -22:22:28.946 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ solr6-binding --- -22:22:29.260 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ tarantool-binding --- -22:22:29.644 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ tablestore-binding --- -22:22:30.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ voltdb-binding --- -22:22:32.834 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ core --- -22:22:32.971 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ datastore-specific-descriptor --- -22:22:33.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.6-binding --- -22:22:34.116 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.7-binding --- -22:22:34.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ accumulo1.8-binding --- -22:22:34.941 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ aerospike-binding --- -22:22:35.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ arangodb-binding --- -22:22:35.752 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ asynchbase-binding --- -22:22:36.302 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.8:test (default-test) @ cassandra-binding --- -22:22:36.899 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cloudspanner-binding --- -22:22:37.278 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchbase-binding --- -22:22:37.729 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchbase2-binding --- -22:22:38.063 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ crail-binding --- -22:22:38.825 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ azurecosmos-binding --- -22:22:39.162 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ azuretablestorage-binding --- -22:22:39.573 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dynamodb-binding --- -22:22:39.990 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ elasticsearch-binding --- -22:22:41.134 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ foundationdb-binding --- -22:22:41.514 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ geode-binding --- -22:22:41.872 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ googledatastore-binding --- -22:22:42.325 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ googlebigtable-binding --- -22:22:42.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ griddb-binding --- -22:22:43.051 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase098-binding --- -22:22:43.446 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase10-binding --- -22:22:43.744 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase12-binding --- -22:22:44.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase14-binding --- -22:22:44.355 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hbase20-binding --- -22:22:44.721 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ hypertable-binding --- -22:22:45.184 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ignite-binding --- -22:22:45.545 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ infinispan-binding --- -22:22:45.976 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jdbc-binding --- -22:22:46.335 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ kudu-binding --- -22:22:46.691 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ memcached-binding --- -22:22:47.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ maprjsondb-binding --- -22:22:47.842 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nosqldb-binding --- -22:22:48.209 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ orientdb-binding --- -22:22:48.581 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ postgrenosql-binding --- -22:22:48.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rados-binding --- -22:22:49.202 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ redis-binding --- -22:22:49.628 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rest-binding --- -22:22:53.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ riak-binding --- -22:22:53.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocksdb-binding --- -22:22:54.201 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ s3-binding --- -22:22:54.572 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ solr-binding --- -22:22:54.943 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ solr6-binding --- -22:22:55.286 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ tarantool-binding --- -22:22:55.671 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ tablestore-binding --- -22:22:56.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ voltdb-binding --- -22:22:58.330 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ mockserver-core --- -22:23:00.957 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ mockserver-core --- -22:23:04.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:23:04.604 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:23:04.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:23:05.229 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:23:05.271 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:23:05.554 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:23:05.857 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:23:05.917 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:23:06.805 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:23:07.460 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:23:07.572 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:23:07.897 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:23:07.927 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:23:08.216 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:23:08.642 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:23:08.953 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-guice --- -22:23:09.111 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:23:09.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:23:09.507 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:23:12.725 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:23:12.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:23:12.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:23:12.981 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:23:13.695 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:23:13.870 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:23:13.929 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:23:14.035 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:23:14.257 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-mvc --- -22:23:14.340 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-xml --- -22:23:14.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:23:14.520 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:23:14.646 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:23:14.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:23:14.780 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:23:14.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:23:15.099 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:23:15.156 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:23:15.274 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:23:15.356 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:23:18.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:23:18.542 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:23:18.884 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:23:19.202 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:23:19.240 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:23:19.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:23:19.813 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:23:19.868 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:23:20.908 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:23:21.601 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:23:21.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:23:22.014 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:23:22.040 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:23:22.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:23:22.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:23:23.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-guice --- -22:23:23.245 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:23:23.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:23:23.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:23:26.543 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:23:26.655 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:23:26.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:23:26.802 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:23:27.480 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:23:27.622 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:23:27.675 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:23:27.737 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:23:28.793 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:23:28.864 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:23:28.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:23:29.059 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:23:29.120 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:23:29.225 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:23:29.507 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:23:29.553 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:23:29.655 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:23:29.723 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:23:32.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:23:32.699 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:23:33.051 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:23:33.351 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:23:33.393 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:23:33.638 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:23:33.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:23:34.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:23:34.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:23:35.579 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:23:35.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:23:36.017 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:23:36.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:23:36.379 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:23:36.778 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:23:37.105 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-guice --- -22:23:38.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:23:38.497 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:23:38.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:23:38.756 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:23:38.882 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:23:38.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:23:39.037 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:23:39.833 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:23:40.001 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:23:40.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:23:40.152 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:23:40.379 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-mvc --- -22:23:40.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-xml --- -22:23:40.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:23:40.659 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:23:40.778 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:23:40.854 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:23:40.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:23:40.973 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:23:41.249 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:23:41.304 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:23:41.421 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:23:41.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:23:44.622 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:23:44.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:23:45.017 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:23:45.356 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:23:45.397 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:23:45.643 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:23:45.954 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:23:46.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:23:46.913 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:23:47.526 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:23:47.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:23:47.929 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:23:47.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:23:48.239 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:23:48.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:23:49.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:23:49.494 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:23:49.711 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:23:49.778 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:23:49.894 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:23:50.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:23:50.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:23:50.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:23:50.930 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:23:51.012 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:23:51.105 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:23:51.341 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-mvc --- -22:23:51.426 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-xml --- -22:23:51.546 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:23:51.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:23:51.722 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:23:51.788 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:23:51.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:23:51.895 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:23:52.163 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:23:52.212 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:23:52.326 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:23:52.392 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:23:56.330 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:23:56.404 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:23:56.789 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:23:57.084 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:23:57.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:23:57.385 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:23:57.694 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:23:57.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:23:58.727 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:24:00.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:24:00.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:24:00.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:24:00.992 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:24:01.300 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:24:01.735 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:24:02.041 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-guice --- -22:24:02.181 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:24:02.378 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:24:02.571 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:24:02.627 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:24:02.756 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:24:02.861 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:24:02.910 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:24:03.569 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:24:03.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:24:03.767 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:24:03.827 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:24:04.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-mvc --- -22:24:04.174 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-xml --- -22:24:04.276 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:24:04.350 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:24:04.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:24:04.547 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:24:04.606 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:24:04.670 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:24:04.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:24:05.027 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:24:05.147 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:24:05.222 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:24:08.399 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-lang --- -22:24:08.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-core --- -22:24:08.804 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-hash --- -22:24:09.129 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-crypto-cipher --- -22:24:09.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-event --- -22:24:09.416 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cache --- -22:24:09.710 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-core --- -22:24:09.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-config-ogdl --- -22:24:10.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-core --- -22:24:12.466 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-web --- -22:24:12.579 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-aspectj --- -22:24:12.913 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-ehcache --- -22:24:12.940 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-hazelcast --- -22:24:13.259 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-quartz --- -22:24:13.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring --- -22:24:13.978 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-guice --- -22:24:14.124 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-cas --- -22:24:14.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-starter --- -22:24:14.522 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-spring-boot-web-starter --- -22:24:14.585 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-servlet-plugin --- -22:24:14.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-jaxrs --- -22:24:14.805 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-aspectj --- -22:24:14.850 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart --- -22:24:15.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-support --- -22:24:15.716 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-web --- -22:24:15.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-client --- -22:24:15.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring --- -22:24:16.041 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-mvc --- -22:24:16.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-xml --- -22:24:16.260 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-sprhib --- -22:24:16.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot --- -22:24:16.476 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-spring-boot-web --- -22:24:16.546 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-guice --- -22:24:16.614 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-quickstart-guice --- -22:24:16.677 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-servlet-plugin --- -22:24:16.928 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ samples-jaxrs --- -22:24:16.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-tools-hasher --- -22:24:17.085 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice3 --- -22:24:17.155 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ shiro-its-guice4 --- -22:24:20.287 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ aws-java-sdk-core --- -22:24:23.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ aws-java-sdk-core --- -22:24:25.616 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ decryptor --- -22:24:25.742 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ config --- -22:24:25.772 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ utility --- -22:24:25.796 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ http-string --- -22:24:25.827 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ http-url --- -22:24:25.852 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ service --- -22:24:25.871 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ status --- -22:24:25.891 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ common --- -22:24:25.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ handler --- -22:24:25.928 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ monad-result --- -22:24:25.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ switcher --- -22:24:25.981 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ registry --- -22:24:25.997 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ balance --- -22:24:26.014 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ cluster --- -22:24:27.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ client --- -22:24:27.455 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ exception --- -22:24:27.487 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ security --- -22:24:27.504 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ correlation --- -22:24:27.523 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ mask --- -22:24:27.542 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ audit --- -22:24:27.559 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ body --- -22:24:27.587 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ dump --- -22:24:27.607 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ info --- -22:24:27.627 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ health --- -22:24:27.644 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ header --- -22:24:27.666 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ consul --- -22:24:27.693 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ zookeeper --- -22:24:27.740 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ server --- -22:24:27.783 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ metrics --- -22:24:27.819 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ prometheus --- -22:24:27.862 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ sanitizer --- -22:24:27.886 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ traceability --- -22:24:27.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ cors --- -22:24:27.929 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ rate-limit --- -22:24:27.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ email-sender --- -22:24:27.975 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ resource --- -22:24:27.995 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ content --- -22:24:28.023 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ data-source --- -22:24:28.052 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ basic-auth --- -22:24:28.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ deref-token --- -22:24:28.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ ip-whitelist --- -22:24:28.119 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ encode-decode --- -22:24:28.133 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ logger-config --- -22:24:29.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ decryptor --- -22:24:29.917 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ config --- -22:24:30.565 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ http-string --- -22:24:30.598 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ http-url --- -22:24:32.283 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ monad-result --- -22:24:32.295 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ switcher --- -22:24:32.316 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ registry --- -22:24:32.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ balance --- -22:24:32.346 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ cluster --- -22:24:38.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ zookeeper --- -22:24:46.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:24:47.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:00.256 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:25:00.354 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:25:00.567 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:25:01.805 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:25:03.342 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:10.522 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:25:10.624 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:25:10.836 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:25:12.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:25:13.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:15.655 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:25:15.762 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:25:15.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:25:17.227 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:25:18.775 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:20.750 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:25:20.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:25:21.073 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:25:22.357 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:25:23.878 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:25.159 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:25:39.960 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:25:40.158 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:25:41.321 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-commons --- -22:25:42.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-modules --- -22:25:44.004 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-engine --- -22:50:48.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default) @ heritrix --- -22:50:48.587 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.9:test (default-test) @ heritrix-contrib --- -22:50:49.939 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest-common --- -22:50:50.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest --- -22:50:56.194 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest-droid --- -22:50:57.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest-common --- -22:50:57.547 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest --- -22:51:03.580 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jest-droid --- -22:51:04.730 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient --- -22:51:04.829 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_common --- -22:51:04.853 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_caffeine --- -22:51:04.876 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_dropwizard --- -22:51:04.886 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_graphite_bridge --- -22:51:04.915 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_hibernate --- -22:51:04.931 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_guava --- -22:51:04.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_servlet --- -22:51:04.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_hotspot --- -22:51:04.969 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_httpserver --- -22:51:04.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_log4j --- -22:51:04.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_log4j2 --- -22:51:04.999 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_logback --- -22:51:05.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_pushgateway --- -22:51:05.073 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_spring_web --- -22:51:05.684 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_spring_boot --- -22:51:05.701 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_jetty --- -22:51:05.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_jetty_jdk8 --- -22:51:05.733 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_vertx --- -22:51:05.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ benchmarks --- -22:51:06.895 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient --- -22:51:06.975 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_common --- -22:51:06.993 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_caffeine --- -22:51:07.011 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_dropwizard --- -22:51:07.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_graphite_bridge --- -22:51:07.054 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_hibernate --- -22:51:07.067 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_guava --- -22:51:07.087 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_servlet --- -22:51:07.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_hotspot --- -22:51:07.107 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_httpserver --- -22:51:07.117 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_log4j --- -22:51:07.130 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_log4j2 --- -22:51:07.149 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_logback --- -22:51:07.195 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_pushgateway --- -22:51:07.215 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_spring_web --- -22:51:07.543 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_spring_boot --- -22:51:07.558 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_jetty --- -22:51:07.571 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_jetty_jdk8 --- -22:51:07.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ simpleclient_vertx --- -22:51:07.608 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.15:test (default-test) @ benchmarks --- -22:51:09.754 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ rocketmq-spring-boot --- -22:51:11.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ rocketmq-spring-boot-starter --- -22:51:13.794 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ rocketmq-spring-boot --- -22:51:15.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ rocketmq-spring-boot-starter --- -22:51:17.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ build-tools --- -22:51:19.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ annotations --- -22:51:23.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ utils --- -22:51:25.356 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-spi --- -22:51:28.253 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ test-utils --- -22:51:30.070 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ profiles --- -22:51:31.482 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-tests --- -22:51:33.708 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apache-client --- -22:51:37.043 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ netty-nio-client --- -22:51:41.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sdk-core --- -22:51:43.945 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite --- -22:51:45.767 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite-maven-plugin --- -22:51:49.786 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ regions --- -22:51:52.663 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ auth --- -22:51:54.948 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-core --- -22:51:56.533 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-core --- -22:51:59.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-json-protocol --- -22:52:00.352 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ service-test-utils --- -22:52:02.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-cbor-protocol --- -22:52:04.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-ion-protocol --- -22:52:06.134 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-query-protocol --- -22:52:08.319 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-xml-protocol --- -22:52:14.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen --- -22:52:16.644 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-maven-plugin --- -22:52:17.823 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acm --- -22:52:18.595 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acmpca --- -22:52:21.211 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ alexaforbusiness --- -22:52:22.016 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ amplify --- -22:52:25.616 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigateway --- -22:52:25.720 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewaymanagementapi --- -22:52:27.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewayv2 --- -22:52:27.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationautoscaling --- -22:52:28.034 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationdiscovery --- -22:52:28.800 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appmesh --- -22:52:29.803 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appstream --- -22:52:30.545 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appsync --- -22:52:30.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ athena --- -22:52:34.863 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iam --- -22:52:35.288 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sts --- -22:52:35.873 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sqs --- -22:52:36.503 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sns --- -22:52:37.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscaling --- -22:52:38.038 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscalingplans --- -22:52:39.014 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ backup --- -22:52:39.569 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ batch --- -22:52:39.854 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ budgets --- -22:52:41.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ chime --- -22:52:41.809 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloud9 --- -22:52:43.743 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ clouddirectory --- -22:52:45.631 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ arns --- -22:52:46.144 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3control --- -22:52:47.191 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kms --- -22:52:49.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3 --- -22:52:51.008 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudformation --- -22:52:52.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudfront --- -22:52:52.543 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsm --- -22:52:52.834 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsmv2 --- -22:52:53.343 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearch --- -22:52:53.529 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearchdomain --- -22:52:54.099 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudtrail --- -22:52:54.789 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatch --- -22:52:55.315 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchevents --- -22:52:56.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchlogs --- -22:52:56.771 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codebuild --- -22:52:59.446 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codecommit --- -22:53:00.727 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codedeploy --- -22:53:01.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codepipeline --- -22:53:01.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestar --- -22:53:02.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentity --- -22:53:04.549 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentityprovider --- -22:53:04.859 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitosync --- -22:53:05.947 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehend --- -22:53:06.263 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehendmedical --- -22:53:08.076 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ config --- -22:53:08.715 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connect --- -22:53:08.872 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costandusagereport --- -22:53:09.526 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costexplorer --- -22:53:10.808 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ databasemigration --- -22:53:11.217 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datapipeline --- -22:53:11.734 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datasync --- -22:53:12.200 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dax --- -22:53:13.794 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ devicefarm --- -22:53:14.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directconnect --- -22:53:34.381 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2 --- -22:53:35.515 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directory --- -22:53:35.738 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dlm --- -22:53:36.777 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ docdb --- -22:53:38.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb --- -22:53:39.095 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecr --- -22:53:40.733 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecs --- -22:53:41.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ efs --- -22:53:41.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eks --- -22:53:43.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticache --- -22:53:44.059 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticbeanstalk --- -22:53:44.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancing --- -22:53:45.622 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancingv2 --- -22:53:46.206 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticsearch --- -22:53:46.824 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elastictranscoder --- -22:53:47.655 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ emr --- -22:53:48.121 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ firehose --- -22:53:48.378 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fms --- -22:53:48.750 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fsx --- -22:53:50.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ gamelift --- -22:53:51.159 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glacier --- -22:53:51.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ globalaccelerator --- -22:53:54.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glue --- -22:53:55.990 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ greengrass --- -22:53:56.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ guardduty --- -22:53:57.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ health --- -22:53:58.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ inspector --- -22:54:02.550 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot --- -22:54:02.762 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickdevices --- -22:54:03.033 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickprojects --- -22:54:03.777 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotanalytics --- -22:54:03.924 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotdataplane --- -22:54:04.054 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotjobsdataplane --- -22:54:04.525 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kafka --- -22:54:05.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesis --- -22:54:05.676 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalytics --- -22:54:06.424 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalyticsv2 --- -22:54:06.775 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideo --- -22:54:06.955 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideoarchivedmedia --- -22:54:07.045 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideomedia --- -22:54:08.224 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lambda --- -22:54:09.087 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexmodelbuilding --- -22:54:09.296 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexruntime --- -22:54:09.667 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ licensemanager --- -22:54:11.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lightsail --- -22:54:12.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ machinelearning --- -22:54:12.772 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ macie --- -22:54:13.202 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ managedblockchain --- -22:54:13.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecommerceanalytics --- -22:54:13.421 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplaceentitlement --- -22:54:13.601 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacemetering --- -22:54:13.973 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconnect --- -22:54:15.384 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconvert --- -22:54:17.290 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ medialive --- -22:54:17.734 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackage --- -22:54:18.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackagevod --- -22:54:18.291 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastore --- -22:54:19.708 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ url-connection-client --- -22:54:19.852 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastoredata --- -22:54:20.018 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediatailor --- -22:54:20.364 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhub --- -22:54:20.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mobile --- -22:54:21.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mq --- -22:54:21.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mturk --- -22:54:23.247 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ neptune --- -22:54:24.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworks --- -22:54:24.930 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworkscm --- -22:54:26.726 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ organizations --- -22:54:26.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pi --- -22:54:29.268 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpoint --- -22:54:30.049 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointemail --- -22:54:30.223 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointsmsvoice --- -22:54:30.538 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ polly --- -22:54:30.692 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pricing --- -22:54:32.250 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ quicksight --- -22:54:32.760 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ram --- -22:54:36.911 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rds --- -22:54:37.188 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rdsdata --- -22:54:39.786 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ redshift --- -22:54:40.933 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rekognition --- -22:54:41.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroups --- -22:54:41.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroupstaggingapi --- -22:54:42.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ robomaker --- -22:54:43.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53 --- -22:54:43.978 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53domains --- -22:54:44.417 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53resolver --- -22:54:48.487 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemaker --- -22:54:48.562 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakerruntime --- -22:54:48.925 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ secretsmanager --- -22:54:49.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ securityhub --- -22:54:50.253 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ serverlessapplicationrepository --- -22:54:52.072 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicecatalog --- -22:54:52.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicediscovery --- -22:54:53.830 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ses --- -22:54:54.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sfn --- -22:54:54.675 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ shield --- -22:54:54.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ signer --- -22:54:55.518 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sms --- -22:54:55.920 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ snowball --- -22:54:59.849 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssm --- -22:55:01.266 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ storagegateway --- -22:55:01.605 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ support --- -22:55:02.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ swf --- -22:55:02.862 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ textract --- -22:55:03.152 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribe --- -22:55:03.304 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribestreaming --- -22:55:03.658 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transfer --- -22:55:03.823 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ translate --- -22:55:06.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ waf --- -22:55:07.011 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workdocs --- -22:55:07.443 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ worklink --- -22:55:08.002 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmail --- -22:55:08.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workspaces --- -22:55:09.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ xray --- -22:55:09.833 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ groundstation --- -22:55:10.467 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotthingsgraph --- -22:55:10.798 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotevents --- -22:55:10.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ioteventsdata --- -22:55:11.036 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeruntime --- -22:55:11.844 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalize --- -22:55:11.914 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeevents --- -22:55:12.258 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicequotas --- -22:55:12.660 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationinsights --- -22:55:12.734 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2instanceconnect --- -22:55:13.225 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eventbridge --- -22:55:13.508 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lakeformation --- -22:55:14.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecast --- -22:55:14.169 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecastquery --- -22:55:14.455 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldb --- -22:55:14.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldbsession --- -22:55:14.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmailmessageflow --- -22:55:14.917 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarnotifications --- -22:55:15.171 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ savingsplans --- -22:55:15.304 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sso --- -22:55:15.436 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssooidc --- -22:55:15.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecatalog --- -22:55:16.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sesv2 --- -22:55:16.991 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dataexchange --- -22:55:17.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhubconfig --- -22:55:17.231 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connectparticipant --- -22:55:18.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ wafv2 --- -22:55:18.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appconfig --- -22:55:18.666 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotsecuretunneling --- -22:55:18.753 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticinference --- -22:55:19.640 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ imagebuilder --- -22:55:20.079 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ schemas --- -22:55:20.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ accessanalyzer --- -22:55:20.645 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ computeoptimizer --- -22:55:21.177 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ networkmanager --- -22:55:21.706 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kendra --- -22:55:22.270 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ frauddetector --- -22:55:22.402 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegurureviewer --- -22:55:22.589 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codeguruprofiler --- -22:55:22.731 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ outposts --- -22:55:22.867 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakera2iruntime --- -22:55:22.990 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ebs --- -22:55:23.086 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideosignaling --- -22:55:23.295 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ detective --- -22:55:23.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarconnections --- -22:55:23.447 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-sdk-java --- -22:55:26.647 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb-enhanced --- -22:55:26.689 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bom-internal --- -22:55:26.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bundle --- -22:55:28.261 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ release-scripts --- -22:55:28.422 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbdocument-v1 --- -22:55:28.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbmapper-v1 --- -22:55:31.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests-core --- -22:55:40.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests --- -22:55:43.484 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-generated-classes-test --- -22:55:45.616 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ sdk-benchmarks --- -22:55:45.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ module-path-tests --- -22:55:45.777 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ tests-coverage-reporting --- -22:55:45.893 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ stability-tests --- -22:55:47.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ build-tools --- -22:55:50.274 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ annotations --- -22:55:54.298 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ utils --- -22:55:56.407 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-spi --- -22:55:59.285 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ test-utils --- -22:56:01.107 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ profiles --- -22:56:02.528 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-tests --- -22:56:04.815 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apache-client --- -22:56:12.518 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sdk-core --- -22:56:14.770 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite --- -22:56:16.615 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite-maven-plugin --- -22:56:20.753 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ regions --- -22:56:23.618 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ auth --- -22:56:25.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-core --- -22:56:27.538 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-core --- -22:56:29.940 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-json-protocol --- -22:56:31.289 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ service-test-utils --- -22:56:32.940 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-cbor-protocol --- -22:56:35.107 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-ion-protocol --- -22:56:37.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-query-protocol --- -22:56:39.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-xml-protocol --- -22:56:45.513 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen --- -22:56:47.581 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-maven-plugin --- -22:56:49.002 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acm --- -22:56:50.079 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acmpca --- -22:56:52.441 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ alexaforbusiness --- -22:56:53.159 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ amplify --- -22:56:56.517 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigateway --- -22:56:56.617 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewaymanagementapi --- -22:56:57.785 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewayv2 --- -22:56:58.184 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationautoscaling --- -22:56:58.729 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationdiscovery --- -22:56:59.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appmesh --- -22:57:00.365 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appstream --- -22:57:01.019 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appsync --- -22:57:01.446 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ athena --- -22:57:05.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iam --- -22:57:05.460 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sts --- -22:57:05.982 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sqs --- -22:57:06.614 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sns --- -22:57:07.788 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscaling --- -22:57:08.033 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscalingplans --- -22:57:08.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ backup --- -22:57:09.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ batch --- -22:57:09.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ budgets --- -22:57:11.514 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ chime --- -22:57:11.728 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloud9 --- -22:57:13.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ clouddirectory --- -22:57:14.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ arns --- -22:57:15.291 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3control --- -22:57:16.312 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kms --- -22:57:18.673 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3 --- -22:57:19.992 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudformation --- -22:57:21.192 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudfront --- -22:57:21.475 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsm --- -22:57:21.747 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsmv2 --- -22:57:22.221 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearch --- -22:57:22.393 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearchdomain --- -22:57:22.944 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudtrail --- -22:57:23.621 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatch --- -22:57:24.139 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchevents --- -22:57:24.858 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchlogs --- -22:57:25.550 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codebuild --- -22:57:28.076 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codecommit --- -22:57:29.312 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codedeploy --- -22:57:30.197 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codepipeline --- -22:57:30.522 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestar --- -22:57:30.885 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentity --- -22:57:33.114 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentityprovider --- -22:57:33.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitosync --- -22:57:34.472 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehend --- -22:57:34.796 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehendmedical --- -22:57:36.544 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ config --- -22:57:37.161 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connect --- -22:57:37.305 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costandusagereport --- -22:57:37.979 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costexplorer --- -22:57:39.215 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ databasemigration --- -22:57:39.607 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datapipeline --- -22:57:40.133 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datasync --- -22:57:40.571 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dax --- -22:57:42.135 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ devicefarm --- -22:57:43.129 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directconnect --- -22:58:00.220 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2 --- -22:58:01.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directory --- -22:58:01.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dlm --- -22:58:02.460 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ docdb --- -22:58:04.015 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb --- -22:58:04.654 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecr --- -22:58:06.176 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecs --- -22:58:06.524 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ efs --- -22:58:06.992 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eks --- -22:58:08.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticache --- -22:58:09.357 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticbeanstalk --- -22:58:09.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancing --- -22:58:10.880 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancingv2 --- -22:58:11.447 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticsearch --- -22:58:12.000 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elastictranscoder --- -22:58:12.813 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ emr --- -22:58:13.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ firehose --- -22:58:13.558 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fms --- -22:58:13.926 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fsx --- -22:58:15.419 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ gamelift --- -22:58:16.116 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glacier --- -22:58:16.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ globalaccelerator --- -22:58:19.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glue --- -22:58:20.505 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ greengrass --- -22:58:21.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ guardduty --- -22:58:21.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ health --- -22:58:22.482 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ inspector --- -22:58:26.502 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot --- -22:58:26.696 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickdevices --- -22:58:26.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickprojects --- -22:58:27.673 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotanalytics --- -22:58:27.820 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotdataplane --- -22:58:27.949 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotjobsdataplane --- -22:58:28.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kafka --- -22:58:28.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesis --- -22:58:29.492 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalytics --- -22:58:30.218 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalyticsv2 --- -22:58:30.540 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideo --- -22:58:30.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideoarchivedmedia --- -22:58:30.810 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideomedia --- -22:58:31.923 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lambda --- -22:58:32.743 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexmodelbuilding --- -22:58:32.941 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexruntime --- -22:58:33.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ licensemanager --- -22:58:35.409 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lightsail --- -22:58:35.987 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ machinelearning --- -22:58:36.163 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ macie --- -22:58:36.566 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ managedblockchain --- -22:58:36.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecommerceanalytics --- -22:58:36.782 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplaceentitlement --- -22:58:36.924 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacemetering --- -22:58:37.283 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconnect --- -22:58:38.624 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconvert --- -22:58:40.426 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ medialive --- -22:58:40.838 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackage --- -22:58:41.127 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackagevod --- -22:58:41.380 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastore --- -22:58:42.721 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ url-connection-client --- -22:58:42.858 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastoredata --- -22:58:43.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediatailor --- -22:58:43.316 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhub --- -22:58:43.559 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mobile --- -22:58:43.982 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mq --- -22:58:44.712 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mturk --- -22:58:46.109 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ neptune --- -22:58:47.389 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworks --- -22:58:47.709 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworkscm --- -22:58:49.330 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ organizations --- -22:58:49.453 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pi --- -22:58:51.678 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpoint --- -22:58:52.416 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointemail --- -22:58:52.570 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointsmsvoice --- -22:58:52.891 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ polly --- -22:58:53.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pricing --- -22:58:54.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ quicksight --- -22:58:55.033 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ram --- -22:58:58.747 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rds --- -22:58:59.002 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rdsdata --- -22:59:01.405 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ redshift --- -22:59:02.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rekognition --- -22:59:02.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroups --- -22:59:03.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroupstaggingapi --- -22:59:03.824 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ robomaker --- -22:59:04.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53 --- -22:59:05.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53domains --- -22:59:05.781 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53resolver --- -22:59:09.634 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemaker --- -22:59:09.713 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakerruntime --- -22:59:10.082 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ secretsmanager --- -22:59:11.031 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ securityhub --- -22:59:11.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ serverlessapplicationrepository --- -22:59:13.039 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicecatalog --- -22:59:13.481 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicediscovery --- -22:59:14.653 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ses --- -22:59:15.151 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sfn --- -22:59:15.448 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ shield --- -22:59:15.746 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ signer --- -22:59:16.282 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sms --- -22:59:16.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ snowball --- -22:59:20.377 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssm --- -22:59:21.667 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ storagegateway --- -22:59:21.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ support --- -22:59:23.011 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ swf --- -22:59:23.250 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ textract --- -22:59:23.533 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribe --- -22:59:23.674 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribestreaming --- -22:59:24.013 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transfer --- -22:59:24.177 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ translate --- -22:59:26.361 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ waf --- -22:59:27.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workdocs --- -22:59:27.505 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ worklink --- -22:59:28.048 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmail --- -22:59:28.743 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workspaces --- -22:59:29.361 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ xray --- -22:59:29.809 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ groundstation --- -22:59:30.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotthingsgraph --- -22:59:30.719 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotevents --- -22:59:30.872 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ioteventsdata --- -22:59:30.953 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeruntime --- -22:59:31.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalize --- -22:59:31.746 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeevents --- -22:59:32.093 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicequotas --- -22:59:32.490 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationinsights --- -22:59:32.557 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2instanceconnect --- -22:59:33.016 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eventbridge --- -22:59:33.295 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lakeformation --- -22:59:33.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecast --- -22:59:33.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecastquery --- -22:59:34.166 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldb --- -22:59:34.286 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldbsession --- -22:59:34.348 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmailmessageflow --- -22:59:34.615 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarnotifications --- -22:59:34.883 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ savingsplans --- -22:59:35.006 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sso --- -22:59:35.133 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssooidc --- -22:59:35.322 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecatalog --- -22:59:36.148 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sesv2 --- -22:59:36.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dataexchange --- -22:59:36.684 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhubconfig --- -22:59:36.814 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connectparticipant --- -22:59:37.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ wafv2 --- -22:59:38.034 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appconfig --- -22:59:38.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotsecuretunneling --- -22:59:38.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticinference --- -22:59:39.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ imagebuilder --- -22:59:39.532 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ schemas --- -22:59:39.861 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ accessanalyzer --- -22:59:40.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ computeoptimizer --- -22:59:40.585 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ networkmanager --- -22:59:41.094 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kendra --- -22:59:41.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ frauddetector --- -22:59:41.769 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegurureviewer --- -22:59:41.947 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codeguruprofiler --- -22:59:42.085 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ outposts --- -22:59:42.223 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakera2iruntime --- -22:59:42.342 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ebs --- -22:59:42.435 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideosignaling --- -22:59:42.653 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ detective --- -22:59:42.760 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarconnections --- -22:59:42.808 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-sdk-java --- -22:59:45.917 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb-enhanced --- -22:59:45.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bom-internal --- -22:59:45.991 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bundle --- -22:59:47.375 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ release-scripts --- -22:59:47.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbdocument-v1 --- -22:59:48.086 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbmapper-v1 --- -22:59:50.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests-core --- -22:59:58.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests --- -23:00:02.703 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-generated-classes-test --- -23:00:04.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ sdk-benchmarks --- -23:00:04.938 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ module-path-tests --- -23:00:04.995 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ tests-coverage-reporting --- -23:00:05.106 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ stability-tests --- -23:00:06.759 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ build-tools --- -23:00:09.608 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ annotations --- -23:00:13.220 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ utils --- -23:00:15.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-spi --- -23:00:18.233 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ test-utils --- -23:00:20.152 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ profiles --- -23:00:21.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-tests --- -23:00:23.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apache-client --- -23:00:27.262 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ netty-nio-client --- -23:00:31.941 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sdk-core --- -23:00:34.288 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite --- -23:00:36.136 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite-maven-plugin --- -23:00:40.111 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ regions --- -23:00:42.813 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ auth --- -23:00:45.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-core --- -23:00:46.649 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-core --- -23:00:49.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-json-protocol --- -23:00:50.357 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ service-test-utils --- -23:00:52.037 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-cbor-protocol --- -23:00:54.127 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-ion-protocol --- -23:00:56.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-query-protocol --- -23:00:58.374 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-xml-protocol --- -23:01:04.509 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen --- -23:01:06.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-maven-plugin --- -23:01:07.742 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acm --- -23:01:08.415 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acmpca --- -23:01:10.970 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ alexaforbusiness --- -23:01:11.772 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ amplify --- -23:01:15.443 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigateway --- -23:01:15.565 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewaymanagementapi --- -23:01:16.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewayv2 --- -23:01:17.267 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationautoscaling --- -23:01:17.789 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationdiscovery --- -23:01:18.566 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appmesh --- -23:01:19.484 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appstream --- -23:01:20.190 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appsync --- -23:01:20.610 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ athena --- -23:01:24.398 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iam --- -23:01:24.784 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sts --- -23:01:25.351 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sqs --- -23:01:25.988 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sns --- -23:01:27.206 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscaling --- -23:01:27.464 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscalingplans --- -23:01:28.405 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ backup --- -23:01:28.928 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ batch --- -23:01:29.242 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ budgets --- -23:01:30.877 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ chime --- -23:01:31.117 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloud9 --- -23:01:32.982 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ clouddirectory --- -23:01:34.159 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ arns --- -23:01:34.614 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3control --- -23:01:35.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kms --- -23:01:38.042 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3 --- -23:01:39.409 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudformation --- -23:01:40.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudfront --- -23:01:40.934 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsm --- -23:01:41.201 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsmv2 --- -23:01:41.678 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearch --- -23:01:41.863 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearchdomain --- -23:01:42.437 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudtrail --- -23:01:43.133 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatch --- -23:01:43.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchevents --- -23:01:44.388 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchlogs --- -23:01:45.105 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codebuild --- -23:01:47.696 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codecommit --- -23:01:48.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codedeploy --- -23:01:49.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codepipeline --- -23:01:50.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestar --- -23:01:50.635 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentity --- -23:01:52.727 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentityprovider --- -23:01:53.034 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitosync --- -23:01:54.110 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehend --- -23:01:54.428 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehendmedical --- -23:01:56.248 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ config --- -23:01:56.924 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connect --- -23:01:57.078 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costandusagereport --- -23:01:57.738 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costexplorer --- -23:01:59.061 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ databasemigration --- -23:01:59.490 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datapipeline --- -23:02:00.002 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datasync --- -23:02:00.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dax --- -23:02:02.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ devicefarm --- -23:02:03.055 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directconnect --- -23:02:20.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2 --- -23:02:21.623 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directory --- -23:02:21.883 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dlm --- -23:02:22.880 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ docdb --- -23:02:24.479 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb --- -23:02:25.120 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecr --- -23:02:26.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecs --- -23:02:27.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ efs --- -23:02:27.516 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eks --- -23:02:28.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticache --- -23:02:29.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticbeanstalk --- -23:02:30.568 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancing --- -23:02:31.420 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancingv2 --- -23:02:32.014 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticsearch --- -23:02:32.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elastictranscoder --- -23:02:33.468 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ emr --- -23:02:33.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ firehose --- -23:02:34.196 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fms --- -23:02:34.617 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fsx --- -23:02:36.165 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ gamelift --- -23:02:36.823 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glacier --- -23:02:37.169 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ globalaccelerator --- -23:02:39.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glue --- -23:02:41.345 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ greengrass --- -23:02:42.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ guardduty --- -23:02:42.445 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ health --- -23:02:43.359 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ inspector --- -23:02:47.462 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot --- -23:02:47.661 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickdevices --- -23:02:47.925 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickprojects --- -23:02:48.662 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotanalytics --- -23:02:48.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotdataplane --- -23:02:48.934 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotjobsdataplane --- -23:02:49.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kafka --- -23:02:50.001 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesis --- -23:02:50.515 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalytics --- -23:02:51.260 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalyticsv2 --- -23:02:51.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideo --- -23:02:51.815 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideoarchivedmedia --- -23:02:51.904 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideomedia --- -23:02:53.020 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lambda --- -23:02:53.873 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexmodelbuilding --- -23:02:54.069 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexruntime --- -23:02:54.477 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ licensemanager --- -23:02:56.617 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lightsail --- -23:02:57.273 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ machinelearning --- -23:02:57.441 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ macie --- -23:02:57.862 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ managedblockchain --- -23:02:57.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecommerceanalytics --- -23:02:58.082 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplaceentitlement --- -23:02:58.227 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacemetering --- -23:02:58.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconnect --- -23:02:59.928 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconvert --- -23:03:01.807 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ medialive --- -23:03:02.252 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackage --- -23:03:02.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackagevod --- -23:03:02.791 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastore --- -23:03:04.169 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ url-connection-client --- -23:03:05.886 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastoredata --- -23:03:06.048 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediatailor --- -23:03:06.351 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhub --- -23:03:06.568 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mobile --- -23:03:07.025 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mq --- -23:03:07.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mturk --- -23:03:09.165 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ neptune --- -23:03:10.442 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworks --- -23:03:10.778 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworkscm --- -23:03:12.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ organizations --- -23:03:12.588 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pi --- -23:03:14.897 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpoint --- -23:03:15.630 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointemail --- -23:03:15.790 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointsmsvoice --- -23:03:16.097 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ polly --- -23:03:16.271 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pricing --- -23:03:17.789 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ quicksight --- -23:03:18.290 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ram --- -23:03:22.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rds --- -23:03:22.297 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rdsdata --- -23:03:24.780 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ redshift --- -23:03:25.856 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rekognition --- -23:03:26.115 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroups --- -23:03:26.371 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroupstaggingapi --- -23:03:27.217 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ robomaker --- -23:03:28.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53 --- -23:03:28.797 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53domains --- -23:03:29.238 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53resolver --- -23:03:33.121 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemaker --- -23:03:33.197 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakerruntime --- -23:03:33.560 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ secretsmanager --- -23:03:34.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ securityhub --- -23:03:34.927 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ serverlessapplicationrepository --- -23:03:36.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicecatalog --- -23:03:37.062 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicediscovery --- -23:03:38.261 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ses --- -23:03:38.787 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sfn --- -23:03:39.100 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ shield --- -23:03:39.399 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ signer --- -23:03:39.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sms --- -23:03:40.343 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ snowball --- -23:03:44.068 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssm --- -23:03:45.408 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ storagegateway --- -23:03:45.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ support --- -23:03:46.781 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ swf --- -23:03:47.002 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ textract --- -23:03:47.292 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribe --- -23:03:47.436 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribestreaming --- -23:03:47.789 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transfer --- -23:03:47.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ translate --- -23:03:50.194 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ waf --- -23:03:50.933 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workdocs --- -23:03:51.349 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ worklink --- -23:03:51.924 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmail --- -23:03:52.623 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workspaces --- -23:03:53.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ xray --- -23:03:53.672 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ groundstation --- -23:03:54.266 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotthingsgraph --- -23:03:54.594 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotevents --- -23:03:54.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ioteventsdata --- -23:03:54.849 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeruntime --- -23:03:55.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalize --- -23:03:55.660 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeevents --- -23:03:55.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicequotas --- -23:03:56.395 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationinsights --- -23:03:56.467 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2instanceconnect --- -23:03:56.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eventbridge --- -23:03:57.208 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lakeformation --- -23:03:57.786 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecast --- -23:03:57.865 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecastquery --- -23:03:58.116 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldb --- -23:03:58.228 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldbsession --- -23:03:58.286 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmailmessageflow --- -23:03:58.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarnotifications --- -23:03:58.807 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ savingsplans --- -23:03:58.926 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sso --- -23:03:59.054 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssooidc --- -23:03:59.248 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecatalog --- -23:04:00.095 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sesv2 --- -23:04:00.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dataexchange --- -23:04:00.667 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhubconfig --- -23:04:00.799 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connectparticipant --- -23:04:01.524 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ wafv2 --- -23:04:02.013 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appconfig --- -23:04:02.164 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotsecuretunneling --- -23:04:02.243 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticinference --- -23:04:03.092 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ imagebuilder --- -23:04:03.545 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ schemas --- -23:04:03.887 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ accessanalyzer --- -23:04:04.110 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ computeoptimizer --- -23:04:04.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ networkmanager --- -23:04:05.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kendra --- -23:04:05.688 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ frauddetector --- -23:04:05.821 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegurureviewer --- -23:04:05.995 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codeguruprofiler --- -23:04:06.127 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ outposts --- -23:04:06.282 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakera2iruntime --- -23:04:06.397 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ebs --- -23:04:06.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideosignaling --- -23:04:06.686 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ detective --- -23:04:06.790 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarconnections --- -23:04:06.835 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-sdk-java --- -23:04:09.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb-enhanced --- -23:04:10.000 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bom-internal --- -23:04:10.035 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bundle --- -23:04:11.470 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ release-scripts --- -23:04:11.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbdocument-v1 --- -23:04:12.212 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbmapper-v1 --- -23:04:14.817 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests-core --- -23:04:23.131 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests --- -23:04:24.340 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-generated-classes-test --- -23:04:26.444 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ sdk-benchmarks --- -23:04:26.545 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ module-path-tests --- -23:04:26.600 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ tests-coverage-reporting --- -23:04:26.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ stability-tests --- -23:04:28.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ build-tools --- -23:04:31.267 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ annotations --- -23:04:34.923 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ utils --- -23:04:36.921 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-spi --- -23:04:39.658 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ test-utils --- -23:04:41.568 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ profiles --- -23:04:42.953 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ http-client-tests --- -23:04:45.226 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apache-client --- -23:04:48.428 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ netty-nio-client --- -23:04:53.036 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sdk-core --- -23:04:55.247 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite --- -23:04:57.042 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-lite-maven-plugin --- -23:05:01.028 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ regions --- -23:05:04.028 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ auth --- -23:05:06.371 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-core --- -23:05:07.947 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-core --- -23:05:10.300 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-json-protocol --- -23:05:11.628 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ service-test-utils --- -23:05:13.445 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-cbor-protocol --- -23:05:15.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-ion-protocol --- -23:05:17.666 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-query-protocol --- -23:05:19.868 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-xml-protocol --- -23:05:26.188 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen --- -23:05:28.230 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-maven-plugin --- -23:05:29.425 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acm --- -23:05:30.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ acmpca --- -23:05:32.736 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ alexaforbusiness --- -23:05:33.517 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ amplify --- -23:05:37.075 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigateway --- -23:05:37.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewaymanagementapi --- -23:05:38.740 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ apigatewayv2 --- -23:05:39.170 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationautoscaling --- -23:05:39.735 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationdiscovery --- -23:05:40.603 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appmesh --- -23:05:41.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appstream --- -23:05:42.247 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appsync --- -23:05:42.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ athena --- -23:05:46.527 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iam --- -23:05:46.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sts --- -23:05:47.404 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sqs --- -23:05:48.061 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sns --- -23:05:49.240 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscaling --- -23:05:49.504 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ autoscalingplans --- -23:05:50.468 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ backup --- -23:05:51.026 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ batch --- -23:05:51.345 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ budgets --- -23:05:53.057 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ chime --- -23:05:53.285 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloud9 --- -23:05:55.180 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ clouddirectory --- -23:05:56.413 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ arns --- -23:05:56.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3control --- -23:05:57.918 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kms --- -23:06:00.387 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ s3 --- -23:06:01.740 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudformation --- -23:06:02.987 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudfront --- -23:06:03.280 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsm --- -23:06:03.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudhsmv2 --- -23:06:04.068 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearch --- -23:06:04.245 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudsearchdomain --- -23:06:04.799 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudtrail --- -23:06:05.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatch --- -23:06:06.036 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchevents --- -23:06:06.770 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cloudwatchlogs --- -23:06:07.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codebuild --- -23:06:10.122 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codecommit --- -23:06:11.467 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codedeploy --- -23:06:12.385 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codepipeline --- -23:06:12.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestar --- -23:06:13.076 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentity --- -23:06:15.257 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitoidentityprovider --- -23:06:15.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ cognitosync --- -23:06:16.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehend --- -23:06:17.025 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ comprehendmedical --- -23:06:18.892 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ config --- -23:06:19.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connect --- -23:06:19.692 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costandusagereport --- -23:06:20.356 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ costexplorer --- -23:06:21.687 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ databasemigration --- -23:06:22.104 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datapipeline --- -23:06:22.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ datasync --- -23:06:23.104 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dax --- -23:06:24.719 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ devicefarm --- -23:06:25.743 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directconnect --- -23:06:45.460 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2 --- -23:06:46.577 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ directory --- -23:06:46.798 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dlm --- -23:06:47.851 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ docdb --- -23:06:49.490 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb --- -23:06:50.178 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecr --- -23:06:51.758 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ecs --- -23:06:52.146 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ efs --- -23:06:52.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eks --- -23:06:54.119 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticache --- -23:06:55.159 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticbeanstalk --- -23:06:55.804 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancing --- -23:06:56.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticloadbalancingv2 --- -23:06:57.303 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticsearch --- -23:06:57.882 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elastictranscoder --- -23:06:58.756 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ emr --- -23:06:59.233 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ firehose --- -23:06:59.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fms --- -23:06:59.883 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ fsx --- -23:07:01.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ gamelift --- -23:07:02.254 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glacier --- -23:07:02.572 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ globalaccelerator --- -23:07:05.521 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ glue --- -23:07:06.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ greengrass --- -23:07:07.847 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ guardduty --- -23:07:08.127 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ health --- -23:07:09.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ inspector --- -23:07:13.495 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot --- -23:07:13.722 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickdevices --- -23:07:13.992 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iot1clickprojects --- -23:07:14.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotanalytics --- -23:07:14.895 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotdataplane --- -23:07:15.027 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotjobsdataplane --- -23:07:15.521 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kafka --- -23:07:16.103 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesis --- -23:07:16.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalytics --- -23:07:17.429 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisanalyticsv2 --- -23:07:17.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideo --- -23:07:17.953 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideoarchivedmedia --- -23:07:18.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideomedia --- -23:07:19.259 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lambda --- -23:07:20.126 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexmodelbuilding --- -23:07:20.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lexruntime --- -23:07:20.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ licensemanager --- -23:07:23.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lightsail --- -23:07:23.637 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ machinelearning --- -23:07:23.809 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ macie --- -23:07:24.231 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ managedblockchain --- -23:07:24.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecommerceanalytics --- -23:07:24.447 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplaceentitlement --- -23:07:24.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacemetering --- -23:07:24.993 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconnect --- -23:07:26.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediaconvert --- -23:07:28.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ medialive --- -23:07:28.715 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackage --- -23:07:28.999 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediapackagevod --- -23:07:29.253 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastore --- -23:07:30.577 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ url-connection-client --- -23:07:32.332 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediastoredata --- -23:07:32.497 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mediatailor --- -23:07:32.843 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhub --- -23:07:33.083 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mobile --- -23:07:33.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mq --- -23:07:34.302 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ mturk --- -23:07:35.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ neptune --- -23:07:37.150 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworks --- -23:07:37.482 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ opsworkscm --- -23:07:39.291 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ organizations --- -23:07:39.420 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pi --- -23:07:41.801 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpoint --- -23:07:42.588 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointemail --- -23:07:42.752 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pinpointsmsvoice --- -23:07:43.064 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ polly --- -23:07:43.222 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ pricing --- -23:07:44.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ quicksight --- -23:07:45.328 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ram --- -23:07:49.416 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rds --- -23:07:49.690 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rdsdata --- -23:07:52.300 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ redshift --- -23:07:53.428 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ rekognition --- -23:07:53.689 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroups --- -23:07:53.954 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ resourcegroupstaggingapi --- -23:07:54.834 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ robomaker --- -23:07:56.038 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53 --- -23:07:56.473 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53domains --- -23:07:56.906 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ route53resolver --- -23:08:01.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemaker --- -23:08:01.110 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakerruntime --- -23:08:01.481 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ secretsmanager --- -23:08:02.480 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ securityhub --- -23:08:02.849 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ serverlessapplicationrepository --- -23:08:04.675 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicecatalog --- -23:08:05.144 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicediscovery --- -23:08:06.407 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ses --- -23:08:06.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sfn --- -23:08:07.280 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ shield --- -23:08:07.589 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ signer --- -23:08:08.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sms --- -23:08:08.581 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ snowball --- -23:08:12.505 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssm --- -23:08:13.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ storagegateway --- -23:08:14.279 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ support --- -23:08:15.403 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ swf --- -23:08:15.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ textract --- -23:08:15.937 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribe --- -23:08:16.094 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transcribestreaming --- -23:08:16.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ transfer --- -23:08:16.607 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ translate --- -23:08:19.072 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ waf --- -23:08:19.850 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workdocs --- -23:08:20.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ worklink --- -23:08:20.864 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmail --- -23:08:21.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workspaces --- -23:08:22.193 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ xray --- -23:08:22.661 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ groundstation --- -23:08:23.266 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotthingsgraph --- -23:08:23.621 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotevents --- -23:08:23.781 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ioteventsdata --- -23:08:23.868 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeruntime --- -23:08:24.637 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalize --- -23:08:24.715 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ personalizeevents --- -23:08:25.075 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ servicequotas --- -23:08:25.483 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ applicationinsights --- -23:08:25.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ec2instanceconnect --- -23:08:26.057 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ eventbridge --- -23:08:26.356 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ lakeformation --- -23:08:26.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecast --- -23:08:27.018 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ forecastquery --- -23:08:27.308 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldb --- -23:08:27.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ qldbsession --- -23:08:27.488 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ workmailmessageflow --- -23:08:27.755 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarnotifications --- -23:08:28.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ savingsplans --- -23:08:28.134 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sso --- -23:08:28.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ssooidc --- -23:08:28.456 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ marketplacecatalog --- -23:08:29.385 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sesv2 --- -23:08:29.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dataexchange --- -23:08:29.953 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ migrationhubconfig --- -23:08:30.095 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ connectparticipant --- -23:08:30.832 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ wafv2 --- -23:08:31.319 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ appconfig --- -23:08:31.465 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ iotsecuretunneling --- -23:08:31.547 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ elasticinference --- -23:08:32.456 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ imagebuilder --- -23:08:32.898 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ schemas --- -23:08:33.232 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ accessanalyzer --- -23:08:33.462 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ computeoptimizer --- -23:08:33.976 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ networkmanager --- -23:08:34.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kendra --- -23:08:35.048 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ frauddetector --- -23:08:35.213 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegurureviewer --- -23:08:35.407 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codeguruprofiler --- -23:08:35.557 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ outposts --- -23:08:35.697 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ sagemakera2iruntime --- -23:08:35.819 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ebs --- -23:08:35.915 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ kinesisvideosignaling --- -23:08:36.120 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ detective --- -23:08:36.220 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codestarconnections --- -23:08:36.264 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ aws-sdk-java --- -23:08:39.425 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodb-enhanced --- -23:08:39.466 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bom-internal --- -23:08:39.502 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ bundle --- -23:08:41.010 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ release-scripts --- -23:08:41.182 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbdocument-v1 --- -23:08:41.790 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ dynamodbmapper-v1 --- -23:08:44.446 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests-core --- -23:08:52.782 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ protocol-tests --- -23:08:54.026 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ codegen-generated-classes-test --- -23:08:56.227 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ sdk-benchmarks --- -23:08:56.329 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ module-path-tests --- -23:08:56.386 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ tests-coverage-reporting --- -23:08:56.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ stability-tests --- -23:08:57.719 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jvm-profiler --- -23:08:59.171 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jvm-profiler --- -23:09:01.293 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-lang --- -23:09:01.888 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-io --- -23:09:02.376 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-image --- -23:09:03.043 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ servlet --- -23:09:03.542 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-core --- -23:09:03.569 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-metadata --- -23:09:03.587 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-clippath --- -23:09:03.613 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-bmp --- -23:09:03.634 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-hdr --- -23:09:03.654 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-icns --- -23:09:03.674 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-iff --- -23:09:03.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-jpeg --- -23:09:03.723 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pcx --- -23:09:03.728 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pdf --- -23:09:03.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pict --- -23:09:03.768 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pnm --- -23:09:03.798 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-psd --- -23:09:03.812 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-sgi --- -23:09:03.827 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-tga --- -23:09:03.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-thumbsdb --- -23:09:03.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-tiff --- -23:09:03.896 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-batik --- -23:09:04.331 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-reference --- -23:09:04.344 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ contrib --- -23:09:06.160 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-lang --- -23:09:06.762 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-io --- -23:09:07.359 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ common-image --- -23:09:08.039 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ servlet --- -23:09:08.552 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-core --- -23:09:08.574 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-metadata --- -23:09:08.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-clippath --- -23:09:08.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-bmp --- -23:09:08.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-hdr --- -23:09:08.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-icns --- -23:09:08.677 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-iff --- -23:09:08.704 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-jpeg --- -23:09:08.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pcx --- -23:09:08.729 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pdf --- -23:09:08.751 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pict --- -23:09:08.773 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-pnm --- -23:09:08.804 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-psd --- -23:09:08.824 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-sgi --- -23:09:08.839 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-tga --- -23:09:08.858 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-thumbsdb --- -23:09:08.888 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-tiff --- -23:09:08.927 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-batik --- -23:09:09.370 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ imageio-reference --- -23:09:09.386 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ contrib --- -23:09:10.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-build-config --- -23:09:11.164 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:11.382 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-entry --- -23:09:11.502 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-html-report --- -23:09:11.588 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-aggregator --- -23:09:13.488 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven --- -23:09:13.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-command-line --- -23:09:14.038 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-ant --- -23:09:14.140 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven-verification --- -23:09:14.200 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-java8-verification --- -23:09:15.511 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-build-config --- -23:09:16.244 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:16.455 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-entry --- -23:09:16.574 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-html-report --- -23:09:16.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-aggregator --- -23:09:18.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven --- -23:09:18.933 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-command-line --- -23:09:19.009 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-ant --- -23:09:19.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven-verification --- -23:09:19.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-java8-verification --- -23:09:20.444 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-build-config --- -23:09:21.121 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:21.539 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-entry --- -23:09:21.646 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-html-report --- -23:09:21.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-aggregator --- -23:09:23.573 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven --- -23:09:23.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-command-line --- -23:09:23.709 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-ant --- -23:09:23.810 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven-verification --- -23:09:23.869 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-java8-verification --- -23:09:25.126 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-build-config --- -23:09:25.876 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:26.357 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-entry --- -23:09:26.465 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-html-report --- -23:09:26.558 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-aggregator --- -23:09:28.289 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven --- -23:09:28.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-command-line --- -23:09:28.440 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-ant --- -23:09:28.548 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-maven-verification --- -23:09:28.605 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest-java8-verification --- -23:09:33.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:39.309 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.17:test (default-test) @ pitest --- -23:09:40.713 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-entry --- -23:09:40.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-api --- -23:09:40.888 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-util --- -23:09:40.925 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-dao --- -23:09:41.101 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-service --- -23:09:42.206 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-web --- -23:09:42.222 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-generator --- -23:09:43.283 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-entry --- -23:09:43.425 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-api --- -23:09:43.446 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-util --- -23:09:43.484 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-dao --- -23:09:43.657 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-service --- -23:09:44.601 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-web --- -23:09:44.618 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ goodsKill-generator --- -23:09:45.792 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-core --- -23:09:45.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-analysis --- -23:09:45.910 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-io --- -23:09:46.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-instances --- -23:09:46.975 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-examples --- -23:09:48.153 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-core --- -23:09:48.228 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-analysis --- -23:09:48.261 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-io --- -23:09:49.296 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-instances --- -23:09:49.321 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ jsprit-examples --- -23:09:52.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-common --- -23:09:53.123 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-api --- -23:09:53.535 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-transport-api --- -23:09:53.904 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-api --- -23:09:54.934 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-rpc --- -23:09:55.257 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-flightexec --- -23:09:55.856 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-transport-netty --- -23:09:56.231 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-monitor --- -23:09:56.608 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-spring-support --- -23:09:57.049 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-default --- -23:09:57.388 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-zookeeper --- -23:09:57.910 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-hessian --- -23:09:58.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-java --- -23:09:59.018 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-kryo --- -23:10:00.087 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-protostuff --- -23:10:00.397 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-extension-tracing --- -23:10:00.411 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-all --- -23:10:01.768 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-example --- -23:10:04.932 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-common --- -23:10:05.550 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-api --- -23:10:05.986 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-transport-api --- -23:10:06.364 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-api --- -23:10:07.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-rpc --- -23:10:07.772 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-flightexec --- -23:10:08.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-transport-netty --- -23:10:08.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-monitor --- -23:10:09.146 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-spring-support --- -23:10:09.586 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-default --- -23:10:09.933 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-registry-zookeeper --- -23:10:10.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-hessian --- -23:10:10.987 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-java --- -23:10:11.583 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-kryo --- -23:10:12.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-serialization-protostuff --- -23:10:12.960 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-extension-tracing --- -23:10:12.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-all --- -23:10:14.372 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jupiter-example --- -23:10:15.468 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ core --- -23:10:15.594 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ javase --- -23:10:15.907 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ android --- -23:10:17.907 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ core --- -23:10:18.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ javase --- -23:10:18.347 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ android --- -23:10:19.929 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.3.0:test (default-test) @ reflectasm --- -23:10:21.490 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.3.0:test (default-test) @ reflectasm --- -23:10:22.901 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async --- -23:10:24.584 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async-maven-plugin --- -23:10:24.698 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async-maven-plugin-sample --- -23:10:25.784 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async --- -23:10:27.447 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async-maven-plugin --- -23:10:27.554 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.21.0:test (default-test) @ ea-async-maven-plugin-sample --- -23:10:31.096 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-cache --- -23:10:35.151 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-cache --- -23:10:40.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5 --- -23:10:41.318 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-fluent --- -23:10:42.598 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-cache --- -23:10:44.158 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-win --- -23:10:44.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-testing --- -23:10:49.220 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5 --- -23:10:50.104 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-fluent --- -23:10:51.329 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-cache --- -23:10:52.698 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-win --- -23:10:53.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.1:test (default-test) @ httpclient5-testing --- -23:10:57.893 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core --- -23:10:59.323 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core-shaded --- -23:11:00.043 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-query-builder --- -23:11:00.490 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-runtime --- -23:11:00.584 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-processor --- -23:11:00.990 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-test-infra --- -23:11:01.147 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-integration-tests --- -23:11:01.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-distribution --- -23:11:01.419 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-examples --- -23:11:06.211 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core --- -23:11:07.486 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core-shaded --- -23:11:08.163 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-query-builder --- -23:11:08.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-runtime --- -23:11:08.698 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-processor --- -23:11:09.117 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-test-infra --- -23:11:09.290 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-integration-tests --- -23:11:09.312 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-distribution --- -23:11:09.507 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-examples --- -23:11:14.403 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core --- -23:11:15.830 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core-shaded --- -23:11:16.570 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-query-builder --- -23:11:16.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-runtime --- -23:11:17.065 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-processor --- -23:11:17.479 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-test-infra --- -23:11:17.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-integration-tests --- -23:11:17.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-distribution --- -23:11:17.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-examples --- -23:11:22.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core --- -23:11:23.881 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-core-shaded --- -23:11:24.667 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-query-builder --- -23:11:25.086 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-runtime --- -23:11:25.201 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-mapper-processor --- -23:11:25.579 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-test-infra --- -23:11:25.719 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-integration-tests --- -23:11:25.744 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-distribution --- -23:11:25.939 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ java-driver-examples --- -23:11:32.656 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-core --- -23:11:35.863 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-rest --- -23:11:39.089 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-tomcat7 --- -23:11:44.699 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-tomcat85 --- -23:11:49.847 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-tomcat9 --- -23:11:53.173 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-web --- -23:12:00.178 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-core --- -23:12:03.500 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-rest --- -23:12:09.150 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-tomcat85 --- -23:12:13.619 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-tomcat9 --- -23:12:17.448 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M4:test (default-test) @ psi-probe-web --- -23:12:18.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-api --- -23:12:18.865 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-common --- -23:12:22.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-compiler --- -23:12:23.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-backend --- -23:12:24.305 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-kafka --- -23:12:33.388 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-tests --- -23:12:34.706 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-api --- -23:12:34.847 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-common --- -23:12:38.596 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-compiler --- -23:12:40.095 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-kafka --- -23:12:46.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-tests --- -23:12:48.223 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-api --- -23:12:48.373 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-common --- -23:12:52.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-compiler --- -23:12:53.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-backend --- -23:13:22.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-kafka --- -23:13:23.341 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-tests --- -23:13:24.576 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-common --- -23:13:28.392 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-compiler --- -23:13:29.599 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-backend --- -23:13:49.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-vm-connector-kafka --- -23:13:50.592 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ athenax-tests --- -23:13:52.187 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ apk-parser --- -23:13:54.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ apk-parser --- -23:13:55.877 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jdonframework --- -23:14:01.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jdonframework --- -23:14:04.484 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-cli) @ wasabi-export --- -23:14:05.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-cli) @ wasabi-export --- -23:14:07.149 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-experiment-objects --- -23:14:07.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-export --- -23:14:07.854 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-assignment-objects --- -23:14:08.130 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-exceptions --- -23:14:08.396 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-analytics-objects --- -23:14:08.681 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authentication-objects --- -23:14:08.899 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-eventlog --- -23:14:09.171 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-cassandra-datastax --- -23:14:09.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authorization-objects --- -23:14:09.691 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-user-directory --- -23:14:09.961 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-feedback-objects --- -23:14:10.172 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-auditlog-objects --- -23:14:10.443 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-database --- -23:14:10.753 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-repository-datastax --- -23:14:11.086 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-experiment --- -23:14:11.750 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-assignment --- -23:14:12.064 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-util --- -23:14:12.291 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-analytics --- -23:14:12.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-auditlog --- -23:14:12.985 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-event-objects --- -23:14:13.275 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-event --- -23:14:13.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-email --- -23:14:13.980 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-feedback --- -23:14:14.333 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authentication --- -23:14:14.671 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authorization --- -23:14:15.858 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-api --- -23:14:16.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-functional-test --- -23:14:16.565 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-main --- -23:14:17.114 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-swagger-ui --- -23:14:18.800 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-experiment-objects --- -23:14:19.212 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-export --- -23:14:19.462 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-assignment-objects --- -23:14:19.732 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-exceptions --- -23:14:20.015 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-analytics-objects --- -23:14:20.273 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authentication-objects --- -23:14:20.492 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-eventlog --- -23:14:21.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authorization-objects --- -23:14:21.402 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-user-directory --- -23:14:21.682 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-feedback-objects --- -23:14:21.919 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-auditlog-objects --- -23:14:22.192 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-database --- -23:14:23.734 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-experiment --- -23:14:24.863 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-util --- -23:14:25.096 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-analytics --- -23:14:25.455 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-auditlog --- -23:14:25.785 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-event-objects --- -23:14:26.060 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-event --- -23:14:26.425 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-email --- -23:14:26.769 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-feedback --- -23:14:27.112 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authentication --- -23:14:27.462 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-authorization --- -23:14:28.672 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-api --- -23:14:29.115 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-functional-test --- -23:14:29.392 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-main --- -23:14:29.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.11:test (default-test) @ wasabi-swagger-ui --- -23:14:34.286 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-core --- -23:14:34.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-extensions --- -23:14:35.067 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-springmvc-plugin --- -23:14:35.871 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-httpclient-plugin --- -23:14:36.544 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-okhttp-plugin --- -23:14:37.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-datasource-plugin --- -23:14:38.018 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-zipkin-plugin --- -23:14:38.751 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-plugin --- -23:14:51.067 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-spring-cloud-plugin --- -23:14:51.761 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-resttmplate-plugin --- -23:14:52.063 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-flexible-plugin --- -23:14:52.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-2.6.x-plugin --- -23:15:04.502 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-all --- -23:15:05.828 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-sofa-boot-starter --- -23:15:06.239 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-core-test --- -23:15:06.513 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-logback-test --- -23:15:06.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j2-test --- -23:15:07.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j-test --- -23:15:10.901 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-core --- -23:15:11.186 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-extensions --- -23:15:11.649 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-springmvc-plugin --- -23:15:12.396 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-httpclient-plugin --- -23:15:13.031 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-okhttp-plugin --- -23:15:13.876 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-datasource-plugin --- -23:15:14.587 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-zipkin-plugin --- -23:15:15.277 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-plugin --- -23:15:27.632 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-spring-cloud-plugin --- -23:15:28.302 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-resttmplate-plugin --- -23:15:28.625 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-flexible-plugin --- -23:15:29.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-2.6.x-plugin --- -23:15:29.606 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-all --- -23:15:30.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-sofa-boot-starter --- -23:15:31.404 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-core-test --- -23:15:31.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-logback-test --- -23:15:32.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j2-test --- -23:15:32.280 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j-test --- -23:15:36.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-core --- -23:15:36.386 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-extensions --- -23:15:36.847 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-springmvc-plugin --- -23:15:37.606 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-httpclient-plugin --- -23:15:38.262 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-okhttp-plugin --- -23:15:39.090 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-datasource-plugin --- -23:15:39.784 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-zipkin-plugin --- -23:15:40.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-plugin --- -23:15:40.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-spring-cloud-plugin --- -23:15:41.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-resttmplate-plugin --- -23:15:41.974 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-flexible-plugin --- -23:15:42.727 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-2.6.x-plugin --- -23:15:42.758 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-all --- -23:15:44.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-sofa-boot-starter --- -23:15:44.615 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-core-test --- -23:15:44.912 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-logback-test --- -23:15:45.381 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j2-test --- -23:15:45.931 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j-test --- -23:15:49.925 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-core --- -23:15:50.225 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-extensions --- -23:15:50.692 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-springmvc-plugin --- -23:15:51.475 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-httpclient-plugin --- -23:15:52.140 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-okhttp-plugin --- -23:15:52.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-datasource-plugin --- -23:15:53.627 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-zipkin-plugin --- -23:15:54.358 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-plugin --- -23:15:54.844 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-spring-cloud-plugin --- -23:15:55.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-resttmplate-plugin --- -23:15:55.892 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-flexible-plugin --- -23:15:56.626 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-dubbo-2.6.x-plugin --- -23:15:56.657 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-all --- -23:15:58.057 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ tracer-sofa-boot-starter --- -23:15:58.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-core-test --- -23:15:58.796 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-logback-test --- -23:15:59.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j2-test --- -23:15:59.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ sofa-tracer-log4j-test --- -23:16:00.860 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ spqr --- -23:16:02.554 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ spqr --- -23:16:04.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-common --- -23:16:06.907 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web --- -23:16:07.969 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-client --- -23:16:08.149 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-jade --- -23:16:08.300 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-mvel --- -23:16:08.480 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-handlebars --- -23:16:08.772 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-thymeleaf --- -23:16:08.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-freemarker --- -23:16:09.112 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-pebble --- -23:16:09.659 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-rocker --- -23:16:11.108 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-contract --- -23:16:12.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-service --- -23:16:12.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-graphql --- -23:16:14.442 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-common --- -23:16:16.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web --- -23:16:17.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-client --- -23:16:17.832 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-jade --- -23:16:17.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-mvel --- -23:16:18.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-handlebars --- -23:16:18.472 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-thymeleaf --- -23:16:18.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-freemarker --- -23:16:18.788 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-pebble --- -23:16:19.318 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-rocker --- -23:16:20.698 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-contract --- -23:16:21.496 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-service --- -23:16:22.097 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-graphql --- -23:16:23.949 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-common --- -23:16:26.139 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web --- -23:16:27.208 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-client --- -23:16:27.391 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-jade --- -23:16:27.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-mvel --- -23:16:28.203 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-handlebars --- -23:16:28.364 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-thymeleaf --- -23:16:28.530 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-freemarker --- -23:16:28.676 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-pebble --- -23:16:29.217 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-rocker --- -23:16:30.728 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-contract --- -23:16:31.049 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-service --- -23:16:31.628 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-graphql --- -23:16:33.485 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-common --- -23:16:35.659 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web --- -23:16:36.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-client --- -23:16:37.054 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-jade --- -23:16:37.211 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-mvel --- -23:16:37.867 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-handlebars --- -23:16:38.031 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-thymeleaf --- -23:16:38.191 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-freemarker --- -23:16:38.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-pebble --- -23:16:38.861 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-templ-rocker --- -23:16:40.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-contract --- -23:16:40.580 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-api-service --- -23:16:41.224 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ vertx-web-graphql --- -23:16:42.732 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rtree --- -23:16:45.032 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rtree --- -23:17:00.827 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dble --- -23:17:17.844 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dble --- -23:17:34.725 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dble --- -23:17:50.425 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ dble --- -23:17:53.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-frontend --- -23:17:53.222 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks-testkit --- -23:17:54.989 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks --- -23:17:55.022 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ external-reports --- -23:17:55.075 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-surefire --- -23:17:55.191 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-java-plugin --- -23:17:55.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-jacoco-listeners --- -23:17:55.486 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-performancing --- -23:17:55.561 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-extension-plugin --- -23:17:55.586 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-plugin-tests --- -23:17:55.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-ruling --- -23:17:55.706 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-debugging-plugin --- -23:17:55.723 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-semantic-tests --- -23:17:57.787 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-frontend --- -23:17:57.892 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks-testkit --- -23:17:59.674 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks --- -23:17:59.708 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ external-reports --- -23:17:59.761 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-surefire --- -23:17:59.875 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-java-plugin --- -23:18:00.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-jacoco-listeners --- -23:18:00.181 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-performancing --- -23:18:00.258 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-extension-plugin --- -23:18:00.283 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-plugin-tests --- -23:18:00.328 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-ruling --- -23:18:00.392 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-debugging-plugin --- -23:18:00.411 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-semantic-tests --- -23:18:02.487 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-frontend --- -23:18:02.591 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks-testkit --- -23:18:04.146 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks --- -23:18:04.911 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ external-reports --- -23:18:04.962 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-surefire --- -23:18:05.078 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-java-plugin --- -23:18:05.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-jacoco-listeners --- -23:18:05.379 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-performancing --- -23:18:05.468 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-extension-plugin --- -23:18:05.493 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-plugin-tests --- -23:18:05.552 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-ruling --- -23:18:05.642 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-debugging-plugin --- -23:18:05.664 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-semantic-tests --- -23:18:10.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks-testkit --- -23:18:12.596 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-checks --- -23:18:13.332 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ external-reports --- -23:18:13.382 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-surefire --- -23:18:13.487 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-java-plugin --- -23:18:13.765 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ sonar-jacoco-listeners --- -23:18:13.800 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-performancing --- -23:18:13.884 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-extension-plugin --- -23:18:13.910 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-plugin-tests --- -23:18:13.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-ruling --- -23:18:14.043 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ java-debugging-plugin --- -23:18:14.061 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ it-java-semantic-tests --- -23:18:18.611 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ spring-hateoas --- -23:18:24.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ spring-hateoas --- -23:18:27.087 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator --- -23:18:27.162 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator-jsr303 --- -23:18:27.212 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator-spring --- -23:18:29.899 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator --- -23:18:29.972 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator-jsr303 --- -23:18:30.012 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14.1:test (default-test) @ fluent-validator-spring --- -23:18:32.507 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ BitHub --- -23:18:34.742 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ BitHub --- -23:18:36.269 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ BitHub --- -23:18:38.314 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ BitHub --- -23:18:49.653 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-core --- -23:18:52.894 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-pherf --- -23:18:54.686 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-client --- -23:18:56.552 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-server --- -23:19:00.163 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-tracing-webapp --- -23:19:12.269 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-core --- -23:19:15.519 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-pherf --- -23:19:17.322 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-client --- -23:19:19.194 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-server --- -23:19:22.932 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-tracing-webapp --- -23:19:34.829 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-core --- -23:19:38.820 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-pherf --- -23:19:40.618 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-client --- -23:19:42.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-server --- -23:19:46.108 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-tracing-webapp --- -23:19:58.192 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-core --- -23:20:02.192 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-pherf --- -23:20:04.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-client --- -23:20:05.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-server --- -23:20:09.510 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ phoenix-tracing-webapp --- -23:20:12.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry --- -23:20:12.727 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-android --- -23:20:12.744 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-appengine --- -23:20:12.770 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-log4j --- -23:20:13.304 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-logback --- -23:20:14.031 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-log4j2 --- -23:20:14.892 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-spring --- -23:20:14.936 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-spring-boot-starter --- -23:20:16.495 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry --- -23:20:16.662 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-android --- -23:20:16.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-appengine --- -23:20:16.715 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-log4j --- -23:20:17.255 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-logback --- -23:20:17.965 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-log4j2 --- -23:20:18.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-spring --- -23:20:18.473 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ sentry-spring-boot-starter --- -23:20:19.471 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-base --- -23:20:19.587 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-core --- -23:20:19.599 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-ioc --- -23:20:19.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-example --- -23:20:20.886 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-base --- -23:20:21.013 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-core --- -23:20:21.022 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-ioc --- -23:20:21.036 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ cicada-example --- -23:20:23.199 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner --- -23:20:23.381 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-extras --- -23:20:24.818 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-java8 --- -23:20:24.868 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-examples-common --- -23:20:24.905 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-examples-hotreload --- -23:20:26.840 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner --- -23:20:27.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-extras --- -23:21:17.317 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-java8 --- -23:21:17.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-examples-common --- -23:21:17.399 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ owner-examples-hotreload --- -23:21:18.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ xlsx-streamer --- -23:21:19.900 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ xlsx-streamer --- -23:21:21.332 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ xlsx-streamer --- -23:21:22.920 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ xlsx-streamer --- -23:21:36.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:24:21.393 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Worker --- -23:24:21.704 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Distribution --- -23:24:23.932 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:24:30.670 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:24:49.281 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Worker --- -23:24:49.634 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Distribution --- -23:24:55.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:25:09.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Worker --- -23:25:09.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Distribution --- -23:25:11.970 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:27:50.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.14:test (default-test) @ uReplicator-Controller --- -23:27:57.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-processor --- -23:27:58.044 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator --- -23:27:59.477 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-extension --- -23:27:59.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-test --- -23:27:59.506 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-example --- -23:27:59.517 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-knime --- -23:27:59.527 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-rapidminer --- -23:27:59.540 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-rattle --- -23:27:59.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-sas --- -23:27:59.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-jacoco --- -23:28:00.872 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-processor --- -23:28:01.114 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator --- -23:28:02.547 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-extension --- -23:28:02.561 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-test --- -23:28:02.585 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-example --- -23:28:02.605 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-knime --- -23:28:02.617 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-rapidminer --- -23:28:02.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-rattle --- -23:28:02.639 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-sas --- -23:28:02.774 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ pmml-evaluator-jacoco --- -23:28:04.235 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-core --- -23:28:04.315 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-testng --- -23:28:04.351 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-assertj --- -23:28:04.396 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-junit-jupiter --- -23:28:04.437 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-integration-tests --- -23:28:04.465 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-junit --- -23:28:06.157 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-cucumber --- -23:28:07.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-spock --- -23:28:07.096 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-coverage-report --- -23:28:08.562 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-core --- -23:28:08.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-testng --- -23:28:08.729 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-assertj --- -23:28:08.775 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-junit-jupiter --- -23:28:08.812 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-integration-tests --- -23:28:08.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-junit --- -23:28:10.101 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-cucumber --- -23:28:11.028 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-spock --- -23:28:11.045 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ fluentlenium-coverage-report --- -23:28:12.756 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-dictgenerator --- -23:28:16.348 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-core --- -23:28:17.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix40 --- -23:28:17.241 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix41 --- -23:28:17.430 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix42 --- -23:28:17.623 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix43 --- -23:28:17.838 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix44 --- -23:28:18.028 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50 --- -23:28:18.219 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50sp1 --- -23:28:18.405 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50sp2 --- -23:28:18.589 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fixt11 --- -23:28:18.780 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-all --- -23:28:18.941 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-executor --- -23:28:19.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-ordermatch --- -23:28:19.265 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-banzai --- -23:28:19.330 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-all --- -23:28:21.070 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-dictgenerator --- -23:28:24.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-core --- -23:28:25.457 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix40 --- -23:28:25.657 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix41 --- -23:28:25.853 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix42 --- -23:28:26.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix43 --- -23:28:26.239 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix44 --- -23:28:26.432 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50 --- -23:28:26.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50sp1 --- -23:28:26.824 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fix50sp2 --- -23:28:27.011 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-fixt11 --- -23:28:27.196 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-messages-all --- -23:28:27.361 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-executor --- -23:28:27.522 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-ordermatch --- -23:28:27.693 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-examples-banzai --- -23:28:27.761 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ quickfixj-all --- -23:28:29.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-spring-boot --- -23:28:31.195 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app --- -23:28:31.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-web-reactive-app --- -23:28:31.276 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-naked --- -23:28:31.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-ext-jar --- -23:28:34.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-docs --- -23:28:35.757 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-spring-boot --- -23:28:37.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app --- -23:28:37.324 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-web-reactive-app --- -23:28:37.346 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-naked --- -23:28:37.365 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-ext-jar --- -23:28:40.364 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-docs --- -23:28:41.993 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-spring-boot --- -23:28:48.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app --- -23:28:48.700 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-web-reactive-app --- -23:28:48.736 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-naked --- -23:28:48.759 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-ext-jar --- -23:28:51.584 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-docs --- -23:28:53.181 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-spring-boot --- -23:28:54.713 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app --- -23:28:54.751 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-web-reactive-app --- -23:28:54.773 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-naked --- -23:28:54.790 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-demo-app-ext-jar --- -23:28:58.949 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ chaos-monkey-docs --- -23:29:00.074 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ zt-exec --- -23:29:01.532 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ zt-exec --- -23:29:30.065 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:29:30.559 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:29:30.759 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:29:31.598 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:29:31.943 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:29:32.478 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:29:33.037 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:29:33.671 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:29:34.317 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:29:34.846 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:29:35.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:29:36.514 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:29:37.347 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:29:37.862 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:29:38.924 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:29:39.433 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:29:39.941 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:29:40.783 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:29:41.552 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:29:42.080 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:29:42.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:29:43.188 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:29:43.752 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:29:44.398 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:29:44.939 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:29:45.543 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:29:48.695 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:29:49.240 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:29:49.818 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:29:51.241 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:29:51.861 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:29:52.342 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:29:53.207 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:29:53.746 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:29:58.752 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:29:59.248 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:29:59.450 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:30:00.307 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:30:00.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:30:01.220 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:30:01.822 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:30:02.458 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:30:03.128 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:30:03.684 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:30:04.645 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:30:05.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:30:06.134 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:30:06.684 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:30:07.732 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:30:08.232 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:30:08.761 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:30:09.595 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:30:10.371 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:30:10.910 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:30:11.455 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:30:11.976 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:30:12.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:30:13.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:30:13.704 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:30:14.301 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:30:15.178 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:30:15.738 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:30:16.331 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:30:17.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:30:18.284 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:30:18.795 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:30:19.685 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:30:20.215 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:30:23.574 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:30:24.154 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:30:24.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:30:25.185 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:30:25.549 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:30:26.140 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:30:26.699 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:30:27.370 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:30:28.025 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:30:28.585 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:30:29.553 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:30:30.290 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:30:31.055 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:30:31.600 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:30:32.196 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:30:32.732 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:30:33.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:30:34.132 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:30:34.895 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:30:35.411 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:30:35.937 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:30:37.081 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:30:37.656 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:30:38.277 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:30:38.811 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:30:39.434 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:30:40.303 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:30:40.868 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:30:41.467 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:30:42.834 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:30:43.408 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:30:43.887 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:30:44.882 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:30:45.423 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:30:48.893 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:30:49.415 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:30:49.638 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:30:50.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:30:50.822 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:30:51.371 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:30:51.987 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:30:52.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:30:53.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:30:53.835 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:30:54.762 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:30:55.521 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:30:56.284 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:30:56.833 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:30:57.414 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:30:57.945 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:30:58.486 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:30:59.380 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:31:00.151 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:31:00.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:31:01.209 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:31:02.278 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:31:02.857 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:31:03.505 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:31:04.026 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:31:04.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:31:05.528 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:31:06.112 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:31:06.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:31:08.079 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:31:08.660 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:31:09.153 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:31:10.088 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:31:10.648 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:31:14.079 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:31:14.651 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:31:14.896 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:31:15.786 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:31:16.157 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:31:16.737 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:31:17.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:31:17.969 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:31:18.625 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:31:19.215 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:31:20.131 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:31:20.883 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:31:21.649 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:31:22.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:31:22.830 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:31:23.388 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:31:23.903 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:31:24.777 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:31:26.245 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:31:26.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:31:27.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:31:27.806 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:31:28.373 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:31:28.990 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:31:29.531 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:31:30.132 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:31:31.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:31:31.577 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:31:32.145 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:31:33.499 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:31:34.093 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:31:34.577 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:31:35.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:31:36.130 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:31:39.596 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-core --- -23:31:40.103 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-test-harness --- -23:31:40.321 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-slf4j --- -23:31:41.148 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-servlet --- -23:31:41.517 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-console --- -23:31:42.060 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cdi --- -23:31:42.646 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-guice --- -23:31:43.342 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-core --- -23:31:44.032 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-web --- -23:31:44.580 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-security --- -23:31:45.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-autoconfigure --- -23:31:46.281 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-legacy-spring-boot-starter --- -23:31:47.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-boot-starter --- -23:31:47.629 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-deltaspike --- -23:31:48.270 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-shiro --- -23:31:48.810 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsf --- -23:31:49.322 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-jsp --- -23:31:50.212 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-appengine --- -23:31:51.590 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cloud-datastore --- -23:31:52.098 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-archaius --- -23:31:52.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-mongodb --- -23:31:53.204 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-testing --- -23:31:53.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit --- -23:31:54.416 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-cassandra --- -23:31:54.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-hazelcast --- -23:31:55.595 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-zookeeper --- -23:31:56.442 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-dynamodb --- -23:31:57.032 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-spring-mobile --- -23:31:57.628 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-amazon-s3 --- -23:31:59.021 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ togglz-slack --- -23:31:59.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-redis --- -23:32:00.086 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-microprofile-config --- -23:32:00.942 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-benchmarks --- -23:32:01.491 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ togglz-junit5 --- -23:32:02.624 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:05.038 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:06.693 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:09.047 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:11.607 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:13.984 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ ddd-sample-2 --- -23:32:16.593 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rxjava-jdbc --- -23:32:19.102 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rxjava-jdbc --- -23:32:20.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-core --- -23:32:20.889 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-aws --- -23:32:20.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-elasticsearch --- -23:32:20.992 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-langid --- -23:32:21.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-solr --- -23:32:21.039 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-sql --- -23:32:21.147 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-tika --- -23:32:31.003 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-warc --- -23:32:31.062 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-archetype --- -23:32:34.083 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-aws --- -23:32:34.230 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-elasticsearch --- -23:32:34.246 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-langid --- -23:32:34.269 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-solr --- -23:32:34.281 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-sql --- -23:32:34.364 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-tika --- -23:32:36.329 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-warc --- -23:32:36.399 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ storm-crawler-archetype --- -23:32:44.541 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ spring-data-neo4j --- -23:32:55.748 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ spring-data-neo4j --- -23:33:00.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchdb-lucene --- -23:33:01.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ couchdb-lucene --- -23:33:26.597 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ dataverse --- -23:33:38.618 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ dataverse --- -23:33:43.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager --- -23:33:43.474 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc6 --- -23:33:43.497 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc7 --- -23:33:43.616 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc8 --- -23:33:43.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc9 --- -23:34:01.276 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ msm-kryo-serializer --- -23:34:01.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ msm-xstream-serializer --- -23:34:01.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ msm-flexjson-serializer --- -23:34:02.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager --- -23:34:02.526 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc6 --- -23:34:02.551 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc7 --- -23:34:02.640 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc8 --- -23:34:02.662 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ memcached-session-manager-tc9 --- -23:34:05.783 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ msm-xstream-serializer --- -23:34:05.801 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ msm-flexjson-serializer --- -23:34:06.977 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:07.054 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:07.088 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:07.147 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:07.182 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:07.243 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:07.268 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:07.295 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:07.329 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:07.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:07.398 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:07.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:07.473 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:07.496 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:07.570 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:07.618 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:07.671 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:08.721 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:08.749 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:08.798 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:08.845 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:08.885 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:08.921 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:08.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:08.998 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:09.046 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:09.094 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:09.134 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:09.211 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:09.270 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:09.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:09.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:09.358 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:10.554 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:10.641 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:10.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:10.731 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:10.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:10.832 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:10.856 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:10.886 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:10.917 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:10.950 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:10.986 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:11.030 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:11.072 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:11.099 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:11.189 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:11.233 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:11.292 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:12.307 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:12.336 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:12.390 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:12.435 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:12.477 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:12.515 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:12.549 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:12.592 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:12.637 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:13.234 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:13.305 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:13.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:13.404 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:13.431 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:13.452 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:14.687 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:14.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:14.816 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:14.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:14.905 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:14.971 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:14.995 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:15.023 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:15.057 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:15.090 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:15.127 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:15.171 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:15.206 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:15.231 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:15.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:15.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:15.418 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:15.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:15.753 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:15.807 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:15.853 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:15.897 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:15.935 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:15.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:16.020 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:16.075 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:16.128 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:16.174 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:16.262 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:16.327 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:16.377 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:16.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:16.427 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:17.645 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:20.267 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:20.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:20.322 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:21.390 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:21.421 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:23.102 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:24.164 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:24.209 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:26.327 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:26.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:27.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:27.025 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:27.050 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:28.316 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:28.401 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:28.440 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:28.499 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:28.533 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:28.598 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:28.625 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:28.657 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:28.692 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:28.724 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:28.760 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:28.803 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:28.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:28.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:28.956 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:29.011 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:29.073 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:29.120 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:29.149 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:29.204 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:29.259 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:29.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:29.348 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:29.380 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:30.056 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:30.102 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:30.156 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:30.202 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:30.284 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:30.366 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:30.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:30.441 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:30.459 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:31.713 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:31.813 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:31.849 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:31.899 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:31.938 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:32.001 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:32.024 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:32.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:32.082 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:32.113 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:32.148 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:32.197 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:32.243 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:32.272 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:32.367 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:32.420 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:32.480 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:32.526 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:32.555 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:32.610 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:32.659 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:32.702 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:32.741 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:32.779 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:33.470 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:33.517 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:33.568 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:33.612 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:33.697 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:33.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:33.812 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:33.837 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:33.858 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:35.108 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:35.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:35.245 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:35.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-util --- -23:34:35.329 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:35.403 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:35.429 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:35.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:35.505 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:35.546 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:35.592 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:35.635 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:35.676 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:35.705 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:35.791 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:36.130 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:36.186 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:36.225 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:36.255 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:36.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:36.358 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:36.402 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:36.442 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:36.476 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:36.527 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:36.578 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:36.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:36.680 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:36.766 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:36.832 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:36.883 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:36.906 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:36.932 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:38.172 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-servlet --- -23:34:38.256 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-logconfig --- -23:34:38.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-util --- -23:34:39.053 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-generictype --- -23:34:39.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-springext --- -23:34:39.142 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-springext-all --- -23:34:39.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-expr --- -23:34:39.192 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-base --- -23:34:39.224 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-dataresolver --- -23:34:39.256 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-configuration --- -23:34:39.297 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-resource --- -23:34:39.340 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-upload --- -23:34:39.367 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-common-hessian --- -23:34:39.444 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-requestcontext --- -23:34:39.716 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pull --- -23:34:39.768 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-form --- -23:34:39.808 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-pipeline --- -23:34:39.835 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-template --- -23:34:39.884 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-moduleloader --- -23:34:39.927 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mappingrule --- -23:34:39.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-jsp --- -23:34:40.005 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-velocity --- -23:34:40.035 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-freemarker --- -23:34:40.077 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-uribroker --- -23:34:40.125 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-service-mail --- -23:34:40.176 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-framework --- -23:34:40.219 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-webx --- -23:34:40.306 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-turbine --- -23:34:40.362 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-async --- -23:34:40.407 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-dev --- -23:34:40.440 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-webx-all --- -23:34:40.463 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.16:test (default-test) @ citrus-test-all --- -23:34:42.251 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ takes --- -23:34:44.694 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ takes --- -23:34:51.072 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-api --- -23:34:51.662 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-impl --- -23:34:52.187 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-tools --- -23:34:52.630 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-parsers --- -23:34:53.124 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-oboformat --- -23:34:53.709 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-rio --- -23:34:54.334 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-apibinding --- -23:34:54.909 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-compatibility --- -23:34:56.139 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-contract --- -23:34:57.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-distribution --- -23:34:58.525 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-osgidistribution --- -23:35:04.963 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-api --- -23:35:05.448 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-impl --- -23:35:05.891 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-tools --- -23:35:06.282 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-parsers --- -23:35:06.745 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-oboformat --- -23:35:07.282 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-rio --- -23:35:07.866 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-apibinding --- -23:35:08.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-compatibility --- -23:35:09.596 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-contract --- -23:35:10.536 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-distribution --- -23:35:11.352 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-test) @ owlapi-osgidistribution --- -23:35:13.459 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ Utils --- -23:35:13.585 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ Transport --- -23:35:15.819 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Core --- -23:35:17.636 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Client --- -23:35:17.681 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Server --- -23:35:17.718 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Mitm --- -23:35:17.792 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ Attacks --- -23:35:17.820 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Forensics --- -23:35:17.843 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TraceTool --- -23:35:19.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ Utils --- -23:35:19.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ Transport --- -23:35:21.952 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Core --- -23:35:23.096 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Client --- -23:35:23.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Server --- -23:35:24.386 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TLS-Forensics --- -23:35:24.412 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20.1:test (default-test) @ TraceTool --- -23:35:25.497 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jafka --- -23:35:37.669 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ jafka --- -23:35:40.014 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12:test (default-test) @ spring-websocket-portfolio --- -23:35:45.894 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12:test (default-test) @ spring-websocket-portfolio --- -23:35:58.712 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-embedded-webserver --- -23:35:59.426 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-spring-context --- -23:36:00.313 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-spring-webmvc-sample --- -23:36:01.392 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-embedded-webserver --- -23:36:02.169 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-spring-context --- -23:36:02.461 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ nacos-spring-webmvc-sample --- -23:36:04.167 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18:test (default-test) @ sonar-gitlab-plugin --- -23:36:07.006 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18:test (default-test) @ sonar-gitlab-plugin --- -23:36:09.607 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-runtime --- -23:36:10.454 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-compiler --- -23:36:11.484 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-maven-plugin --- -23:36:11.523 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-gradle-plugin --- -23:36:12.476 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-test-java6 --- -23:36:12.763 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ rocker-test-reload --- -23:36:13.985 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-test-java8 --- -23:36:15.890 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-runtime --- -23:36:16.733 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-compiler --- -23:36:17.781 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-maven-plugin --- -23:36:17.812 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-gradle-plugin --- -23:36:18.704 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-test-java6 --- -23:36:19.012 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19:test (default-test) @ rocker-test-reload --- -23:36:20.194 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ rocker-test-java8 --- -23:36:21.277 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ picasso2-okhttp3-downloader --- -23:36:23.555 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ picasso2-okhttp3-downloader --- -23:36:25.749 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-legacy --- -23:36:25.879 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-frontend --- -23:36:25.901 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-assembly --- -23:36:26.146 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-lib --- -23:36:28.673 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-sql --- -23:36:28.714 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-core --- -23:36:29.896 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-legacy --- -23:36:30.004 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-frontend --- -23:36:30.026 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-assembly --- -23:36:30.349 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-lib --- -23:36:32.178 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-sql --- -23:36:32.218 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ macrobase-core --- -23:36:33.831 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ amazon-kinesis-client --- -23:36:35.174 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ amazon-kinesis-client-multilang --- -23:36:37.287 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ amazon-kinesis-client --- -23:36:38.617 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ amazon-kinesis-client-multilang --- -23:36:46.665 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ lavagna --- -23:36:58.337 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.19.1:test (default-test) @ lavagna --- -23:37:09.889 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ soy --- -23:37:20.396 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ soy --- -23:37:21.892 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ distributed-redis-tool --- -23:37:24.257 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ distributed-redis-tool --- -23:37:26.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-core --- -23:37:26.326 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-commonshttp4 --- -23:37:26.634 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-jetty6 --- -23:37:27.628 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-core --- -23:37:27.750 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-commonshttp4 --- -23:37:28.015 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ signpost-jetty6 --- -23:37:29.201 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ github-maven-core --- -23:37:30.089 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ site-maven-plugin --- -23:37:31.296 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ github-maven-core --- -23:37:32.035 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ site-maven-plugin --- -23:37:33.376 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12:test (default-test) @ jongo --- -23:37:34.997 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12:test (default-test) @ jongo --- -23:37:36.142 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-cli) @ jongo --- -23:37:37.104 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.20:test (default-cli) @ jongo --- -23:37:38.410 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-common --- -23:37:38.489 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-client --- -23:37:38.981 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-common-gwt --- -23:37:39.216 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-service --- -23:37:41.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-server --- -23:37:41.659 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-webapp --- -23:37:42.787 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-common --- -23:37:42.871 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-client --- -23:37:43.312 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-common-gwt --- -23:37:43.575 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-service --- -23:37:45.158 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-server --- -23:37:45.166 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.0:test (default-test) @ openscoring-webapp --- -23:37:46.385 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ mybatis-plus --- -23:37:49.683 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.22.2:test (default-test) @ mybatis-plus --- -23:37:53.325 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12.4:test (default-test) @ sonar-objective-c-plugin --- -23:37:55.400 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.12.4:test (default-test) @ sonar-objective-c-plugin --- -23:37:56.901 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ natty --- -23:37:58.863 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ natty --- -23:38:00.560 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus --- -23:38:01.733 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-core --- -23:38:08.535 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-web --- -23:38:08.633 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-webservices --- -23:38:08.692 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-client --- -23:38:09.205 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-sdk --- -23:38:10.294 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus --- -23:38:11.310 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-core --- -23:38:14.797 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-web --- -23:38:14.915 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-webservices --- -23:38:15.004 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-client --- -23:38:15.504 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:2.18.1:test (default-test) @ argus-sdk --- -23:38:16.556 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ postgresql-embedded --- -23:38:22.713 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.2.5:test (default-test) @ postgresql-embedded --- -23:38:27.278 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-core-annotations --- -23:38:27.701 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-javac-support --- -23:38:28.112 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-core --- -23:38:28.582 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-rt-util --- -23:38:28.882 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-lombok --- -23:38:29.303 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jaxb --- -23:38:29.732 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jackson --- -23:38:30.162 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jackson1 --- -23:38:30.563 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jaxrs --- -23:38:30.973 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jaxws --- -23:38:31.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-spring-web --- -23:38:32.326 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-idl --- -23:38:35.550 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-java-xml-client --- -23:38:36.869 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-java-json-client --- -23:38:37.363 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-csharp-xml-client --- -23:38:37.861 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-c-xml-client --- -23:38:38.287 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-obj-c-xml-client --- -23:38:38.704 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-php-xml-client --- -23:38:39.124 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-php-json-client --- -23:38:39.563 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-ruby-json-client --- -23:38:40.118 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-javascript-client --- -23:38:41.614 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-gwt-json-overlay --- -23:38:42.195 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-swagger --- -23:38:42.646 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-docs --- -23:38:43.912 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-slim-maven-plugin --- -23:38:44.449 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-top --- -23:38:46.112 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-maven-plugin --- -23:38:47.778 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-full-api-edge-cases --- -23:38:48.951 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-jax-rs-jackson --- -23:38:50.193 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-jax-rs-jackson-lombok --- -23:38:50.722 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-jersey-storage --- -23:38:51.374 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-jersey-storage-spring --- -23:38:52.406 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-jboss-full --- -23:38:53.438 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-cxf-full --- -23:38:54.605 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-spring-petclinic --- -23:38:55.830 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-contract-first --- -23:38:57.964 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-core-annotations --- -23:38:58.326 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-javac-support --- -23:38:58.696 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-core --- -23:38:59.121 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-rt-util --- -23:38:59.373 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-lombok --- -23:38:59.759 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jaxb --- -23:39:00.138 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jackson --- -23:39:00.545 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jackson1 --- -23:39:01.421 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-jaxws --- -23:39:01.801 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-spring-web --- -23:39:02.672 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-idl --- -23:39:05.121 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-java-xml-client --- -23:39:06.405 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-java-json-client --- -23:39:06.851 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-csharp-xml-client --- -23:39:07.296 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-c-xml-client --- -23:39:07.679 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-obj-c-xml-client --- -23:39:08.048 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-php-xml-client --- -23:39:08.423 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-php-json-client --- -23:39:08.841 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-ruby-json-client --- -23:39:09.360 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-javascript-client --- -23:39:10.810 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-gwt-json-overlay --- -23:39:11.347 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-swagger --- -23:39:11.753 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-docs --- -23:39:12.968 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-slim-maven-plugin --- -23:39:13.467 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-top --- -23:39:15.101 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-maven-plugin --- -23:39:16.652 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-full-api-edge-cases --- -23:39:19.701 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-spring-petclinic --- -23:39:21.041 [StreamPumper-systemOut] INFO maven.runners.com.github.gilesi.harness.compsuite.Log4JLogger - [Maven] [INFO] --- surefire:3.0.0-M3:test (default-test) @ enunciate-examples-contract-first --- From 72469813d414018a8284da7b2f093966204b1cd1 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 15:41:27 +0200 Subject: [PATCH 168/244] more cleanup --- .../gilesi/testgenerator/ArgumentUtils.java | 42 +--- .../gilesi/testgenerator/DescriptorUtils.java | 128 ++++++++++++ .../com/github/gilesi/testgenerator/Main.java | 190 +----------------- .../gilesi/testgenerator/MarkerUtils.java | 26 +++ .../testgenerator/SerializationUtils.java | 42 +--- .../gilesi/testgenerator/TraceReader.java | 48 +++++ 6 files changed, 213 insertions(+), 263 deletions(-) create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/MarkerUtils.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceReader.java diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java index 3fcf93f2..ea1c0c2f 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -37,30 +37,13 @@ private static String getDataVariableDeclaration(InstanceReference serializableD if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { return VariableStackHandler.getVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils + String returnType = DescriptorUtils .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); if (returnType.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } - try { - var el = returnType.split("\\."); - Integer.valueOf(el[el.length - 1]); - - // so this is a number, replace type with "var" as we have no idea. - returnType = "var"; - } catch (NumberFormatException e) { - // Not a number, continue - } - - if (returnType.contains("..")) { - // Bad type, use var - returnType = "var"; - } - - if (returnType.endsWith(".")) { - returnType = "var"; - } + returnType = DescriptorUtils.getCleanedVar(returnType); variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); @@ -77,27 +60,10 @@ private static String getDataVariableDeclaration2(InstanceReference serializable if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { return VariableStackHandler.getVariableName(serializableData.getInstanceId()); } else { - String returnType = SerializationUtils + String returnType = DescriptorUtils .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); - try { - var el = returnType.split("\\."); - Integer.valueOf(el[el.length - 1]); - - // so this is a number, replace type with "var" as we have no idea. - returnType = "var"; - } catch (NumberFormatException e) { - // Not a number, continue - } - - if (returnType.contains("..")) { - // Bad type, use var - returnType = "var"; - } - - if (returnType.endsWith(".")) { - returnType = "var"; - } + returnType = DescriptorUtils.getCleanedVar(returnType); variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java new file mode 100644 index 00000000..f13d2069 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java @@ -0,0 +1,128 @@ +package com.github.gilesi.testgenerator; + +import java.util.ArrayList; +import java.util.List; + +import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; + +public class DescriptorUtils { + public static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { + if (name.length() == 0) { + return 0; + } + + return switch (name.charAt(0)) { + case 'I' -> 1; + case 'V' -> 1; + case 'Z' -> 1; + case 'B' -> 1; + case 'C' -> 1; + case 'S' -> 1; + case 'D' -> 1; + case 'F' -> 1; + case 'J' -> 1; + case 'L' -> name.indexOf(";") + 1; + case '[' -> getFirstArgLength(name.substring(1)) + 1; + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static String getCleanedType(String FQN) { + int currentCharacterIndex = 0; + char currentCharacter = FQN.charAt(currentCharacterIndex); + while (currentCharacter == '[') { + currentCharacter = FQN.charAt(++currentCharacterIndex); + } + + if (((currentCharacter == 'I' || currentCharacter == 'V' || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + (currentCharacter == 'L' && FQN.endsWith(";"))) { + try { + return JvmTypeToLangType(FQN).replace("$", "."); + } catch (UnsupportedJavaPrimitiveTypeException ignored) { + + } + } + return FQN.replace("$", "."); + } + + private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.length() - 1).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static void convertDescriptorToNormalTypesTest(String descr) throws UnsupportedJavaPrimitiveTypeException { + int startArg = descr.indexOf("("); + int endArg = descr.lastIndexOf(")"); + + String returns = descr.substring(endArg + 1, descr.length()); + String argusStr = descr.substring(startArg + 1, endArg); + + int length = 1; + List arguments = new ArrayList<>(); + String returnValue = null; + + do { + length = getFirstArgLength(argusStr); + String curArg = argusStr.substring(0, length); + argusStr = argusStr.substring(length); + if (curArg.length() != 0) { + arguments.add(getCleanedType(curArg)); + } + } while (length != 0); + + if (!returns.equals("V")) { + returnValue = getCleanedType(returns); + } + + System.out.println("Descriptor: " + descr); + + if (arguments.size() != 0) { + System.out.println("Arguments: (%s)".formatted(String.join(", ", arguments))); + } + + if (returnValue != null) { + System.out.println("Returns: " + returnValue); + } + } + + public static String getCleanedVar(String fullyQualifiedTypeName) { + String returnType = fullyQualifiedTypeName.replace("$", "."); + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + return returnType; + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index 08f77c5d..f8fdf965 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -1,135 +1,19 @@ package com.github.gilesi.testgenerator; -import com.fasterxml.jackson.databind.ObjectMapper; -import com.fasterxml.jackson.databind.SerializationFeature; -import com.github.gilesi.instrumentation.models.TestTraceResults; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; -import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; -import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; -import java.nio.file.Paths; import java.util.*; public class Main { - private static final ObjectMapper objectMapper = new ObjectMapper() - .enable(SerializationFeature.INDENT_OUTPUT) - // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) - .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) - .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) - .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); - - // This is ugly, I know - private static int GetTraceNumber(Path i) { - return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); - } - - private static ArrayList readTraces(String traceXmlFolder) throws IOException { - ArrayList traces = new ArrayList<>(); - - List traceFiles = Files.list(Path.of(traceXmlFolder)) - .sorted(Comparator.comparingInt(Main::GetTraceNumber)).toList(); - - for (Path testTraceFile : traceFiles) { - try { - TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), - TestTraceResults.class); - traces.add(testTraceResults.Trace); - } catch (Exception e) { - System.out.println("ERROR while deserializing a trace!"); - e.printStackTrace(); - } - } - - return traces; - } - - public static void writeMarker(List failure, String output) { - int mainPadding = 1; - String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, - mainPadding); - - while (Files.exists(Paths.get(tracesFileName))) { - tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, - ++mainPadding); - } - - try { - Files.write(new File(tracesFileName).toPath(), failure); - } catch (Throwable e) { - System.err.println("ERROR while saving marker"); - e.printStackTrace(); - } - } - - private static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { - if (name.length() == 0) { - return 0; - } - - return switch (name.charAt(0)) { - case 'I' -> 1; - case 'V' -> 1; - case 'Z' -> 1; - case 'B' -> 1; - case 'C' -> 1; - case 'S' -> 1; - case 'D' -> 1; - case 'F' -> 1; - case 'J' -> 1; - case 'L' -> name.indexOf(";") + 1; - case '[' -> getFirstArgLength(name.substring(1)) + 1; - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { - return switch (name.charAt(0)) { - case 'I' -> "java.lang.Integer"; - case 'V' -> "java.lang.Void"; - case 'Z' -> "java.lang.Boolean"; - case 'B' -> "java.lang.Byte"; - case 'C' -> "java.lang.Character"; - case 'S' -> "java.lang.Short"; - case 'D' -> "java.lang.Double"; - case 'F' -> "java.lang.Float"; - case 'J' -> "java.lang.Long"; - case 'L' -> name.substring(1, name.length() - 1).replace("/", "."); - case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - public static String getCleanedType(String FQN) { - int currentCharacterIndex = 0; - char currentCharacter = FQN.charAt(currentCharacterIndex); - while (currentCharacter == '[') { - currentCharacter = FQN.charAt(++currentCharacterIndex); - } - - if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || - (currentCharacter == 'L' && FQN.endsWith(";"))) { - try { - return JvmTypeToLangType(FQN).replace("$", "."); - } catch (UnsupportedJavaPrimitiveTypeException ignored) { - - } - } - return FQN.replace("$", "."); - } - public static void main(String[] args) throws IOException { - // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", "/home/gus/Git/gilesi/Results/generated/tests" }; @@ -153,7 +37,7 @@ public static void main(String[] args) throws IOException { return; } - ArrayList methodTraces = readTraces(traceXmlFolder); + ArrayList methodTraces = TraceReader.readTraces(traceXmlFolder); if (methodTraces.isEmpty()) { System.out.println("No traces found!"); @@ -211,8 +95,6 @@ public static void main(String[] args) throws IOException { for (int i = 0; i < methodTraces.size(); i++) { - // System.out.println("==========================="); - Trace trace = methodTraces.get(i); try { @@ -240,42 +122,6 @@ public static void main(String[] args) throws IOException { List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, variableStackHandler); - /*for (String descr : trace.getConfDescriptors()) { - int startArg = descr.indexOf("("); - int endArg = descr.lastIndexOf(")"); - - String returns = descr.substring(endArg + 1, descr.length()); - String argusStr = descr.substring(startArg + 1, endArg); - - int length = 1; - List arguments = new ArrayList<>(); - String returnValue = null; - - do { - length = getFirstArgLength(argusStr); - String curArg = argusStr.substring(0, length); - argusStr = argusStr.substring(length); - if (curArg.length() != 0) { - arguments.add(getCleanedType(curArg)); - } - } while (length != 0); - - if (!returns.equals("V")) { - returnValue = getCleanedType(returns); - } - - System.out.println("Descriptor: " + descr); - - if (arguments.size() != 0) { - System.out.println("Arguments: (%s)".formatted(String.join(", ", arguments))); - } - - if (returnValue != null) { - System.out.println("Returns: " + returnValue); - } - } - System.out.println();/* */ - if (trace.getMethodReference().getIsConstructor()) { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); @@ -362,8 +208,9 @@ public static void main(String[] args) throws IOException { testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); } - String returnType = getCleanedVar( - getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName())); + String returnType = DescriptorUtils.getCleanedVar( + DescriptorUtils.getCleanedType( + returnData.getClassReference().getFullyQualifiedTypeName())); returnVariableName = String.format("%s %s", returnType, returnVariableName); } @@ -437,7 +284,7 @@ public static void main(String[] args) throws IOException { } catch (Exception e) { System.out.println("Unable to convert trace to code!"); e.printStackTrace(); - writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); + MarkerUtils.writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); } @@ -476,29 +323,4 @@ public static void main(String[] args) throws IOException { Files.deleteIfExists(classOutputPath); Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); } - - public static String getCleanedVar(String fullyQualifiedTypeName) { - String returnType = fullyQualifiedTypeName.replace("$", "."); - - try { - var el = returnType.split("\\."); - Integer.valueOf(el[el.length - 1]); - - // so this is a number, replace type with "var" as we have no idea. - returnType = "var"; - } catch (NumberFormatException e) { - // Not a number, continue - } - - if (returnType.contains("..")) { - // Bad type, use var - returnType = "var"; - } - - if (returnType.endsWith(".")) { - returnType = "var"; - } - - return returnType; - } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/MarkerUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/MarkerUtils.java new file mode 100644 index 00000000..b9e14055 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/MarkerUtils.java @@ -0,0 +1,26 @@ +package com.github.gilesi.testgenerator; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class MarkerUtils { + public static void writeMarker(List failure, String output) { + int mainPadding = 1; + String tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sgilesi.testgen_failure_%d.marker", output, File.separatorChar, + ++mainPadding); + } + + try { + Files.write(new File(tracesFileName).toPath(), failure); + } catch (Throwable e) { + System.err.println("ERROR while saving marker"); + e.printStackTrace(); + } + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index 36ae4cb5..d17a178b 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -3,56 +3,16 @@ import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.exceptions.SerializationException; -import com.github.gilesi.testgenerator.exceptions.UnsupportedJavaPrimitiveTypeException; import org.apache.commons.text.StringEscapeUtils; import java.util.ArrayList; import java.util.List; public class SerializationUtils { - private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { - return switch (name.charAt(0)) { - case 'I' -> "java.lang.Integer"; - case 'V' -> "java.lang.Void"; - case 'Z' -> "java.lang.Boolean"; - case 'B' -> "java.lang.Byte"; - case 'C' -> "java.lang.Character"; - case 'S' -> "java.lang.Short"; - case 'D' -> "java.lang.Double"; - case 'F' -> "java.lang.Float"; - case 'J' -> "java.lang.Long"; - case 'L' -> name.substring(1, name.charAt(name.length() - 1)).replace("/", "."); - case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); - default -> throw new UnsupportedJavaPrimitiveTypeException(name); - }; - } - - public static String getCleanedType(String FQN) { - int currentCharacterIndex = 0; - char currentCharacter = FQN.charAt(currentCharacterIndex); - while (currentCharacter == '[') { - currentCharacter = FQN.charAt(++currentCharacterIndex); - } - - if (((currentCharacter == 'I' || currentCharacter == 'V' || - currentCharacter == 'Z' || currentCharacter == 'B' || - currentCharacter == 'C' || currentCharacter == 'S' || - currentCharacter == 'D' || currentCharacter == 'F' || - currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || - (currentCharacter == 'L' && FQN.endsWith(";"))) { - try { - return JvmTypeToLangType(FQN).replace("$", "."); - } catch (UnsupportedJavaPrimitiveTypeException ignored) { - - } - } - return FQN.replace("$", "."); - } - public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) throws SerializationException { String valueToBeEqualTo = serializableData.getValueAsXmlString(); - String FQN = getCleanedType(argClass.getFullyQualifiedTypeName()); + String FQN = DescriptorUtils.getCleanedType(argClass.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceReader.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceReader.java new file mode 100644 index 00000000..acc9da93 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceReader.java @@ -0,0 +1,48 @@ +package com.github.gilesi.testgenerator; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.instrumentation.models.TestTraceResults; +import com.github.gilesi.instrumentation.models.Trace; + +public class TraceReader { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + // This is ugly, I know + private static int GetTraceNumber(Path i) { + return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); + } + + public static ArrayList readTraces(String traceXmlFolder) throws IOException { + ArrayList traces = new ArrayList<>(); + + List traceFiles = Files.list(Path.of(traceXmlFolder)) + .sorted(Comparator.comparingInt(TraceReader::GetTraceNumber)).toList(); + + for (Path testTraceFile : traceFiles) { + try { + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), + TestTraceResults.class); + traces.add(testTraceResults.Trace); + } catch (Exception e) { + System.out.println("ERROR while deserializing a trace!"); + e.printStackTrace(); + } + } + + return traces; + } +} From 83d891c3b779e6a39b7a8c16c095a6946755024f Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 15:41:37 +0200 Subject: [PATCH 169/244] Update gitignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 2e9b11a1..3cf0268c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ +Backup/ + # Compiled class file *.class From 2b243e4ac3728f9149174b31ce10d849683ee1b7 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 15:58:42 +0200 Subject: [PATCH 170/244] Further cleanup --- .../gilesi/testgenerator/ArgumentUtils.java | 94 +++--- .../gilesi/testgenerator/ClassUtils.java | 119 +++++++ .../com/github/gilesi/testgenerator/Main.java | 294 +----------------- .../gilesi/testgenerator/TraceUtils.java | 193 ++++++++++++ 4 files changed, 361 insertions(+), 339 deletions(-) create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java index ea1c0c2f..615d3549 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java @@ -9,44 +9,57 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { - public static String serializableDataToCode(InstanceReference arg, ClassReference argClass, + public static class ArgLineGenerateResult { + public boolean Success; + public String argumentsForMethodCall; + public List variableList; + + public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { + this.Success = Success; + this.argumentsForMethodCall = argumentsForMethodCall; + this.variableList = variableList; + } + } + + public static String serializableDataToCode(InstanceReference instanceReference, ClassReference classReference, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { - if (arg.getValueAsXmlString() != null) { - if (arg.getIsNull()) { + if (instanceReference.getValueAsXmlString() != null) { + if (instanceReference.getIsNull()) { return "null"; } - String dataLine = SerializationUtils.serializableDataToJava(arg, argClass); + String dataLine = SerializationUtils.serializableDataToJava(instanceReference, classReference); - if (failOnLambdas && arg.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { + if (failOnLambdas + && instanceReference.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } return dataLine; - } else if (variableStackHandler.DoesVariableExist(arg.getInstanceId())) { - return VariableStackHandler.getVariableName(arg.getInstanceId()); + } else if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { + return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { - return "// Unserializable data with instance id: " + arg.getInstanceId(); + return "// Unserializable data with instance id: " + instanceReference.getInstanceId(); } } - private static String getDataVariableDeclaration(InstanceReference serializableData, - VariableStackHandler variableStackHandler) throws SerializationException { - if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { - return VariableStackHandler.getVariableName(serializableData.getInstanceId()); + private static String getDataVariableDeclaration(InstanceReference instanceReference, + VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { + if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { + return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); } else { String returnType = DescriptorUtils - .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); - if (returnType.contains("..Lambda/")) { + .getCleanedType(instanceReference.getClassReference().getFullyQualifiedTypeName()); + if (failOnLambdas && returnType.contains("..Lambda/")) { throw new SerializationException("We cannot handle lamdas at the moment!"); } returnType = DescriptorUtils.getCleanedVar(returnType); - variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); - String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); + variableStackHandler.CreateNewVariable(instanceReference.getInstanceId()); + String instanceVariableName = VariableStackHandler.getVariableName(instanceReference.getInstanceId()); // if (serializableData.getValueAsXmlString() == null || // serializableData.getValueAsXmlString().equals("null")) { return "%s %s".formatted(returnType, instanceVariableName); @@ -55,53 +68,22 @@ private static String getDataVariableDeclaration(InstanceReference serializableD } } - private static String getDataVariableDeclaration2(InstanceReference serializableData, - VariableStackHandler variableStackHandler) { - if (variableStackHandler.DoesVariableExist(serializableData.getInstanceId())) { - return VariableStackHandler.getVariableName(serializableData.getInstanceId()); - } else { - String returnType = DescriptorUtils - .getCleanedType(serializableData.getClassReference().getFullyQualifiedTypeName()); - - returnType = DescriptorUtils.getCleanedVar(returnType); - - variableStackHandler.CreateNewVariable(serializableData.getInstanceId()); - String instanceVariableName = VariableStackHandler.getVariableName(serializableData.getInstanceId()); - // if (serializableData.getValueAsXmlString().equals("null")) { - return "%s %s".formatted(returnType, instanceVariableName); - // } - // return "%s %s".formatted("var", instanceVariableName); - } - } - - public static class ArgLineGenerateResult { - public boolean Success; - public String argumentsForMethodCall; - public List variableList; - - public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { - this.Success = Success; - this.argumentsForMethodCall = argumentsForMethodCall; - this.variableList = variableList; - } - } - - public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableStackHandler variableStackHandler) + public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHandler variableStackHandler) throws SerializationException { List preCallArguments = new ArrayList<>(); List variableList = new ArrayList<>(); boolean commentItAll = false; - for (int i = 0; i < methodTrace.getPreCallArguments().size(); i++) { - InstanceReference preCallArgument = methodTrace.getPreCallArguments().get(i); + for (int i = 0; i < trace.getPreCallArguments().size(); i++) { + InstanceReference preCallArgument = trace.getPreCallArguments().get(i); if (preCallArgument.getIsNull()) { preCallArguments.add("null"); continue; } - ClassReference correspondingMethodArg = methodTrace.getMethodReference().getParameterTypes()[i]; + ClassReference correspondingMethodArg = trace.getMethodReference().getParameterTypes()[i]; String argumentValue; try { @@ -113,11 +95,15 @@ public static ArgLineGenerateResult GenerateArgLine(Trace methodTrace, VariableS commentItAll = true; } - String argumentVariable; + String argumentVariable = null; try { - argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler); + argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler, true); } catch (SerializationException e) { - argumentVariable = getDataVariableDeclaration2(preCallArgument, variableStackHandler); + try { + argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler, false); + } catch (SerializationException ex) { + + } commentItAll = true; // todo: problem here... } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java new file mode 100644 index 00000000..2817fa97 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java @@ -0,0 +1,119 @@ +package com.github.gilesi.testgenerator; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Arrays; + +import com.github.gilesi.instrumentation.models.Trace; + +public class ClassUtils { + private static final String GENERATED_TEST_NAME = "ClientSourcedGeneratedTest"; + private static final String GENERATED_PACKAGE_NAME = "com.gilesi.testgen.generated"; + private static final String GENERATED_CLASS_NAME = "GilesiGeneratedTestClass"; + + private static void generateClassFileHeader(StringBuilder stringBuilder, String packageName) { + if (!packageName.isEmpty()) { + stringBuilder.append("package %s;\n\n".formatted(packageName)); + } + + stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); + stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); + stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); + stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); + stringBuilder.append("import org.junit.jupiter.api.Test;\n"); + stringBuilder.append("import java.lang.Throwable;\n"); + stringBuilder.append("\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); + stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); + stringBuilder.append("\n"); + } + + public static void generateClassFile(ArrayList methodTraces, String testPath) throws IOException { + Path mainOutputPath = Path.of(testPath).toAbsolutePath(); + if (!Files.isDirectory(mainOutputPath)) { + Files.createDirectories(mainOutputPath); + } + + Path packageOutputPath = mainOutputPath.toAbsolutePath(); + + if (!GENERATED_PACKAGE_NAME.isEmpty()) { + for (String element : GENERATED_PACKAGE_NAME.split("\\.")) { + packageOutputPath = packageOutputPath.resolve(element); + } + + if (!Files.isDirectory(packageOutputPath)) { + Files.createDirectories(packageOutputPath); + } + } + + Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(GENERATED_CLASS_NAME)); + + StringBuilder stringBuilder = new StringBuilder(); + + generateClassFileHeader(stringBuilder, GENERATED_PACKAGE_NAME); + + stringBuilder.append("public class %s {\n".formatted(GENERATED_CLASS_NAME)); + + stringBuilder.append("\t@Test\n"); + stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(GENERATED_TEST_NAME)); + + VariableStackHandler variableStackHandler = new VariableStackHandler(); + + StringBuilder testMethodStringBuilder = new StringBuilder(); + + for (int i = 0; i < methodTraces.size(); i++) { + System.out.println("Processing Trace %d out of %d".formatted(i + 1, methodTraces.size())); + + Trace trace = methodTraces.get(i); + + try { + TraceUtils.parseTrace(i, trace, variableStackHandler, testMethodStringBuilder); + + if (i != methodTraces.size() - 1) { + testMethodStringBuilder.append("\n"); + } + } catch (Exception e) { + System.out.println("Unable to convert trace to code!"); + e.printStackTrace(); + MarkerUtils.writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); + + stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); + } + } + + String padding = "\t\t"; + String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString() + .substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); + stringBuilder.append(String.format("%s\n\t}\n", paddedString)); + + stringBuilder.append(""" + + \tpublic static String getToXml(Object obj) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\treturn xStream.toXML(obj); + \t} + """); + + stringBuilder.append(""" + + \t@SuppressWarnings("unchecked") + \tpublic static T getFromXml(String xmlString) { + \t\tDomDriver domDriver = new DomDriver(); + \t\tXStream xStream = new XStream(domDriver); + \t\txStream.addPermission(AnyTypePermission.ANY); + \t\tObject obj = xStream.fromXML(xmlString); + \t\treturn (T) obj; + \t} + """); + + stringBuilder.append("}\n"); + stringBuilder.append("\n"); + + System.out.println(classOutputPath); + Files.deleteIfExists(classOutputPath); + Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index f8fdf965..b37d643e 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -1,8 +1,6 @@ package com.github.gilesi.testgenerator; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.instrumentation.models.InstanceReference; -import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; import java.io.IOException; import java.nio.file.Files; @@ -10,13 +8,7 @@ import java.util.*; public class Main { - public static void main(String[] args) throws IOException { - // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", - // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; - - args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", - "/home/gus/Git/gilesi/Results/generated/tests" }; - + private static void processArguments(String[] args) throws IOException { if (args.length != 2) { System.out.println("Usage: "); return; @@ -43,284 +35,16 @@ public static void main(String[] args) throws IOException { System.out.println("No traces found!"); } - Path mainOutputPath = Path.of(testPath).toAbsolutePath(); - if (!Files.isDirectory(mainOutputPath)) { - Files.createDirectories(mainOutputPath); - } - - String packageName = "com.gilesi.testgen.generated"; - Path packageOutputPath = mainOutputPath.toAbsolutePath(); - - if (!packageName.isEmpty()) { - for (String element : packageName.split("\\.")) { - packageOutputPath = packageOutputPath.resolve(element); - } - - if (!Files.isDirectory(packageOutputPath)) { - Files.createDirectories(packageOutputPath); - } - } - - String className = "GilesiGeneratedTestClass"; - - Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(className)); - - StringBuilder stringBuilder = new StringBuilder(); - - if (!packageName.isEmpty()) { - stringBuilder.append("package %s;\n\n".formatted(packageName)); - } - - stringBuilder.append("import com.thoughtworks.xstream.XStream;\n"); - stringBuilder.append("import com.thoughtworks.xstream.io.xml.DomDriver;\n"); - stringBuilder.append("import com.thoughtworks.xstream.security.AnyTypePermission;\n"); - stringBuilder.append("import com.thoughtworks.xstream.XStreamException;\n"); - stringBuilder.append("import org.junit.jupiter.api.Test;\n"); - stringBuilder.append("import java.lang.Throwable;\n"); - stringBuilder.append("\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertEquals;\n"); - stringBuilder.append("import static org.junit.jupiter.api.Assertions.assertArrayEquals;\n"); - stringBuilder.append("\n"); - - stringBuilder.append("public class %s {\n".formatted(className)); - - String testName = "ClientSourcedGeneratedTest"; - - stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(testName)); - - VariableStackHandler variableStackHandler = new VariableStackHandler(); - - StringBuilder testMethodStringBuilder = new StringBuilder(); - - for (int i = 0; i < methodTraces.size(); i++) { - - Trace trace = methodTraces.get(i); - - try { - String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; - methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - - InstanceReference instanceData = trace.getInstanceReference(); - - boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() - .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); - - InstanceReference returnData = trace.getReturnedValue(); - String returnVariableName = ""; - if (returnData != null) { - returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); - } - - String instanceVariableName = ""; - if (instanceData != null) { - instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); - } - - ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); - String argumentLine = argLineResult.argumentsForMethodCall; - List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, - variableStackHandler); - - if (trace.getMethodReference().getIsConstructor()) { - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); - instanceVariableName = String.format("%s %s", methodName, instanceVariableName); - } - - String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, - argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("%s\n", str)); - } - - testMethodStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append(returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("// %s\n", str)); - } - - testMethodStringBuilder.append("// " + callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append("// " + varAssert + "\n"); - } - } - } else { - StringBuilder callStringBuilder = new StringBuilder(); - - // Holds whenever or not an issue with instances was found - // If true, we should not create new variables and we should comment out the - // whole code. - // As the code simply is not generable. - boolean issuesDetected = false; - - if (isInstanceCall) { - // When we have an instance dependent call, we need the instance the call is - // performed onto to exist - // If it does not exist, then we cannot generate this code - // Log that, and comment out the code we would have generated. - // And make sure we do not create a variable for the return value if a thing. - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", - i + 1, methodName, instanceData.getInstanceId(), - instanceData.getClassReference().getFullyQualifiedTypeName()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - - issuesDetected = true; - } - - // An instance method call is not called by its fully qualified name (i.e. - // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. - String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); - } - - if (returnData != null) { - if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { - if (!issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.getInstanceId()); - } else { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", - i + 1, returnData.getInstanceId()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - } - - String returnType = DescriptorUtils.getCleanedVar( - DescriptorUtils.getCleanedType( - returnData.getClassReference().getFullyQualifiedTypeName())); - returnVariableName = String.format("%s %s", returnType, returnVariableName); - } - - String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - callStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append(returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } - - callStringBuilder.append("// " + callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append("// " + returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } - } - } else { - String callLine = String.format("%s(%s);\n", methodName, argumentLine); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - callStringBuilder.append(callLine); - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } - - callStringBuilder.append("// " + callLine); - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } - } - } - - // Append the method call to the current string builder. - if (issuesDetected) { - testMethodStringBuilder.append(String.format("// %s", callStringBuilder.toString())); - } else { - testMethodStringBuilder.append(callStringBuilder.toString()); - } - } - - if (i != methodTraces.size() - 1) { - testMethodStringBuilder.append("\n"); - } - } catch (Exception e) { - System.out.println("Unable to convert trace to code!"); - e.printStackTrace(); - MarkerUtils.writeMarker(Arrays.stream(e.toString().split("\\n")).toList(), mainOutputPath.toString()); - - stringBuilder.append("\t\t// %s \n".formatted(trace.getMethodReference().getMethodSignature())); - } - } - - String padding = "\t\t"; - String paddedString = String.format("%s%s", padding, testMethodStringBuilder.toString() - .substring(0, testMethodStringBuilder.length() - 1).replace("\n", String.format("\n%s", padding))); - stringBuilder.append(String.format("%s\n\t}\n", paddedString)); - - stringBuilder.append(""" - - \tpublic static String getToXml(Object obj) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\treturn xStream.toXML(obj); - \t} - """); - - stringBuilder.append(""" + ClassUtils.generateClassFile(methodTraces, testPath); + } - \t@SuppressWarnings("unchecked") - \tpublic static T getFromXml(String xmlString) { - \t\tDomDriver domDriver = new DomDriver(); - \t\tXStream xStream = new XStream(domDriver); - \t\txStream.addPermission(AnyTypePermission.ANY); - \t\tObject obj = xStream.fromXML(xmlString); - \t\treturn (T) obj; - \t} - """); + public static void main(String[] args) throws IOException { + // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", + // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; - stringBuilder.append("}\n"); - stringBuilder.append("\n"); + args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", + "/home/gus/Git/gilesi/Results/generated/tests" }; - System.out.println(classOutputPath); - Files.deleteIfExists(classOutputPath); - Files.write(Files.createFile(classOutputPath), stringBuilder.toString().getBytes()); + processArguments(args); } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java new file mode 100644 index 00000000..08780590 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -0,0 +1,193 @@ +package com.github.gilesi.testgenerator; + +import java.util.List; + +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; +import com.github.gilesi.testgenerator.exceptions.SerializationException; + +public class TraceUtils { + public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, + StringBuilder testMethodStringBuilder) throws SerializationException { + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); + + InstanceReference instanceData = trace.getInstanceReference(); + + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); + + InstanceReference returnData = trace.getReturnedValue(); + String returnVariableName = ""; + if (returnData != null) { + returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); + } + + String instanceVariableName = ""; + if (instanceData != null) { + instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); + } + + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); + String argumentLine = argLineResult.argumentsForMethodCall; + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, + variableStackHandler); + + if (trace.getMethodReference().getIsConstructor()) { + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); + instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + } + + String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("%s\n", str)); + } + + testMethodStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("// %s\n", str)); + } + + testMethodStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + testMethodStringBuilder.append("// " + varAssert + "\n"); + } + } + } else { + StringBuilder callStringBuilder = new StringBuilder(); + + // Holds whenever or not an issue with instances was found + // If true, we should not create new variables and we should comment out the + // whole code. + // As the code simply is not generable. + boolean issuesDetected = false; + + if (isInstanceCall) { + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist + // If it does not exist, then we cannot generate this code + // Log that, and comment out the code we would have generated. + // And make sure we do not create a variable for the return value if a thing. + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + traceId + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); + + issuesDetected = true; + } + + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } + + if (returnData != null) { + if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { + if (!issuesDetected) { + variableStackHandler.CreateNewVariable(returnData.getInstanceId()); + } else { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + traceId + 1, returnData.getInstanceId()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); + } + + String returnType = DescriptorUtils.getCleanedVar( + DescriptorUtils.getCleanedType( + returnData.getClassReference().getFullyQualifiedTypeName())); + returnVariableName = String.format("%s %s", returnType, returnVariableName); + } + + String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + + callStringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append(returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } + + callStringBuilder.append("// " + callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + callStringBuilder.append("// " + returnAssertionLine + "\n"); + } + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } + } + } else { + String callLine = String.format("%s(%s);\n", methodName, argumentLine); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + + callStringBuilder.append(callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); + } + + callStringBuilder.append("// " + callLine); + + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append("// " + varAssert + "\n"); + } + } + } + + // Append the method call to the current string builder. + if (issuesDetected) { + testMethodStringBuilder.append(String.format("// %s", callStringBuilder.toString())); + } else { + testMethodStringBuilder.append(callStringBuilder.toString()); + } + } + } +} \ No newline at end of file From 89fc12e7528ec8586b5d426b0182ee325c0b1aab Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 16:08:49 +0200 Subject: [PATCH 171/244] cleanup --- .../gilesi/testgenerator/TraceUtils.java | 275 ++++++++++-------- 1 file changed, 146 insertions(+), 129 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 08780590..7e6d096c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -8,13 +8,54 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class TraceUtils { - public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, - StringBuilder testMethodStringBuilder) throws SerializationException { - String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; - methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); + private static void handleConstructor(VariableStackHandler variableStackHandler, InstanceReference instanceData, + String instanceVariableName, String methodName, String argumentLine, ArgLineGenerateResult argLineResult, + StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) + throws SerializationException { + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); + instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + } - InstanceReference instanceData = trace.getInstanceReference(); + String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + stringBuilder.append(String.format("%s\n", str)); + } + + stringBuilder.append(callLine); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + stringBuilder.append(returnAssertionLine + "\n"); + } + for (String varAssert : postCallParameterAssertionLine) { + stringBuilder.append(varAssert + "\n"); + } + } else { + for (String str : argLineResult.variableList) { + stringBuilder.append(String.format("// %s\n", str)); + } + + stringBuilder.append(String.format("// %s", callLine)); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + stringBuilder.append(String.format("// %s\n", returnAssertionLine)); + } + + for (String varAssert : postCallParameterAssertionLine) { + stringBuilder.append(String.format("// %s\n", varAssert)); + } + } + } + + private static void handleMethod(int traceId, + VariableStackHandler variableStackHandler, InstanceReference instanceData, + String instanceVariableName, String methodName, String argumentLine, ArgLineGenerateResult argLineResult, + StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) + throws SerializationException { boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); @@ -24,170 +65,146 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); } - String instanceVariableName = ""; - if (instanceData != null) { - instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); - } + StringBuilder callStringBuilder = new StringBuilder(); - ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); - String argumentLine = argLineResult.argumentsForMethodCall; - List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, - variableStackHandler); + // Holds whenever or not an issue with instances was found + // If true, we should not create new variables and we should comment out the + // whole code. + // As the code simply is not generable. + boolean issuesDetected = false; - if (trace.getMethodReference().getIsConstructor()) { + if (isInstanceCall) { + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist + // If it does not exist, then we cannot generate this code + // Log that, and comment out the code we would have generated. + // And make sure we do not create a variable for the return value if a thing. if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); - instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + traceId + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + stringBuilder.append(String.format("// %s\n", warnMessage)); + + issuesDetected = true; + } + + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } + + if (returnData != null) { + if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { + if (!issuesDetected) { + variableStackHandler.CreateNewVariable(returnData.getInstanceId()); + } else { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + traceId + 1, returnData.getInstanceId()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + stringBuilder.append(String.format("// %s\n", warnMessage)); + } + + String returnType = DescriptorUtils.getCleanedVar( + DescriptorUtils.getCleanedType( + returnData.getClassReference().getFullyQualifiedTypeName())); + returnVariableName = String.format("%s %s", returnType, returnVariableName); } - String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, - argumentLine); + String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (argLineResult.Success) { for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("%s\n", str)); + callStringBuilder.append(String.format("%s\n", str)); } - testMethodStringBuilder.append(callLine); + callStringBuilder.append(callLine); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append(returnAssertionLine + "\n"); + callStringBuilder.append(String.format("%s\n", returnAssertionLine)); } for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append(varAssert + "\n"); + callStringBuilder.append(String.format("%s\n", varAssert)); } } else { for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("// %s\n", str)); + callStringBuilder.append(String.format("// %s\n", str)); } - testMethodStringBuilder.append("// " + callLine); + callStringBuilder.append(String.format("// %s", callLine)); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - testMethodStringBuilder.append("// " + returnAssertionLine + "\n"); + callStringBuilder.append(String.format("// %s\n", returnAssertionLine)); } for (String varAssert : postCallParameterAssertionLine) { - testMethodStringBuilder.append("// " + varAssert + "\n"); + callStringBuilder.append(String.format("// %s\n", varAssert)); } } } else { - StringBuilder callStringBuilder = new StringBuilder(); - - // Holds whenever or not an issue with instances was found - // If true, we should not create new variables and we should comment out the - // whole code. - // As the code simply is not generable. - boolean issuesDetected = false; - - if (isInstanceCall) { - // When we have an instance dependent call, we need the instance the call is - // performed onto to exist - // If it does not exist, then we cannot generate this code - // Log that, and comment out the code we would have generated. - // And make sure we do not create a variable for the return value if a thing. - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", - traceId + 1, methodName, instanceData.getInstanceId(), - instanceData.getClassReference().getFullyQualifiedTypeName()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - - issuesDetected = true; + String callLine = String.format("%s(%s);\n", methodName, argumentLine); + if (argLineResult.Success) { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); } - // An instance method call is not called by its fully qualified name (i.e. - // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. - String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); - } + callStringBuilder.append(callLine); - if (returnData != null) { - if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { - if (!issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.getInstanceId()); - } else { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", - traceId + 1, returnData.getInstanceId()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - testMethodStringBuilder.append(String.format("// %s\n", warnMessage)); - } - - String returnType = DescriptorUtils.getCleanedVar( - DescriptorUtils.getCleanedType( - returnData.getClassReference().getFullyQualifiedTypeName())); - returnVariableName = String.format("%s %s", returnType, returnVariableName); + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("%s\n", varAssert)); + } + } else { + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("// %s\n", str)); } - String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - callStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append(returnAssertionLine + "\n"); - } - - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } - - callStringBuilder.append("// " + callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append("// " + returnAssertionLine + "\n"); - } + callStringBuilder.append(String.format("// %s", callLine)); - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("// %s\n", varAssert)); } - } else { - String callLine = String.format("%s(%s);\n", methodName, argumentLine); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } + } + } - callStringBuilder.append(callLine); + // Append the method call to the current string builder. + if (issuesDetected) { + stringBuilder.append(String.format("// %s", callStringBuilder.toString())); + } else { + stringBuilder.append(callStringBuilder.toString()); + } + } - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(varAssert + "\n"); - } - } else { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); - } + public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, + StringBuilder testMethodStringBuilder) throws SerializationException { + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); - callStringBuilder.append("// " + callLine); + InstanceReference instanceData = trace.getInstanceReference(); - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append("// " + varAssert + "\n"); - } - } - } + String instanceVariableName = ""; + if (instanceData != null) { + instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); + } - // Append the method call to the current string builder. - if (issuesDetected) { - testMethodStringBuilder.append(String.format("// %s", callStringBuilder.toString())); - } else { - testMethodStringBuilder.append(callStringBuilder.toString()); - } + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); + String argumentLine = argLineResult.argumentsForMethodCall; + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, + variableStackHandler); + + if (trace.getMethodReference().getIsConstructor()) { + handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, + argLineResult, testMethodStringBuilder, postCallParameterAssertionLine, trace); + } else { + handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, + argLineResult, testMethodStringBuilder, postCallParameterAssertionLine, trace); } } } \ No newline at end of file From a5a7b3ba44c48cc064d8890f1303ecca5cd4c863 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 16:15:59 +0200 Subject: [PATCH 172/244] Centralize configuration of test gen --- .../gilesi/testgenerator/AssertionUtils.java | 10 +++--- .../gilesi/testgenerator/ClassUtils.java | 16 ++++----- .../com/github/gilesi/testgenerator/Main.java | 8 ++--- .../testgenerator/StaticConfiguration.java | 10 ++++++ .../gilesi/testgenerator/TraceUtils.java | 36 ++++++++++++------- 5 files changed, 48 insertions(+), 32 deletions(-) create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java index cefb7790..64c9a7b5 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java @@ -11,8 +11,6 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class AssertionUtils { - private static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; - public static List traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { List argList = new ArrayList<>(); @@ -39,11 +37,11 @@ public static List traceArgumentsToAssert(Trace methodTrace, VariableSta try { assertionCodeLine = getReturnAssertionCodeLine(postCallArgument, correspondingMethodArg, variableStackHandler, true, - USE_ALTERNATIVE_ASSERTION_MODE); + StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(postCallArgument, correspondingMethodArg, variableStackHandler, false, - USE_ALTERNATIVE_ASSERTION_MODE)); + StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE)); } argList.add(assertionCodeLine); } @@ -132,12 +130,12 @@ public static String traceToAssert(Trace methodTrace, VariableStackHandler varia try { assertionCodeLine = getReturnAssertionCodeLine(traceData, methodTrace.getMethodReference().getReturnType(), variableStackHandler, true, - USE_ALTERNATIVE_ASSERTION_MODE); + StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { assertionCodeLine = "// %s" .formatted(getReturnAssertionCodeLine(traceData, methodTrace.getMethodReference().getReturnType(), variableStackHandler, false, - USE_ALTERNATIVE_ASSERTION_MODE)); + StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE)); } return assertionCodeLine; } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java index 2817fa97..e37d953c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java @@ -9,10 +9,6 @@ import com.github.gilesi.instrumentation.models.Trace; public class ClassUtils { - private static final String GENERATED_TEST_NAME = "ClientSourcedGeneratedTest"; - private static final String GENERATED_PACKAGE_NAME = "com.gilesi.testgen.generated"; - private static final String GENERATED_CLASS_NAME = "GilesiGeneratedTestClass"; - private static void generateClassFileHeader(StringBuilder stringBuilder, String packageName) { if (!packageName.isEmpty()) { stringBuilder.append("package %s;\n\n".formatted(packageName)); @@ -38,8 +34,8 @@ public static void generateClassFile(ArrayList methodTraces, String testP Path packageOutputPath = mainOutputPath.toAbsolutePath(); - if (!GENERATED_PACKAGE_NAME.isEmpty()) { - for (String element : GENERATED_PACKAGE_NAME.split("\\.")) { + if (!StaticConfiguration.GENERATED_PACKAGE_NAME.isEmpty()) { + for (String element : StaticConfiguration.GENERATED_PACKAGE_NAME.split("\\.")) { packageOutputPath = packageOutputPath.resolve(element); } @@ -48,16 +44,16 @@ public static void generateClassFile(ArrayList methodTraces, String testP } } - Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(GENERATED_CLASS_NAME)); + Path classOutputPath = packageOutputPath.resolve("%s.java".formatted(StaticConfiguration.GENERATED_CLASS_NAME)); StringBuilder stringBuilder = new StringBuilder(); - generateClassFileHeader(stringBuilder, GENERATED_PACKAGE_NAME); + generateClassFileHeader(stringBuilder, StaticConfiguration.GENERATED_PACKAGE_NAME); - stringBuilder.append("public class %s {\n".formatted(GENERATED_CLASS_NAME)); + stringBuilder.append("public class %s {\n".formatted(StaticConfiguration.GENERATED_CLASS_NAME)); stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(GENERATED_TEST_NAME)); + stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(StaticConfiguration.GENERATED_TEST_NAME)); VariableStackHandler variableStackHandler = new VariableStackHandler(); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index b37d643e..b8a231f2 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -39,11 +39,11 @@ private static void processArguments(String[] args) throws IOException { } public static void main(String[] args) throws IOException { - // args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", - // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", + "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; - args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", - "/home/gus/Git/gilesi/Results/generated/tests" }; + //args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", + // "/home/gus/Git/gilesi/Results/generated/tests" }; processArguments(args); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java new file mode 100644 index 00000000..34d69317 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java @@ -0,0 +1,10 @@ +package com.github.gilesi.testgenerator; + +public class StaticConfiguration { + public static final String GENERATED_TEST_NAME = "ClientSourcedGeneratedTest"; + public static final String GENERATED_PACKAGE_NAME = "com.gilesi.testgen.generated"; + public static final String GENERATED_CLASS_NAME = "GilesiGeneratedTestClass"; + + public static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; + public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = false; +} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 7e6d096c..392463a3 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -31,8 +31,10 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, stringBuilder.append(returnAssertionLine + "\n"); } - for (String varAssert : postCallParameterAssertionLine) { - stringBuilder.append(varAssert + "\n"); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + stringBuilder.append(varAssert + "\n"); + } } } else { for (String str : argLineResult.variableList) { @@ -45,8 +47,10 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } - for (String varAssert : postCallParameterAssertionLine) { - stringBuilder.append(String.format("// %s\n", varAssert)); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + stringBuilder.append(String.format("// %s\n", varAssert)); + } } } } @@ -131,8 +135,10 @@ private static void handleMethod(int traceId, callStringBuilder.append(String.format("%s\n", returnAssertionLine)); } - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("%s\n", varAssert)); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("%s\n", varAssert)); + } } } else { for (String str : argLineResult.variableList) { @@ -145,8 +151,10 @@ private static void handleMethod(int traceId, callStringBuilder.append(String.format("// %s\n", returnAssertionLine)); } - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("// %s\n", varAssert)); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("// %s\n", varAssert)); + } } } } else { @@ -158,8 +166,10 @@ private static void handleMethod(int traceId, callStringBuilder.append(callLine); - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("%s\n", varAssert)); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("%s\n", varAssert)); + } } } else { for (String str : argLineResult.variableList) { @@ -168,8 +178,10 @@ private static void handleMethod(int traceId, callStringBuilder.append(String.format("// %s", callLine)); - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("// %s\n", varAssert)); + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + callStringBuilder.append(String.format("// %s\n", varAssert)); + } } } } From 804a3222e6a1b5bbae3e275902ab75b08847eef8 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 16:27:55 +0200 Subject: [PATCH 173/244] cleanup duplicated serial code --- .../gilesi/testgenerator/AssertionUtils.java | 27 +----- .../testgenerator/SerializationUtils.java | 87 ++++++++----------- 2 files changed, 36 insertions(+), 78 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java index 64c9a7b5..340a6cf7 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java @@ -3,8 +3,6 @@ import java.util.ArrayList; import java.util.List; -import org.apache.commons.text.StringEscapeUtils; - import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; @@ -80,30 +78,7 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); } } else { - String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(returnedValueDataAsXml)); - - // int maxStringSize = (int) Math.pow(2, 16); - // TODO: CHeck why this still fails - int maxStringSize = 1024; - - if (valueAsCode.length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueAsCode.length()) { - end2 = valueAsCode.length(); - } - - String sectionOfDataAsXml = "SNIP";// valueToBeEqualTo.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - valueAsCode = String.join("+", sectionList.toArray(String[]::new)); - } - + String valueAsCode = SerializationUtils.generateStringJavaLine(returnedValueDataAsXml); assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java index d17a178b..fed03759 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java @@ -25,36 +25,13 @@ public static String serializableDataToJava(InstanceReference serializableData, !FQN.equals("java.lang.Long") && !FQN.equals("java.lang.String")) { - // int maxStringSize = (int) Math.pow(2, 16); - // TODO: Check why this still fails - int maxStringSize = 1024; - - if (serializableData.getValueAsXmlString().length() > maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start = 0; start < serializableData.getValueAsXmlString().length(); start += maxStringSize) { - int end = start + maxStringSize; - if (start + maxStringSize > serializableData.getValueAsXmlString().length()) { - end = serializableData.getValueAsXmlString().length(); - } - - String sectionOfDataAsXml = "SNIP";// serializableData.getValueAsXmlString().substring(start, end); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - String finalEscapedValue = String.join(" + ", sectionList.toArray(String[]::new)); + String valueAsCode = generateStringJavaLine(serializableData.getValueAsXmlString()); - valueToBeEqualTo = "getFromXml(%s)".formatted(finalEscapedValue); - } else { - // Casting is not needed if we only use this with variable assignments that are - // strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, - // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - valueToBeEqualTo = "getFromXml(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - } + // Casting is not needed if we only use this with variable assignments that are + // strictly typed + // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, + // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); + valueToBeEqualTo = "getFromXml(%s)".formatted(valueAsCode); } else { int start = valueToBeEqualTo.indexOf(">"); int end = valueToBeEqualTo.lastIndexOf(" maxStringSize) { - List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueToBeEqualTo.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueToBeEqualTo.length()) { - end2 = valueToBeEqualTo.length(); - } - - String sectionOfDataAsXml = "SNIP";// valueToBeEqualTo.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); - } - - valueToBeEqualTo = String.join(" + ", sectionList.toArray(String[]::new)); - } else { - valueToBeEqualTo = "\"%s\"".formatted(StringEscapeUtils.escapeJava(valueToBeEqualTo)); - } + valueToBeEqualTo = generateStringJavaLine(valueToBeEqualTo); } else if (FQN.equals("java.lang.Float")) { valueToBeEqualTo = "%sF".formatted(valueToBeEqualTo); } else if (FQN.equals("java.lang.Long")) { @@ -107,4 +62,32 @@ public static String serializableDataToJava(InstanceReference serializableData, return valueToBeEqualTo; } + + public static String generateStringJavaLine(String stringContent) { + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(stringContent)); + + // int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueAsCode.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = valueAsCode.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueAsCode = String.join(" + ", sectionList.toArray(String[]::new)); + } + + return valueAsCode; + } } From 39630791c8009889aef99f5ff50a2c62daccb426 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 11 Jul 2024 16:32:03 +0200 Subject: [PATCH 174/244] shift namespaces to reflect reviewed status --- .../gilesi/testgenerator/{ => review}/ArgumentUtils.java | 4 +++- .../gilesi/testgenerator/{ => review}/AssertionUtils.java | 4 +++- .../gilesi/testgenerator/{ => review}/SerializationUtils.java | 3 ++- 3 files changed, 8 insertions(+), 3 deletions(-) rename TestGenerator/src/main/java/com/github/gilesi/testgenerator/{ => review}/ArgumentUtils.java (97%) rename TestGenerator/src/main/java/com/github/gilesi/testgenerator/{ => review}/AssertionUtils.java (97%) rename TestGenerator/src/main/java/com/github/gilesi/testgenerator/{ => review}/SerializationUtils.java (97%) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java similarity index 97% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 615d3549..7a38bbdc 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.review; import java.util.ArrayList; import java.util.List; @@ -6,6 +6,8 @@ import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.DescriptorUtils; +import com.github.gilesi.testgenerator.VariableStackHandler; import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java similarity index 97% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 340a6cf7..01d0987d 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -1,4 +1,4 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.review; import java.util.ArrayList; import java.util.List; @@ -6,6 +6,8 @@ import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.testgenerator.StaticConfiguration; +import com.github.gilesi.testgenerator.VariableStackHandler; import com.github.gilesi.testgenerator.exceptions.SerializationException; public class AssertionUtils { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java similarity index 97% rename from TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java rename to TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index fed03759..f8c44ee9 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -1,7 +1,8 @@ -package com.github.gilesi.testgenerator; +package com.github.gilesi.testgenerator.review; import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.testgenerator.DescriptorUtils; import com.github.gilesi.testgenerator.exceptions.SerializationException; import org.apache.commons.text.StringEscapeUtils; From 68f12ec56127975a73dcd5862d5ecf927680138a Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 12 Jul 2024 09:29:23 +0200 Subject: [PATCH 175/244] fix compilation --- .../github/gilesi/testgenerator/TraceUtils.java | 4 +++- .../review/ArgLineGenerateResult.java | 15 +++++++++++++++ .../testgenerator/review/ArgumentUtils.java | 12 ------------ 3 files changed, 18 insertions(+), 13 deletions(-) create mode 100644 TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgLineGenerateResult.java diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 392463a3..8448bd3c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -4,7 +4,9 @@ import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; -import com.github.gilesi.testgenerator.ArgumentUtils.ArgLineGenerateResult; +import com.github.gilesi.testgenerator.review.ArgLineGenerateResult; +import com.github.gilesi.testgenerator.review.ArgumentUtils; +import com.github.gilesi.testgenerator.review.AssertionUtils; import com.github.gilesi.testgenerator.exceptions.SerializationException; public class TraceUtils { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgLineGenerateResult.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgLineGenerateResult.java new file mode 100644 index 00000000..7fc2ce84 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgLineGenerateResult.java @@ -0,0 +1,15 @@ +package com.github.gilesi.testgenerator.review; + +import java.util.List; + +public class ArgLineGenerateResult { + public boolean Success; + public String argumentsForMethodCall; + public List variableList; + + public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { + this.Success = Success; + this.argumentsForMethodCall = argumentsForMethodCall; + this.variableList = variableList; + } +} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 7a38bbdc..e768904d 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -11,18 +11,6 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { - public static class ArgLineGenerateResult { - public boolean Success; - public String argumentsForMethodCall; - public List variableList; - - public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { - this.Success = Success; - this.argumentsForMethodCall = argumentsForMethodCall; - this.variableList = variableList; - } - } - public static String serializableDataToCode(InstanceReference instanceReference, ClassReference classReference, VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { if (instanceReference.getValueAsXmlString() != null) { From 9856c9697141dd7f6cd45ab08fdebab7f2bc8b8e Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 12 Jul 2024 09:54:53 +0200 Subject: [PATCH 176/244] Refactor assert equals gen --- .../testgenerator/review/AssertionUtils.java | 20 +++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 01d0987d..9f081e28 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -60,7 +60,7 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue String instanceVarName = VariableStackHandler.getVariableName(returnedValueInstanceId); if (returnedValueDataAsXml.equals("null")) { - return "assertEquals(null, %s);".formatted(instanceVarName); + return generateAssertEquals("null", instanceVarName); } if (failOnLambdas @@ -75,19 +75,19 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue returnClassReference, variableStackHandler, true); if (valueAsCode.endsWith("[].class)")) { - assertionLine = "assertArrayEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + assertionLine = generateAssertArrayEquals(valueAsCode, instanceVarName); } else { - assertionLine = "assertEquals(%s, %s);".formatted(valueAsCode, instanceVarName); + assertionLine = generateAssertEquals(valueAsCode, instanceVarName); } } else { String valueAsCode = SerializationUtils.generateStringJavaLine(returnedValueDataAsXml); - assertionLine = "assertEquals(%s, getToXml(%s));".formatted(valueAsCode, instanceVarName); + assertionLine = generateAssertEquals(valueAsCode, "getToXml(%s)".formatted(instanceVarName)); } return assertionLine; } else if (variableStackHandler.DoesVariableExist(returnedValueInstanceId)) { - return "// assertEquals(UNKNOWN_DATA_VALUE, getToXml(%s));" - .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)); + return String.format("// %s", generateAssertEquals("UNKNOWN_DATA_VALUE", "getToXml(%s)" + .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)))); } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { @@ -119,4 +119,12 @@ public static String traceToAssert(Trace methodTrace, VariableStackHandler varia return null; } + + private static String generateAssertEquals(String expected, String actual) { + return "assertEquals(%s, %s);".formatted(expected, actual); + } + + private static String generateAssertArrayEquals(String expected, String actual) { + return "assertArrayEquals(%s, %s);".formatted(expected, actual); + } } \ No newline at end of file From 71b505d2e34a9b9a6fca76587628bafed4da1cb8 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 12 Jul 2024 10:03:12 +0200 Subject: [PATCH 177/244] more cleanup --- .../gilesi/testgenerator/StaticConfiguration.java | 2 +- .../gilesi/testgenerator/review/AssertionUtils.java | 10 ++++++++-- .../testgenerator/review/SerializationUtils.java | 7 +------ 3 files changed, 10 insertions(+), 9 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java index 34d69317..616ce9c0 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java @@ -6,5 +6,5 @@ public class StaticConfiguration { public static final String GENERATED_CLASS_NAME = "GilesiGeneratedTestClass"; public static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; - public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = false; + public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = true; } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 9f081e28..018d30b3 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -86,8 +86,14 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue return assertionLine; } else if (variableStackHandler.DoesVariableExist(returnedValueInstanceId)) { - return String.format("// %s", generateAssertEquals("UNKNOWN_DATA_VALUE", "getToXml(%s)" - .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)))); + if (useAltAssertionMode) { + // TODO: array + return String.format("// %s", generateAssertEquals("getFromXml<>(\"UNKNOWN_DATA_VALUE\")", + VariableStackHandler.getVariableName(returnedValueInstanceId))); + } else { + return String.format("// %s", generateAssertEquals("UNKNOWN_DATA_VALUE", "getToXml(%s)" + .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)))); + } } else if (failOnLambdas) { throw new SerializationException("We cannot serialize this!"); } else { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index f8c44ee9..fa68105a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -27,12 +27,7 @@ public static String serializableDataToJava(InstanceReference serializableData, !FQN.equals("java.lang.String")) { String valueAsCode = generateStringJavaLine(serializableData.getValueAsXmlString()); - - // Casting is not needed if we only use this with variable assignments that are - // strictly typed - // valueToBeEqualTo = "(%s) (getFromXml(\"%s\"))".formatted(FQN, - // StringEscapeUtils.escapeJava(serializableData.getValueAsXmlString())); - valueToBeEqualTo = "getFromXml(%s)".formatted(valueAsCode); + valueToBeEqualTo = "getFromXml<%s>(%s)".formatted(FQN, valueAsCode); } else { int start = valueToBeEqualTo.indexOf(">"); int end = valueToBeEqualTo.lastIndexOf(" Date: Fri, 12 Jul 2024 11:11:50 +0200 Subject: [PATCH 178/244] get ready for experimentation --- .../src/main/java/com/github/gilesi/testgenerator/Main.java | 6 ++++-- .../github/gilesi/testgenerator/StaticConfiguration.java | 2 +- .../java/com/github/gilesi/testgenerator/TraceUtils.java | 2 +- .../github/gilesi/testgenerator/review/AssertionUtils.java | 2 +- .../gilesi/testgenerator/review/SerializationUtils.java | 2 +- 5 files changed, 8 insertions(+), 6 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index b8a231f2..fcd40b36 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -23,6 +23,8 @@ private static void processArguments(String[] args) throws IOException { return; } + Files.createDirectories(Path.of(testPath)); + if (!Files.exists(Path.of(testPath)) || !Files.isDirectory(Path.of(testPath))) { System.out.println( "Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); @@ -39,8 +41,8 @@ private static void processArguments(String[] args) throws IOException { } public static void main(String[] args) throws IOException { - args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", - "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + //args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", + // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; //args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", // "/home/gus/Git/gilesi/Results/generated/tests" }; diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java index 616ce9c0..34d69317 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java @@ -6,5 +6,5 @@ public class StaticConfiguration { public static final String GENERATED_CLASS_NAME = "GilesiGeneratedTestClass"; public static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; - public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = true; + public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = false; } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 8448bd3c..0f8cbc7e 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -120,7 +120,7 @@ private static void handleMethod(int traceId, String returnType = DescriptorUtils.getCleanedVar( DescriptorUtils.getCleanedType( - returnData.getClassReference().getFullyQualifiedTypeName())); + trace.getMethodReference().getReturnType().getFullyQualifiedTypeName())); returnVariableName = String.format("%s %s", returnType, returnVariableName); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 018d30b3..cd7f10d8 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -88,7 +88,7 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue } else if (variableStackHandler.DoesVariableExist(returnedValueInstanceId)) { if (useAltAssertionMode) { // TODO: array - return String.format("// %s", generateAssertEquals("getFromXml<>(\"UNKNOWN_DATA_VALUE\")", + return String.format("// %s", generateAssertEquals("getFromXml(\"UNKNOWN_DATA_VALUE\")", VariableStackHandler.getVariableName(returnedValueInstanceId))); } else { return String.format("// %s", generateAssertEquals("UNKNOWN_DATA_VALUE", "getToXml(%s)" diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index fa68105a..ca13cec5 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -27,7 +27,7 @@ public static String serializableDataToJava(InstanceReference serializableData, !FQN.equals("java.lang.String")) { String valueAsCode = generateStringJavaLine(serializableData.getValueAsXmlString()); - valueToBeEqualTo = "getFromXml<%s>(%s)".formatted(FQN, valueAsCode); + valueToBeEqualTo = "getFromXml(%s)".formatted(valueAsCode); } else { int start = valueToBeEqualTo.indexOf(">"); int end = valueToBeEqualTo.lastIndexOf(" Date: Fri, 12 Jul 2024 11:21:43 +0200 Subject: [PATCH 179/244] temporarily restrict functionality for debugging purposes --- .../github/gilesi/maestro/compsuite/CompSuite.java | 12 ++++++------ .../testgenerator/review/SerializationUtils.java | 6 ++++-- 2 files changed, 10 insertions(+), 8 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index addd44b6..dd34ff9d 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -131,14 +131,14 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } } - String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); - if (javaToolOptions == null) { - continue; - } + //String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + //if (javaToolOptions == null) { + // continue; + //} - Main.logger.info("Testing old project"); + //Main.logger.info("Testing old project"); TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); - ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + //ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger, runResult); runResults.add(runResult); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index ca13cec5..5e519432 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -67,7 +67,7 @@ public static String generateStringJavaLine(String stringContent) { int maxStringSize = 1024; if (valueAsCode.length() > maxStringSize) { - List sectionList = new ArrayList<>(); + /*List sectionList = new ArrayList<>(); for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { int end2 = start2 + maxStringSize; @@ -81,7 +81,9 @@ public static String generateStringJavaLine(String stringContent) { sectionList.add(readyToUseSection); } - valueAsCode = String.join(" + ", sectionList.toArray(String[]::new)); + valueAsCode = String.join(" + ", sectionList.toArray(String[]::new));*/ + + valueAsCode = "\"SNIP!\""; } return valueAsCode; From 7235b1a33bc05cc1b0b06d655c505eeb8aca8718 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Fri, 12 Jul 2024 11:57:21 +0200 Subject: [PATCH 180/244] Start rewriting argument utils --- .../testgenerator/review/ArgumentUtils.java | 139 ++++++++---------- .../testgenerator/review/AssertionUtils.java | 26 +++- 2 files changed, 89 insertions(+), 76 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index e768904d..04196a9a 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -8,62 +8,14 @@ import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.DescriptorUtils; import com.github.gilesi.testgenerator.VariableStackHandler; -import com.github.gilesi.testgenerator.exceptions.SerializationException; public class ArgumentUtils { - public static String serializableDataToCode(InstanceReference instanceReference, ClassReference classReference, - VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { - if (instanceReference.getValueAsXmlString() != null) { - if (instanceReference.getIsNull()) { - return "null"; - } - - String dataLine = SerializationUtils.serializableDataToJava(instanceReference, classReference); - - if (failOnLambdas - && instanceReference.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); - } - - return dataLine; - } else if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { - return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); - } else if (failOnLambdas) { - throw new SerializationException("We cannot serialize this!"); - } else { - return "// Unserializable data with instance id: " + instanceReference.getInstanceId(); - } - } - - private static String getDataVariableDeclaration(InstanceReference instanceReference, - VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { - if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { - return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); - } else { - String returnType = DescriptorUtils - .getCleanedType(instanceReference.getClassReference().getFullyQualifiedTypeName()); - if (failOnLambdas && returnType.contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); - } - - returnType = DescriptorUtils.getCleanedVar(returnType); - - variableStackHandler.CreateNewVariable(instanceReference.getInstanceId()); - String instanceVariableName = VariableStackHandler.getVariableName(instanceReference.getInstanceId()); - // if (serializableData.getValueAsXmlString() == null || - // serializableData.getValueAsXmlString().equals("null")) { - return "%s %s".formatted(returnType, instanceVariableName); - // } - // return "%s %s".formatted("var", instanceVariableName); - } - } + public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHandler variableStackHandler) { + boolean Succeeded = true; - public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHandler variableStackHandler) - throws SerializationException { + List variableDeclarationList = new ArrayList<>(); List preCallArguments = new ArrayList<>(); - List variableList = new ArrayList<>(); - - boolean commentItAll = false; + List preCallCommitedVariables = new ArrayList<>(); for (int i = 0; i < trace.getPreCallArguments().size(); i++) { InstanceReference preCallArgument = trace.getPreCallArguments().get(i); @@ -75,40 +27,77 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa ClassReference correspondingMethodArg = trace.getMethodReference().getParameterTypes()[i]; - String argumentValue; - try { - argumentValue = serializableDataToCode(preCallArgument, correspondingMethodArg, variableStackHandler, - true); - } catch (SerializationException e) { - argumentValue = serializableDataToCode(preCallArgument, correspondingMethodArg, variableStackHandler, - false); - commentItAll = true; - } - String argumentVariable = null; - try { - argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler, true); - } catch (SerializationException e) { - try { - argumentVariable = getDataVariableDeclaration(preCallArgument, variableStackHandler, false); - } catch (SerializationException ex) { + // Has to be defined already so no need to check here + preCallArguments.add(VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + + String argumentVariable = ""; + // It is possible for us to use the exact sane instance twice during the call to this method + // Therefore, also keep a list of variables we define temporarily given we commit this only at the end of this routine. + Integer instanceIdForArgument = preCallArgument.getInstanceId(); + boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument) || preCallCommitedVariables.contains(instanceIdForArgument); + if (variableAlreadyComitted) { + argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); + } else { + // We do not handle lambdas currently, so fail here. + if (preCallArgument.getClassReference().getFullyQualifiedTypeName().contains("Lambda/")) { + Succeeded = false; + } else { + // Variable does not exist yet, commit to it later + preCallCommitedVariables.add(instanceIdForArgument); } - commentItAll = true; - // todo: problem here... + + String returnType = DescriptorUtils.getCleanedVar(DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName())); + argumentVariable = String.format("%s %s", returnType, VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); } - String argumentDeclaration = "%s = %s".formatted(argumentVariable, argumentValue); - // Has to be defined already so no need to check here - preCallArguments.add(VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + String argumentValue = ""; + if (preCallArgument.getValueAsXmlString() != null && !preCallArgument.getValueAsXmlString().isEmpty()) { + try { + argumentValue = SerializationUtils.serializableDataToJava(preCallArgument, correspondingMethodArg); + } catch (Exception ignored) { + // fail... + // We do not have a value we can deal with, see if it already exists to use this instead. + if (variableAlreadyComitted) { + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); // This is a bit redundant as we will write var1 = var1, fix later, purely cosmetic. + } else { + // We cant do much, fail. + argumentValue = "\"%s\"".formatted(preCallArgument.getValueAsXmlString()); + Succeeded = false; + } + } + } else { + // We do not have a value we can deal with, see if it already exists to use this instead. + if (variableAlreadyComitted) { + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); // This is a bit redundant as we will write var1 = var1, fix later, purely cosmetic. + } else { + // We cant do much, fail. + argumentValue = "\"UNKNOWN_DATA_VALUE\""; + Succeeded = false; + } + } + // Define the variable before the method - variableList.add("%s;".formatted(argumentDeclaration)); + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } + + String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); + + // If the generation above succeeded then create the variables on the stack but not otherwise + // as we would skip defining those variables and we would get further issues down the line. + if (Succeeded) { + for (InstanceReference preCallArgument : trace.getPreCallArguments()) { + if (variableStackHandler.DoesVariableExist(preCallArgument.getInstanceId())) { + variableStackHandler.CreateNewVariable(preCallArgument.getInstanceId()); + } + } } // Return if we succeeded, the list of stuff to pass as method arguments, and // the list of variable declarations to add if any - return new ArgLineGenerateResult(!commentItAll, String.join(", ", preCallArguments), variableList); + return new ArgLineGenerateResult(Succeeded, formattedArgumentsForUseInMethodCall, variableDeclarationList); } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index cd7f10d8..5f0c1e69 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -11,6 +11,30 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class AssertionUtils { + public static String serializableDataToCode(InstanceReference instanceReference, ClassReference classReference, + VariableStackHandler variableStackHandler, boolean failOnLambdas) throws SerializationException { + if (instanceReference.getValueAsXmlString() != null) { + if (instanceReference.getIsNull()) { + return "null"; + } + + String dataLine = SerializationUtils.serializableDataToJava(instanceReference, classReference); + + if (failOnLambdas + && instanceReference.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { + throw new SerializationException("We cannot handle lamdas at the moment!"); + } + + return dataLine; + } else if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { + return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); + } else if (failOnLambdas) { + throw new SerializationException("We cannot serialize this!"); + } else { + return "// Unserializable data with instance id: " + instanceReference.getInstanceId(); + } + } + public static List traceArgumentsToAssert(Trace methodTrace, VariableStackHandler variableStackHandler) throws SerializationException { List argList = new ArrayList<>(); @@ -71,7 +95,7 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue String assertionLine; if (useAltAssertionMode) { - String valueAsCode = ArgumentUtils.serializableDataToCode(returnedValueInstance, + String valueAsCode = serializableDataToCode(returnedValueInstance, returnClassReference, variableStackHandler, true); if (valueAsCode.endsWith("[].class)")) { From e2a6c511a1074a7721898eb857a4275a9f328815 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 15 Jul 2024 10:20:11 +0200 Subject: [PATCH 181/244] Improvements --- .../runners/maven/ProjectRunner.java | 2 +- .../java/com/github/gilesi/confgen/Main.java | 7 ++- .../models/InstrumentationParameters.java | 1 + .../confgen/spoon/SpoonLauncherUtilities.java | 3 +- .../models/InstrumentationParameters.java | 1 + .../models/InstanceReference.java | 2 +- .../github/gilesi/maestro/Orchestrator.java | 2 +- .../gilesi/maestro/compsuite/CompSuite.java | 7 ++- .../maestro/runners/maven/ProjectRunner.java | 27 +++++++--- .../maestro/testing/gradle/GradleHarness.java | 9 ++-- .../github/gilesi/maestro/tools/TestGen.java | 5 +- .../github/gilesi/confgen/models/Class.java | 7 +++ .../models/InstrumentationParameters.java | 7 +++ .../github/gilesi/confgen/models/Method.java | 6 +++ .../instrumentation/ConfigurationReader.java | 12 +++++ .../gilesi/instrumentation/XmlUtils.java | 51 +++++++++++++++++++ .../gilesi/testgenerator/ClassUtils.java | 3 +- .../gilesi/testgenerator/DescriptorUtils.java | 5 +- .../com/github/gilesi/testgenerator/Main.java | 36 +++++++++++-- .../testgenerator/review/ArgumentUtils.java | 46 ++++++++++------- .../testgenerator/review/AssertionUtils.java | 10 +++- 21 files changed, 204 insertions(+), 45 deletions(-) create mode 100644 TestGenerator/src/main/java/com/github/gilesi/confgen/models/Class.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/confgen/models/Method.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java create mode 100644 TestGenerator/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java diff --git a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java index b91e8855..d7de0574 100644 --- a/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java +++ b/CompSuiteHarness/src/main/java/com/github/gilesi/harness/compsuite/runners/maven/ProjectRunner.java @@ -40,7 +40,7 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List(); + instrumentationParameters.LibraryTypes = new ArrayList<>(); instrumentationParameters.traceOutputLocation = traceOutputLocation; for (ClassDecl classDecl : libraryApiModel.getExportedTypes() @@ -163,13 +164,17 @@ public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeExcept } } + for (TypeDecl typeDecl : libraryApiModel.getExportedTypes().toList()) { + instrumentationParameters.LibraryTypes.add(typeDecl.getQualifiedName()); + } + BufferedWriter bufferedWriter = Files.newBufferedWriter(apiReportOutputPath, StandardOpenOption.CREATE); try { String serializedJsonString = objectMapper.writeValueAsString(instrumentationParameters); bufferedWriter.write(serializedJsonString); } catch (Exception e) { - System.out.println("ERROR: Cannot serialize specific argument: " + e); + System.out.println(String.format("ERROR: Cannot serialize specific argument: %s", e)); } bufferedWriter.close(); diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java index 1c3412c5..351419b2 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -4,5 +4,6 @@ public class InstrumentationParameters { public List InstrumentedAPIClasses; + public List LibraryTypes; public String traceOutputLocation; } diff --git a/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java b/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java index f7aeff3f..41cb0d0b 100644 --- a/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java +++ b/ConfGen/src/main/java/com/github/gilesi/confgen/spoon/SpoonLauncherUtilities.java @@ -94,7 +94,7 @@ public static int getProjectSourceComplianceLevel(Path location) { try { return getPomProjectSourceComplianceLevel(location.toAbsolutePath().toString()); } catch (Exception ignore) { - + System.out.println("Unable to get project source compliance level. %s".formatted(ignore)); } return 11; @@ -181,6 +181,7 @@ public static Collection getProjectPaths(Path projectLocation, EnumSet pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, Object logger, String javaToolOptions) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, Object logger, String javaToolOptions) + throws MavenInvocationException { String javaVersion = "8"; @@ -43,15 +45,21 @@ public static int runPomGoals(String pomFilePath, List pomGoals, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) + throws MavenInvocationException { String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); - return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, javaVersion, logger, javaToolOptions); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, + javaVersion, logger, javaToolOptions); } - public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger, + String javaToolOptions) throws MavenInvocationException { File pomFile = new File(pomFilePath); InvokerLogger invokerLogger = null; @@ -116,16 +124,19 @@ public static int runPomGoalsInternal(String pomFilePath, List pomGoals, return result.getExitCode(); } - public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, + String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); ArrayList goals = new ArrayList<>(); goals.add(goal); if (javaVersion != null && !javaVersion.isBlank()) { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger, javaToolOptions) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger, + javaToolOptions) == 0; } else { - return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger, javaToolOptions) == 0; + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger, + javaToolOptions) == 0; } } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java b/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java index c85173d1..aca3abf2 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/testing/gradle/GradleHarness.java @@ -14,8 +14,10 @@ import java.util.ArrayList; public class GradleHarness { - private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { - String sureFireReportsLocation = "%s%stest-results%stest".formatted(targetLocation, File.separator, File.separator); + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, + ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%stest-results%stest".formatted(targetLocation, File.separator, + File.separator); ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); for (String xml : reportXmls) { @@ -30,7 +32,8 @@ private static void buildReportXml(String projectName, String projectCommit, Str } } - public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, String buildGradleFileLocation) { + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, + String buildGradleFileLocation) { ArrayList reportItems = new ArrayList<>(); Path buildGradleFilePath = Path.of(buildGradleFileLocation); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java b/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java index f43526c0..06530096 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/tools/TestGen.java @@ -10,13 +10,14 @@ public class TestGen { public static final Logger logger = LogManager.getLogger(); - public static void runTestGen(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory) throws IOException, InterruptedException { + public static void runTestGen(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory, String libraryConfig) throws IOException, InterruptedException { ProcessUtils.runExternalCommand(new String[]{ "%s/bin/java".formatted(Constants.JAVA_21_BINARY_LOCATION), "-jar", "%s%s".formatted(GilesiRepositoryLocation, Constants.TEST_GEN_LOCATION), traceFile, - outputCodeDirectory + outputCodeDirectory, + libraryConfig }, null, logger); } } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Class.java b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Class.java new file mode 100644 index 00000000..d8e63389 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Class.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgen.models; + +public class Class { + public String ClassName; + public Method[] ClassMethods; + public String[] ClassDescriptors; +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java new file mode 100644 index 00000000..2fa9ceac --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgen.models; + +public class InstrumentationParameters { + public Class[] InstrumentedAPIClasses; + public String[] LibraryTypes; + public String traceOutputLocation; +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Method.java b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Method.java new file mode 100644 index 00000000..8ef6c1e1 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/confgen/models/Method.java @@ -0,0 +1,6 @@ +package com.github.gilesi.confgen.models; + +public class Method { + public String MethodName; + public String[] MethodDescriptors; +} \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java new file mode 100644 index 00000000..27f4c5ae --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java @@ -0,0 +1,12 @@ +package com.github.gilesi.instrumentation; + +import com.github.gilesi.confgen.models.InstrumentationParameters; + +import java.io.File; +import java.io.IOException; + +public class ConfigurationReader { + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { + return XmlUtils.objectMapper.readValue(file, InstrumentationParameters.class); + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java new file mode 100644 index 00000000..3b46a7f2 --- /dev/null +++ b/TestGenerator/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java @@ -0,0 +1,51 @@ +package com.github.gilesi.instrumentation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class XmlUtils { + private static DomDriver domDriver = new DomDriver(); + private static XStream xStream = new XStream(domDriver); + private static Object syncObj = new Object(); + public static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + public static String getToXml(Object obj) { + return xStream.toXML(obj); + } + + public static String getToJson(Object obj) throws JsonProcessingException { + return objectMapper.writeValueAsString(obj); + } + + public static void saveToUniquePath(String basePath, String baseName, String baseExtension, String content) { + synchronized (syncObj) { + int padding = 1; + String finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, padding, baseExtension); + + while (Files.exists(Paths.get(finalFileName))) { + finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, ++padding, baseExtension); + } + + try { + FileWriter outputFile = new FileWriter(finalFileName); + outputFile.write(content); + outputFile.close(); + } catch (Throwable e) { + System.err.println("ERROR"); + e.printStackTrace(); + } + } + } +} diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java index e37d953c..2f4f8c86 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/ClassUtils.java @@ -53,7 +53,8 @@ public static void generateClassFile(ArrayList methodTraces, String testP stringBuilder.append("public class %s {\n".formatted(StaticConfiguration.GENERATED_CLASS_NAME)); stringBuilder.append("\t@Test\n"); - stringBuilder.append("\tpublic void %s() throws Throwable {\n".formatted(StaticConfiguration.GENERATED_TEST_NAME)); + stringBuilder + .append("\tpublic void %s() throws Throwable {\n".formatted(StaticConfiguration.GENERATED_TEST_NAME)); VariableStackHandler variableStackHandler = new VariableStackHandler(); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java index f13d2069..b7c14386 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/DescriptorUtils.java @@ -42,8 +42,9 @@ public static String getCleanedType(String FQN) { (currentCharacter == 'L' && FQN.endsWith(";"))) { try { return JvmTypeToLangType(FQN).replace("$", "."); - } catch (UnsupportedJavaPrimitiveTypeException ignored) { - + } catch (UnsupportedJavaPrimitiveTypeException e) { + System.out.println(String.format("Unsupported Java Primitive Type Exception! %c", currentCharacter)); + e.printStackTrace(); } } return FQN.replace("$", "."); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java index fcd40b36..d35a005f 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/Main.java @@ -1,21 +1,27 @@ package com.github.gilesi.testgenerator; +import com.github.gilesi.confgen.models.InstrumentationParameters; +import com.github.gilesi.instrumentation.ConfigurationReader; import com.github.gilesi.instrumentation.models.Trace; +import java.io.File; import java.io.IOException; import java.nio.file.Files; import java.nio.file.Path; import java.util.*; public class Main { + public static InstrumentationParameters instrumentationParameters; + private static void processArguments(String[] args) throws IOException { - if (args.length != 2) { - System.out.println("Usage: "); + if (args.length != 3) { + System.out.println("Usage: "); return; } String traceXmlFolder = args[0]; String testPath = args[1]; + String libraryConfigPath = args[2]; if (!Files.exists(Path.of(traceXmlFolder)) || !Files.isDirectory(Path.of(traceXmlFolder))) { System.out.println( @@ -31,18 +37,40 @@ private static void processArguments(String[] args) throws IOException { return; } + if (!Files.exists(Path.of(libraryConfigPath)) || Files.isDirectory(Path.of(libraryConfigPath))) { + System.out.println( + "Argument 3 is not a path to a library configuration. It either does not exist or is not a file."); + return; + } + ArrayList methodTraces = TraceReader.readTraces(traceXmlFolder); if (methodTraces.isEmpty()) { System.out.println("No traces found!"); } + // Get the parameters + File configurationFile = new File(libraryConfigPath); + if (!configurationFile.exists()) { + System.err.printf("ERROR: the passed in configuration file (%s) does not exist or could not be found!%n", libraryConfigPath); + return; + } + + try { + instrumentationParameters = ConfigurationReader.parseInstrumentationparameters(configurationFile); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not parse instrumentation configuration file (%s)!%n", libraryConfigPath); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + ClassUtils.generateClassFile(methodTraces, testPath); } public static void main(String[] args) throws IOException { - //args = new String[] {"/home/gus/Datasets/compsuite3/i-3/generated/traces", - // "/home/gus/Datasets/compsuite3/i-3/generated/tests2"}; + // args = new String[] {"/home/gus/Datasets/compsuite3/i-2/generated/traces", + // "/home/gus/Datasets/compsuite3/i-2/generated/tests2"}; //args = new String[] { "/home/gus/Git/gilesi/Results/generated/traces", // "/home/gus/Git/gilesi/Results/generated/tests" }; diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 04196a9a..012c2800 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -27,16 +27,17 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa ClassReference correspondingMethodArg = trace.getMethodReference().getParameterTypes()[i]; - // Has to be defined already so no need to check here preCallArguments.add(VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); - String argumentVariable = ""; - // It is possible for us to use the exact sane instance twice during the call to this method - // Therefore, also keep a list of variables we define temporarily given we commit this only at the end of this routine. + // It is possible for us to use the exact sane instance twice during the call to + // this method + // Therefore, also keep a list of variables we define temporarily given we + // commit this only at the end of this routine. Integer instanceIdForArgument = preCallArgument.getInstanceId(); - boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument) || preCallCommitedVariables.contains(instanceIdForArgument); + boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument) + || preCallCommitedVariables.contains(instanceIdForArgument); if (variableAlreadyComitted) { argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { @@ -48,20 +49,27 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa preCallCommitedVariables.add(instanceIdForArgument); } - String returnType = DescriptorUtils.getCleanedVar(DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName())); - argumentVariable = String.format("%s %s", returnType, VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); - } + String cleanedType = DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(cleanedType); + argumentVariable = String.format("%s %s", returnType, + VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + } String argumentValue = ""; if (preCallArgument.getValueAsXmlString() != null && !preCallArgument.getValueAsXmlString().isEmpty()) { try { argumentValue = SerializationUtils.serializableDataToJava(preCallArgument, correspondingMethodArg); - } catch (Exception ignored) { + } catch (Exception e) { + System.out.println("Unable to generate code for serializing data to java!"); + e.printStackTrace(); // fail... - // We do not have a value we can deal with, see if it already exists to use this instead. + // We do not have a value we can deal with, see if it already exists to use this + // instead. if (variableAlreadyComitted) { - argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); // This is a bit redundant as we will write var1 = var1, fix later, purely cosmetic. + // This is a bit redundant as we will write var1 = var1, fix later, purely + // cosmetic. + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { // We cant do much, fail. argumentValue = "\"%s\"".formatted(preCallArgument.getValueAsXmlString()); @@ -69,9 +77,12 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa } } } else { - // We do not have a value we can deal with, see if it already exists to use this instead. + // We do not have a value we can deal with, see if it already exists to use this + // instead. if (variableAlreadyComitted) { - argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); // This is a bit redundant as we will write var1 = var1, fix later, purely cosmetic. + // This is a bit redundant as we will write var1 = var1, fix later, purely + // cosmetic. + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { // We cant do much, fail. argumentValue = "\"UNKNOWN_DATA_VALUE\""; @@ -79,18 +90,19 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa } } - // Define the variable before the method variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); } String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); - // If the generation above succeeded then create the variables on the stack but not otherwise - // as we would skip defining those variables and we would get further issues down the line. + // If the generation above succeeded then create the variables on the stack but + // not otherwise + // as we would skip defining those variables and we would get further issues + // down the line. if (Succeeded) { for (InstanceReference preCallArgument : trace.getPreCallArguments()) { - if (variableStackHandler.DoesVariableExist(preCallArgument.getInstanceId())) { + if (!variableStackHandler.DoesVariableExist(preCallArgument.getInstanceId())) { variableStackHandler.CreateNewVariable(preCallArgument.getInstanceId()); } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 5f0c1e69..9f0771c7 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -22,14 +22,14 @@ public static String serializableDataToCode(InstanceReference instanceReference, if (failOnLambdas && instanceReference.getClassReference().getFullyQualifiedTypeName().contains("..Lambda/")) { - throw new SerializationException("We cannot handle lamdas at the moment!"); + throw new SerializationException(String.format("We cannot handle lamdas at the moment! %d %s", instanceReference.getInstanceId(), instanceReference.getClassReference().getFullyQualifiedTypeName())); } return dataLine; } else if (variableStackHandler.DoesVariableExist(instanceReference.getInstanceId())) { return VariableStackHandler.getVariableName(instanceReference.getInstanceId()); } else if (failOnLambdas) { - throw new SerializationException("We cannot serialize this!"); + throw new SerializationException(String.format("We cannot serialize this! %d %s", instanceReference.getInstanceId(), instanceReference.getClassReference().getFullyQualifiedTypeName())); } else { return "// Unserializable data with instance id: " + instanceReference.getInstanceId(); } @@ -63,6 +63,9 @@ public static List traceArgumentsToAssert(Trace methodTrace, VariableSta variableStackHandler, true, StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { + System.out.println("Unable to generate code for serializing data to java!"); + e.printStackTrace(); + assertionCodeLine = "// %s".formatted(getReturnAssertionCodeLine(postCallArgument, correspondingMethodArg, variableStackHandler, false, StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE)); @@ -139,6 +142,9 @@ public static String traceToAssert(Trace methodTrace, VariableStackHandler varia methodTrace.getMethodReference().getReturnType(), variableStackHandler, true, StaticConfiguration.USE_ALTERNATIVE_ASSERTION_MODE); } catch (SerializationException e) { + System.out.println("Unable to generate code for serializing data to java!"); + e.printStackTrace(); + assertionCodeLine = "// %s" .formatted(getReturnAssertionCodeLine(traceData, methodTrace.getMethodReference().getReturnType(), variableStackHandler, false, From 3959848a954c0f0ad5fb5e54278faff49be3f0cf Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 15 Jul 2024 11:42:44 +0200 Subject: [PATCH 182/244] Some improvements --- .../gilesi/testgenerator/TraceUtils.java | 28 +++++++---- .../testgenerator/VariableStackHandler.java | 15 +++--- .../testgenerator/review/ArgumentUtils.java | 47 ++++++++++++++----- .../testgenerator/review/AssertionUtils.java | 2 +- .../review/SerializationUtils.java | 35 +++++++++++++- 5 files changed, 98 insertions(+), 29 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 0f8cbc7e..074c135f 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -2,11 +2,13 @@ import java.util.List; +import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.instrumentation.models.Trace; import com.github.gilesi.testgenerator.review.ArgLineGenerateResult; import com.github.gilesi.testgenerator.review.ArgumentUtils; import com.github.gilesi.testgenerator.review.AssertionUtils; +import com.github.gilesi.testgenerator.review.SerializationUtils; import com.github.gilesi.testgenerator.exceptions.SerializationException; public class TraceUtils { @@ -15,7 +17,7 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) throws SerializationException { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - variableStackHandler.CreateNewVariable(instanceData.getInstanceId()); + variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); instanceVariableName = String.format("%s %s", methodName, instanceVariableName); } @@ -77,7 +79,7 @@ private static void handleMethod(int traceId, // If true, we should not create new variables and we should comment out the // whole code. // As the code simply is not generable. - boolean issuesDetected = false; + boolean issuesDetected = !argLineResult.Success; if (isInstanceCall) { // When we have an instance dependent call, we need the instance the call is @@ -105,9 +107,20 @@ private static void handleMethod(int traceId, } if (returnData != null) { + //String rFQN = DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); + //String rReturnType = DescriptorUtils.getCleanedVar(rFQN); + + ClassReference compatibleClassReference = SerializationUtils.getCompatibleClassReference(returnData.getClassReference()); + if (compatibleClassReference == null) { + compatibleClassReference = trace.getMethodReference().getReturnType(); + } + + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { if (!issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.getInstanceId()); + variableStackHandler.CreateNewVariable(returnData.getInstanceId(), returnType); } else { String warnMessage = String.format( "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", @@ -118,15 +131,12 @@ private static void handleMethod(int traceId, stringBuilder.append(String.format("// %s\n", warnMessage)); } - String returnType = DescriptorUtils.getCleanedVar( - DescriptorUtils.getCleanedType( - trace.getMethodReference().getReturnType().getFullyQualifiedTypeName())); returnVariableName = String.format("%s %s", returnType, returnVariableName); } - String callLine = String.format("%s = %s(%s);\n", returnVariableName, methodName, argumentLine); + String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { + if (argLineResult.Success && !issuesDetected) { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("%s\n", str)); } @@ -161,7 +171,7 @@ private static void handleMethod(int traceId, } } else { String callLine = String.format("%s(%s);\n", methodName, argumentLine); - if (argLineResult.Success) { + if (argLineResult.Success && !issuesDetected) { for (String str : argLineResult.variableList) { callStringBuilder.append(String.format("%s\n", str)); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java index 5639022a..2d22578c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/VariableStackHandler.java @@ -1,22 +1,25 @@ package com.github.gilesi.testgenerator; -import java.util.ArrayList; -import java.util.List; +import java.util.HashMap; public class VariableStackHandler { - private List variableInstances = new ArrayList<>(); + private HashMap variableInstances = new HashMap<>(); - public void CreateNewVariable(int instanceId) { + public void CreateNewVariable(int instanceId, String variableType) { if (!DoesVariableExist(instanceId)) { - variableInstances.add(instanceId); + variableInstances.put(instanceId, variableType); } } public boolean DoesVariableExist(int instanceId) { - return variableInstances.contains(instanceId); + return variableInstances.containsKey(instanceId); } public static String getVariableName(int instanceId) { return String.format("var%d", instanceId); } + + public String getVariableType(int instanceId) { + return variableInstances.get(instanceId); + } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 012c2800..0cd43945 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -1,7 +1,9 @@ package com.github.gilesi.testgenerator.review; import java.util.ArrayList; +import java.util.HashMap; import java.util.List; +import java.util.Map.Entry; import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; @@ -15,7 +17,7 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa List variableDeclarationList = new ArrayList<>(); List preCallArguments = new ArrayList<>(); - List preCallCommitedVariables = new ArrayList<>(); + HashMap preCallCommitedVariables = new HashMap<>(); for (int i = 0; i < trace.getPreCallArguments().size(); i++) { InstanceReference preCallArgument = trace.getPreCallArguments().get(i); @@ -27,8 +29,11 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa ClassReference correspondingMethodArg = trace.getMethodReference().getParameterTypes()[i]; + String argFQN = DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName()); + String argReturnType = DescriptorUtils.getCleanedVar(argFQN); + // Has to be defined already so no need to check here - preCallArguments.add(VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + preCallArguments.add("(%s)%s".formatted(argReturnType, VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); String argumentVariable = ""; // It is possible for us to use the exact sane instance twice during the call to @@ -37,21 +42,26 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa // commit this only at the end of this routine. Integer instanceIdForArgument = preCallArgument.getInstanceId(); boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument) - || preCallCommitedVariables.contains(instanceIdForArgument); + || preCallCommitedVariables.containsKey(instanceIdForArgument); if (variableAlreadyComitted) { argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { + ClassReference compatibleClassReference = SerializationUtils.getCompatibleClassReference(preCallArgument.getClassReference()); + if (compatibleClassReference == null) { + compatibleClassReference = correspondingMethodArg; + } + + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + // We do not handle lambdas currently, so fail here. if (preCallArgument.getClassReference().getFullyQualifiedTypeName().contains("Lambda/")) { Succeeded = false; } else { // Variable does not exist yet, commit to it later - preCallCommitedVariables.add(instanceIdForArgument); + preCallCommitedVariables.put(instanceIdForArgument, returnType); } - String cleanedType = DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName()); - String returnType = DescriptorUtils.getCleanedVar(cleanedType); - argumentVariable = String.format("%s %s", returnType, VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); } @@ -90,8 +100,21 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa } } - // Define the variable before the method - variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + if (variableAlreadyComitted) { + String definedType = ""; + + if (variableStackHandler.DoesVariableExist(instanceIdForArgument)) { + definedType = variableStackHandler.getVariableType(instanceIdForArgument); + } else { + definedType = preCallCommitedVariables.get(instanceIdForArgument); + } + + // Define the variable before the method + variableDeclarationList.add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } else { + // Define the variable before the method + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } } String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); @@ -101,9 +124,9 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa // as we would skip defining those variables and we would get further issues // down the line. if (Succeeded) { - for (InstanceReference preCallArgument : trace.getPreCallArguments()) { - if (!variableStackHandler.DoesVariableExist(preCallArgument.getInstanceId())) { - variableStackHandler.CreateNewVariable(preCallArgument.getInstanceId()); + for (Entry preCallArgument : preCallCommitedVariables.entrySet()) { + if (!variableStackHandler.DoesVariableExist(preCallArgument.getKey())) { + variableStackHandler.CreateNewVariable(preCallArgument.getKey(), preCallArgument.getValue()); } } } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java index 9f0771c7..fb0e0db5 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/AssertionUtils.java @@ -122,7 +122,7 @@ private static String getReturnAssertionCodeLine(InstanceReference returnedValue .formatted(VariableStackHandler.getVariableName(returnedValueInstanceId)))); } } else if (failOnLambdas) { - throw new SerializationException("We cannot serialize this!"); + throw new SerializationException(String.format("We cannot serialize this! %d %s", returnedValueInstance.getInstanceId(), returnedValueInstance.getClassReference().getFullyQualifiedTypeName())); } else { return "// Unserializable data with instance id: %d".formatted(returnedValueInstance.getInstanceId()); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index 5e519432..180e0742 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -3,6 +3,7 @@ import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.DescriptorUtils; +import com.github.gilesi.testgenerator.Main; import com.github.gilesi.testgenerator.exceptions.SerializationException; import org.apache.commons.text.StringEscapeUtils; @@ -10,10 +11,42 @@ import java.util.List; public class SerializationUtils { + public static ClassReference getCompatibleClassReference(ClassReference classReference) { + String[] libraryTypes = Main.instrumentationParameters.LibraryTypes; + + for (String libraryType : libraryTypes) { + if (classReference.getFullyQualifiedTypeName().equals(libraryType)) { + return classReference; + } + } + + if (classReference.getSuperClass() != null) { + ClassReference compatibleClassReference = getCompatibleClassReference(classReference.getSuperClass()); + if (compatibleClassReference != null) { + return compatibleClassReference; + } + } + + for (ClassReference interfaceClassReference : classReference.getInterfaces()) { + ClassReference compatibleClassReference = getCompatibleClassReference(interfaceClassReference); + if (compatibleClassReference != null) { + return compatibleClassReference; + } + } + + return null; + } + public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) throws SerializationException { String valueToBeEqualTo = serializableData.getValueAsXmlString(); - String FQN = DescriptorUtils.getCleanedType(argClass.getFullyQualifiedTypeName()); + + ClassReference compatibleClassReference = getCompatibleClassReference(serializableData.getClassReference()); + if (compatibleClassReference == null) { + compatibleClassReference = argClass; + } + + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && !FQN.equals("java.lang.Void") && From 799499233d285dca5e4cba6f63648fc34057694b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 15 Jul 2024 14:45:06 +0200 Subject: [PATCH 183/244] Fixes --- .../gilesi/testgenerator/TraceUtils.java | 33 +++++++++------ .../testgenerator/review/ArgumentUtils.java | 40 ++++++++++++++----- .../review/SerializationUtils.java | 31 +++++++++++--- 3 files changed, 77 insertions(+), 27 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 074c135f..c49d924e 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -42,7 +42,11 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, } } else { for (String str : argLineResult.variableList) { - stringBuilder.append(String.format("// %s\n", str)); + if (argLineResult.Success) { + stringBuilder.append(String.format("%s\n", str)); + } else { + stringBuilder.append(String.format("// %s\n", str)); + } } stringBuilder.append(String.format("// %s", callLine)); @@ -110,11 +114,7 @@ private static void handleMethod(int traceId, //String rFQN = DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); //String rReturnType = DescriptorUtils.getCleanedVar(rFQN); - ClassReference compatibleClassReference = SerializationUtils.getCompatibleClassReference(returnData.getClassReference()); - if (compatibleClassReference == null) { - compatibleClassReference = trace.getMethodReference().getReturnType(); - } - + ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), trace.getMethodReference().getReturnType()); String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); String returnType = DescriptorUtils.getCleanedVar(FQN); @@ -134,6 +134,7 @@ private static void handleMethod(int traceId, returnVariableName = String.format("%s %s", returnType, returnVariableName); } + // TODO: check if type equals "var" here which would be a terrible mistake. String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (argLineResult.Success && !issuesDetected) { @@ -154,7 +155,11 @@ private static void handleMethod(int traceId, } } else { for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); + if (argLineResult.Success) { + callStringBuilder.append(String.format("%s\n", str)); + } else { + callStringBuilder.append(String.format("// %s\n", str)); + } } callStringBuilder.append(String.format("// %s", callLine)); @@ -185,7 +190,11 @@ private static void handleMethod(int traceId, } } else { for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("// %s\n", str)); + if (argLineResult.Success) { + callStringBuilder.append(String.format("%s\n", str)); + } else { + callStringBuilder.append(String.format("// %s\n", str)); + } } callStringBuilder.append(String.format("// %s", callLine)); @@ -199,11 +208,11 @@ private static void handleMethod(int traceId, } // Append the method call to the current string builder. - if (issuesDetected) { - stringBuilder.append(String.format("// %s", callStringBuilder.toString())); - } else { + //if (issuesDetected) { + // stringBuilder.append(String.format("// %s", callStringBuilder.toString())); + //} else { stringBuilder.append(callStringBuilder.toString()); - } + //} } public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 0cd43945..d7e2d260 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -32,8 +32,18 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa String argFQN = DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName()); String argReturnType = DescriptorUtils.getCleanedVar(argFQN); + // TODO: check if type equals "var" here which would be a terrible mistake. // Has to be defined already so no need to check here - preCallArguments.add("(%s)%s".formatted(argReturnType, VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); + if (!argReturnType.equals("var")) { + preCallArguments.add("(%s)%s".formatted(argReturnType, + VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); + } else { + System.out.println(String.format( + "WARNING: Unable to get a proper type for agument in method. This should NEVER happen! %d", + preCallArgument.getInstanceId())); + preCallArguments + .add("%s".formatted(VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); + } String argumentVariable = ""; // It is possible for us to use the exact sane instance twice during the call to @@ -46,14 +56,11 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa if (variableAlreadyComitted) { argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { - ClassReference compatibleClassReference = SerializationUtils.getCompatibleClassReference(preCallArgument.getClassReference()); - if (compatibleClassReference == null) { - compatibleClassReference = correspondingMethodArg; - } - + ClassReference compatibleClassReference = SerializationUtils + .getBetterType(preCallArgument.getClassReference(), correspondingMethodArg); String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); String returnType = DescriptorUtils.getCleanedVar(FQN); - + // We do not handle lambdas currently, so fail here. if (preCallArgument.getClassReference().getFullyQualifiedTypeName().contains("Lambda/")) { Succeeded = false; @@ -104,13 +111,28 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa String definedType = ""; if (variableStackHandler.DoesVariableExist(instanceIdForArgument)) { - definedType = variableStackHandler.getVariableType(instanceIdForArgument); + definedType = variableStackHandler.getVariableType(instanceIdForArgument); } else { definedType = preCallCommitedVariables.get(instanceIdForArgument); } // Define the variable before the method - variableDeclarationList.add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + // TODO: check if type equals "var" here which would be a terrible mistake. + if (!definedType.equals("var")) { + if (argumentValue.startsWith("-")) { + // TODO: Only works with integer! + variableDeclarationList + .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } + } else { + System.out.println(String.format( + "WARNING: Unable to get a proper type for agument in method. This should NEVER happen! %d", + instanceIdForArgument)); + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } } else { // Define the variable before the method variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index 180e0742..8dba46cd 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -12,10 +12,15 @@ public class SerializationUtils { public static ClassReference getCompatibleClassReference(ClassReference classReference) { + String FQN = classReference.getFullyQualifiedTypeName(); + if (FQN.startsWith("java.")) { + return classReference; + } + String[] libraryTypes = Main.instrumentationParameters.LibraryTypes; for (String libraryType : libraryTypes) { - if (classReference.getFullyQualifiedTypeName().equals(libraryType)) { + if (FQN.equals(libraryType)) { return classReference; } } @@ -37,15 +42,29 @@ public static ClassReference getCompatibleClassReference(ClassReference classRef return null; } + public static ClassReference getBetterType(ClassReference actualType, ClassReference desiredType) { + ClassReference compatibleClassReference = getCompatibleClassReference(actualType); + boolean isValid = compatibleClassReference != null && !compatibleClassReference.getFullyQualifiedTypeName().equals("java.lang.Object"); + + if (!isValid) { + compatibleClassReference = getCompatibleClassReference(desiredType); + isValid = compatibleClassReference != null && !compatibleClassReference.getFullyQualifiedTypeName().equals("java.lang.Object"); + if (!isValid) { + System.out.println("WARNING: Argument type is not supported by the library of Java Runtime Environment."); + System.out.println("WARNING: Actual Type: " + actualType.getFullyQualifiedTypeName()); + System.out.println("WARNING: Desired Type: " + desiredType.getFullyQualifiedTypeName()); + } + return desiredType; + } else { + return compatibleClassReference; + } + } + public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) throws SerializationException { String valueToBeEqualTo = serializableData.getValueAsXmlString(); - ClassReference compatibleClassReference = getCompatibleClassReference(serializableData.getClassReference()); - if (compatibleClassReference == null) { - compatibleClassReference = argClass; - } - + ClassReference compatibleClassReference = getBetterType(serializableData.getClassReference(), argClass); String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); if (!FQN.equals("java.lang.Integer") && From 4c455d6f6c04c97edaa17dbe354102e1bb0b3076 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 15 Jul 2024 15:17:09 +0200 Subject: [PATCH 184/244] fixes --- .../gilesi/testgenerator/TraceUtils.java | 4 +++- .../testgenerator/review/ArgumentUtils.java | 24 +++++++++++++++---- 2 files changed, 22 insertions(+), 6 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index c49d924e..f6d3d596 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -17,7 +17,9 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) throws SerializationException { if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); + if (argLineResult.Success) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); + } instanceVariableName = String.format("%s %s", methodName, instanceVariableName); } diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index d7e2d260..200ed354 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -119,13 +119,27 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa // Define the variable before the method // TODO: check if type equals "var" here which would be a terrible mistake. if (!definedType.equals("var")) { - if (argumentValue.startsWith("-")) { - // TODO: Only works with integer! - variableDeclarationList - .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + if (!definedType.equals("java.lang.Integer") && + !definedType.equals("java.lang.Void") && + !definedType.equals("java.lang.Boolean") && + !definedType.equals("java.lang.Byte") && + !definedType.equals("java.lang.Character") && + !definedType.equals("java.lang.Short") && + !definedType.equals("java.lang.Double") && + !definedType.equals("java.lang.Float") && + !definedType.equals("java.lang.Long") && + !definedType.equals("java.lang.String")) { + if (argumentValue.startsWith("-")) { + // TODO: Only works with integer! + variableDeclarationList + .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } } else { variableDeclarationList - .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + .add("%s = %s;".formatted(argumentVariable, argumentValue)); } } else { System.out.println(String.format( From 680434f544edaa7902af4c82286d1923ccd2574d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 09:39:27 +0200 Subject: [PATCH 185/244] Enhancements --- .../gilesi/testgenerator/TraceUtils.java | 60 ++++--------- .../testgenerator/review/ArgumentUtils.java | 86 +++++++++++-------- 2 files changed, 69 insertions(+), 77 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index f6d3d596..c158a869 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -26,11 +26,12 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success) { - for (String str : argLineResult.variableList) { - stringBuilder.append(String.format("%s\n", str)); - } + + for (String str : argLineResult.variableList) { + stringBuilder.append(String.format("%s\n", str)); + } + if (argLineResult.Success) { stringBuilder.append(callLine); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -43,14 +44,6 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, } } } else { - for (String str : argLineResult.variableList) { - if (argLineResult.Success) { - stringBuilder.append(String.format("%s\n", str)); - } else { - stringBuilder.append(String.format("// %s\n", str)); - } - } - stringBuilder.append(String.format("// %s", callLine)); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -85,7 +78,7 @@ private static void handleMethod(int traceId, // If true, we should not create new variables and we should comment out the // whole code. // As the code simply is not generable. - boolean issuesDetected = !argLineResult.Success; + boolean issuesDetected = false; if (isInstanceCall) { // When we have an instance dependent call, we need the instance the call is @@ -121,7 +114,7 @@ private static void handleMethod(int traceId, String returnType = DescriptorUtils.getCleanedVar(FQN); if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { - if (!issuesDetected) { + if (argLineResult.Success && !issuesDetected) { variableStackHandler.CreateNewVariable(returnData.getInstanceId(), returnType); } else { String warnMessage = String.format( @@ -139,11 +132,12 @@ private static void handleMethod(int traceId, // TODO: check if type equals "var" here which would be a terrible mistake. String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (argLineResult.Success && !issuesDetected) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + + if (argLineResult.Success && !issuesDetected) { callStringBuilder.append(callLine); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -156,14 +150,6 @@ private static void handleMethod(int traceId, } } } else { - for (String str : argLineResult.variableList) { - if (argLineResult.Success) { - callStringBuilder.append(String.format("%s\n", str)); - } else { - callStringBuilder.append(String.format("// %s\n", str)); - } - } - callStringBuilder.append(String.format("// %s", callLine)); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -178,11 +164,11 @@ private static void handleMethod(int traceId, } } else { String callLine = String.format("%s(%s);\n", methodName, argumentLine); - if (argLineResult.Success && !issuesDetected) { - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } + for (String str : argLineResult.variableList) { + callStringBuilder.append(String.format("%s\n", str)); + } + if (argLineResult.Success && !issuesDetected) { callStringBuilder.append(callLine); if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { @@ -191,14 +177,6 @@ private static void handleMethod(int traceId, } } } else { - for (String str : argLineResult.variableList) { - if (argLineResult.Success) { - callStringBuilder.append(String.format("%s\n", str)); - } else { - callStringBuilder.append(String.format("// %s\n", str)); - } - } - callStringBuilder.append(String.format("// %s", callLine)); if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { @@ -210,11 +188,7 @@ private static void handleMethod(int traceId, } // Append the method call to the current string builder. - //if (issuesDetected) { - // stringBuilder.append(String.format("// %s", callStringBuilder.toString())); - //} else { - stringBuilder.append(callStringBuilder.toString()); - //} + stringBuilder.append(callStringBuilder.toString()); } public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java index 200ed354..f803fdcc 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/ArgumentUtils.java @@ -1,9 +1,7 @@ package com.github.gilesi.testgenerator.review; import java.util.ArrayList; -import java.util.HashMap; import java.util.List; -import java.util.Map.Entry; import com.github.gilesi.instrumentation.models.ClassReference; import com.github.gilesi.instrumentation.models.InstanceReference; @@ -17,9 +15,13 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa List variableDeclarationList = new ArrayList<>(); List preCallArguments = new ArrayList<>(); - HashMap preCallCommitedVariables = new HashMap<>(); for (int i = 0; i < trace.getPreCallArguments().size(); i++) { + boolean localSucceeded = true; + String localArgumentType = ""; + int localArgumentInstanceId = 0; + boolean localAddArgument = false; + InstanceReference preCallArgument = trace.getPreCallArguments().get(i); if (preCallArgument.getIsNull()) { @@ -51,8 +53,7 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa // Therefore, also keep a list of variables we define temporarily given we // commit this only at the end of this routine. Integer instanceIdForArgument = preCallArgument.getInstanceId(); - boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument) - || preCallCommitedVariables.containsKey(instanceIdForArgument); + boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument); if (variableAlreadyComitted) { argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); } else { @@ -63,10 +64,12 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa // We do not handle lambdas currently, so fail here. if (preCallArgument.getClassReference().getFullyQualifiedTypeName().contains("Lambda/")) { - Succeeded = false; + localSucceeded = false; } else { // Variable does not exist yet, commit to it later - preCallCommitedVariables.put(instanceIdForArgument, returnType); + localArgumentInstanceId = instanceIdForArgument; + localArgumentType = returnType; + localAddArgument = true; } argumentVariable = String.format("%s %s", returnType, @@ -90,7 +93,7 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa } else { // We cant do much, fail. argumentValue = "\"%s\"".formatted(preCallArgument.getValueAsXmlString()); - Succeeded = false; + localSucceeded = false; } } } else { @@ -103,18 +106,12 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa } else { // We cant do much, fail. argumentValue = "\"UNKNOWN_DATA_VALUE\""; - Succeeded = false; + localSucceeded = false; } } if (variableAlreadyComitted) { - String definedType = ""; - - if (variableStackHandler.DoesVariableExist(instanceIdForArgument)) { - definedType = variableStackHandler.getVariableType(instanceIdForArgument); - } else { - definedType = preCallCommitedVariables.get(instanceIdForArgument); - } + String definedType = variableStackHandler.getVariableType(instanceIdForArgument); // Define the variable before the method // TODO: check if type equals "var" here which would be a terrible mistake. @@ -131,42 +128,63 @@ public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHa !definedType.equals("java.lang.String")) { if (argumentValue.startsWith("-")) { // TODO: Only works with integer! + if (localSucceeded) { + variableDeclarationList + .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("// %s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } + } else { + if (localSucceeded) { + variableDeclarationList + .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("// %s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } + } + } else { + if (localSucceeded) { variableDeclarationList - .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + .add("%s = %s;".formatted(argumentVariable, argumentValue)); } else { variableDeclarationList - .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + .add("// %s = %s;".formatted(argumentVariable, argumentValue)); } - } else { - variableDeclarationList - .add("%s = %s;".formatted(argumentVariable, argumentValue)); } } else { System.out.println(String.format( "WARNING: Unable to get a proper type for agument in method. This should NEVER happen! %d", instanceIdForArgument)); - variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + if (localSucceeded) { + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } else { + variableDeclarationList.add("// %s = %s;".formatted(argumentVariable, argumentValue)); + } } } else { // Define the variable before the method - variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + if (localSucceeded) { + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } else { + variableDeclarationList.add("// %s = %s;".formatted(argumentVariable, argumentValue)); + } } - } - - String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); - // If the generation above succeeded then create the variables on the stack but - // not otherwise - // as we would skip defining those variables and we would get further issues - // down the line. - if (Succeeded) { - for (Entry preCallArgument : preCallCommitedVariables.entrySet()) { - if (!variableStackHandler.DoesVariableExist(preCallArgument.getKey())) { - variableStackHandler.CreateNewVariable(preCallArgument.getKey(), preCallArgument.getValue()); + if (localSucceeded && localAddArgument) { + if (!variableStackHandler.DoesVariableExist(localArgumentInstanceId)) { + variableStackHandler.CreateNewVariable(localArgumentInstanceId, localArgumentType); } } + + if (!localSucceeded) { + Succeeded = false; + } } + String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); + // Return if we succeeded, the list of stuff to pass as method arguments, and // the list of variable declarations to add if any return new ArgLineGenerateResult(Succeeded, formattedArgumentsForUseInMethodCall, variableDeclarationList); From ffc7f8649d9fd2fefbb0667c27d18b6532701315 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 10:39:23 +0200 Subject: [PATCH 186/244] fix: instance casting --- .../github/gilesi/testgenerator/TraceUtils.java | 15 +++++++++++---- 1 file changed, 11 insertions(+), 4 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index c158a869..fbf83570 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -26,7 +26,7 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - + for (String str : argLineResult.variableList) { stringBuilder.append(String.format("%s\n", str)); } @@ -106,6 +106,8 @@ private static void handleMethod(int traceId, } if (returnData != null) { + int returnDataInstanceId = returnData.getInstanceId(); + //String rFQN = DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); //String rReturnType = DescriptorUtils.getCleanedVar(rFQN); @@ -113,13 +115,13 @@ private static void handleMethod(int traceId, String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); String returnType = DescriptorUtils.getCleanedVar(FQN); - if (!variableStackHandler.DoesVariableExist(returnData.getInstanceId())) { + if (!variableStackHandler.DoesVariableExist(returnDataInstanceId)) { if (argLineResult.Success && !issuesDetected) { - variableStackHandler.CreateNewVariable(returnData.getInstanceId(), returnType); + variableStackHandler.CreateNewVariable(returnDataInstanceId, returnType); } else { String warnMessage = String.format( "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", - traceId + 1, returnData.getInstanceId()); + traceId + 1, returnDataInstanceId); // Log the warning to the current string builder and the console. System.out.println(warnMessage); @@ -127,6 +129,11 @@ private static void handleMethod(int traceId, } returnVariableName = String.format("%s %s", returnType, returnVariableName); + } else { + String tmpReturnType = variableStackHandler.getVariableType(returnDataInstanceId); + if (!tmpReturnType.equals("var")) { + returnType = tmpReturnType; + } } // TODO: check if type equals "var" here which would be a terrible mistake. From eea33bb63668d7d6e37b8f6f34f305f7140a0c60 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 11:09:22 +0200 Subject: [PATCH 187/244] further fixes --- .../gilesi/testgenerator/TraceUtils.java | 29 +++++++++++++++++-- .../review/SerializationUtils.java | 13 +++++++++ 2 files changed, 39 insertions(+), 3 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index fbf83570..5626883c 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -16,15 +16,28 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, String instanceVariableName, String methodName, String argumentLine, ArgLineGenerateResult argLineResult, StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) throws SerializationException { + + String callLine = ""; + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { if (argLineResult.Success) { variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); } instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + + callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); + } else { + String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); + if (!tmpInstanceType.equals("var")) { + callLine = String.format("%s = (%s)(new %s(%s));\n", instanceVariableName, tmpInstanceType, methodName, + argumentLine); + } else { + callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, + argumentLine); + } } - String callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, - argumentLine); String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); for (String str : argLineResult.variableList) { @@ -102,7 +115,17 @@ private static void handleMethod(int traceId, // An instance method call is not called by its fully qualified name (i.e. // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } else { + String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); + if (!tmpInstanceType.equals("var")) { + // TODO: use the true api type here (we know this info... but lack it in the trace files currently...) + methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, instanceMethodCallName); + } else { + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } + } } if (returnData != null) { diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index 8dba46cd..715cc901 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -16,6 +16,19 @@ public static ClassReference getCompatibleClassReference(ClassReference classRef if (FQN.startsWith("java.")) { return classReference; } + + if (FQN.replace("[]", "").equals("int") || + FQN.replace("[]", "").equals("void") || + FQN.replace("[]", "").equals("boolean") || + FQN.replace("[]", "").equals("byte") || + FQN.replace("[]", "").equals("char") || + FQN.replace("[]", "").equals("short") || + FQN.replace("[]", "").equals("double") || + FQN.replace("[]", "").equals("float") || + FQN.replace("[]", "").equals("long") || + FQN.replace("[]", "").equals("string")) { + return classReference; + } String[] libraryTypes = Main.instrumentationParameters.LibraryTypes; From cb14c0b7f938d01730d65e65ef63991b5031d8f2 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 11:27:34 +0200 Subject: [PATCH 188/244] cleanup --- .../gilesi/testgenerator/TraceUtils.java | 135 ++++++++---------- 1 file changed, 57 insertions(+), 78 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 5626883c..33c75b17 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -13,16 +13,17 @@ public class TraceUtils { private static void handleConstructor(VariableStackHandler variableStackHandler, InstanceReference instanceData, - String instanceVariableName, String methodName, String argumentLine, ArgLineGenerateResult argLineResult, + String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) throws SerializationException { String callLine = ""; if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - if (argLineResult.Success) { + if (argLineResultSuccess) { variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); } + instanceVariableName = String.format("%s %s", methodName, instanceVariableName); callLine = String.format("%s = new %s(%s);\n", instanceVariableName, methodName, @@ -38,33 +39,27 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, } } - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - - for (String str : argLineResult.variableList) { - stringBuilder.append(String.format("%s\n", str)); - } - - if (argLineResult.Success) { + if (argLineResultSuccess) { stringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - stringBuilder.append(returnAssertionLine + "\n"); - } - - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - stringBuilder.append(varAssert + "\n"); - } - } } else { stringBuilder.append(String.format("// %s", callLine)); + } - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + if (argLineResultSuccess) { + stringBuilder.append(String.format("%s\n", returnAssertionLine)); + } else { stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } + } - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + if (argLineResultSuccess) { + stringBuilder.append(String.format("%s\n", varAssert)); + } else { stringBuilder.append(String.format("// %s\n", varAssert)); } } @@ -73,7 +68,7 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, private static void handleMethod(int traceId, VariableStackHandler variableStackHandler, InstanceReference instanceData, - String instanceVariableName, String methodName, String argumentLine, ArgLineGenerateResult argLineResult, + String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) throws SerializationException { boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() @@ -85,8 +80,6 @@ private static void handleMethod(int traceId, returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); } - StringBuilder callStringBuilder = new StringBuilder(); - // Holds whenever or not an issue with instances was found // If true, we should not create new variables and we should comment out the // whole code. @@ -120,8 +113,10 @@ private static void handleMethod(int traceId, } else { String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); if (!tmpInstanceType.equals("var")) { - // TODO: use the true api type here (we know this info... but lack it in the trace files currently...) - methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, instanceMethodCallName); + // TODO: use the true api type here (we know this info... but lack it in the + // trace files currently...) + methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, + instanceMethodCallName); } else { methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); } @@ -131,15 +126,17 @@ private static void handleMethod(int traceId, if (returnData != null) { int returnDataInstanceId = returnData.getInstanceId(); - //String rFQN = DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); - //String rReturnType = DescriptorUtils.getCleanedVar(rFQN); + // String rFQN = + // DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); + // String rReturnType = DescriptorUtils.getCleanedVar(rFQN); - ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), trace.getMethodReference().getReturnType()); + ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), + trace.getMethodReference().getReturnType()); String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); String returnType = DescriptorUtils.getCleanedVar(FQN); if (!variableStackHandler.DoesVariableExist(returnDataInstanceId)) { - if (argLineResult.Success && !issuesDetected) { + if (argLineResultSuccess && !issuesDetected) { variableStackHandler.CreateNewVariable(returnDataInstanceId, returnType); } else { String warnMessage = String.format( @@ -160,65 +157,43 @@ private static void handleMethod(int traceId, } // TODO: check if type equals "var" here which would be a terrible mistake. - String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); - String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - if (argLineResult.Success && !issuesDetected) { - callStringBuilder.append(callLine); - - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append(String.format("%s\n", returnAssertionLine)); - } + String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, + argumentLine); - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("%s\n", varAssert)); - } - } + if (argLineResultSuccess && !issuesDetected) { + stringBuilder.append(callLine); } else { - callStringBuilder.append(String.format("// %s", callLine)); + stringBuilder.append(String.format("// %s", callLine)); + } - if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { - callStringBuilder.append(String.format("// %s\n", returnAssertionLine)); - } + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("// %s\n", varAssert)); - } + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + if (argLineResultSuccess && !issuesDetected) { + stringBuilder.append(String.format("%s\n", returnAssertionLine)); + } else { + stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } } } else { String callLine = String.format("%s(%s);\n", methodName, argumentLine); - for (String str : argLineResult.variableList) { - callStringBuilder.append(String.format("%s\n", str)); - } - - if (argLineResult.Success && !issuesDetected) { - callStringBuilder.append(callLine); - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("%s\n", varAssert)); - } - } + if (argLineResultSuccess && !issuesDetected) { + stringBuilder.append(callLine); } else { - callStringBuilder.append(String.format("// %s", callLine)); + stringBuilder.append(String.format("// %s", callLine)); + } + } - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - callStringBuilder.append(String.format("// %s\n", varAssert)); - } + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + for (String varAssert : postCallParameterAssertionLine) { + if (argLineResultSuccess && !issuesDetected) { + stringBuilder.append(String.format("%s\n", varAssert)); + } else { + stringBuilder.append(String.format("// %s\n", varAssert)); } } } - - // Append the method call to the current string builder. - stringBuilder.append(callStringBuilder.toString()); } public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, @@ -238,12 +213,16 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, variableStackHandler); + for (String str : argLineResult.variableList) { + testMethodStringBuilder.append(String.format("%s\n", str)); + } + if (trace.getMethodReference().getIsConstructor()) { handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, - argLineResult, testMethodStringBuilder, postCallParameterAssertionLine, trace); + argLineResult.Success, testMethodStringBuilder, postCallParameterAssertionLine, trace); } else { handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, - argLineResult, testMethodStringBuilder, postCallParameterAssertionLine, trace); + argLineResult.Success, testMethodStringBuilder, postCallParameterAssertionLine, trace); } } } \ No newline at end of file From 462e08e72019a42d5b1fed8ab26bef53a4e2cd66 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 11:36:45 +0200 Subject: [PATCH 189/244] further cleanup --- .../gilesi/testgenerator/TraceUtils.java | 196 ++++++++++++------ 1 file changed, 131 insertions(+), 65 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 33c75b17..51dedc69 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -12,11 +12,9 @@ import com.github.gilesi.testgenerator.exceptions.SerializationException; public class TraceUtils { - private static void handleConstructor(VariableStackHandler variableStackHandler, InstanceReference instanceData, - String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, - StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) - throws SerializationException { - + private static void handleConstructor(VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, StringBuilder stringBuilder, Trace trace) throws SerializationException { String callLine = ""; if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { @@ -54,26 +52,83 @@ private static void handleConstructor(VariableStackHandler variableStackHandler, stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } } + } - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { + private static void handleMethod(int traceId, VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, StringBuilder stringBuilder, Trace trace) throws SerializationException { + InstanceReference returnData = trace.getReturnedValue(); + String returnVariableName = ""; + if (returnData != null) { + returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); + } + + if (returnData != null) { + int returnDataInstanceId = returnData.getInstanceId(); + + // String rFQN = + // DescriptorUtils.getCleanedType(returnData.getClassReference().getFullyQualifiedTypeName()); + // String rReturnType = DescriptorUtils.getCleanedVar(rFQN); + + ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), + trace.getMethodReference().getReturnType()); + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + + if (!variableStackHandler.DoesVariableExist(returnDataInstanceId)) { if (argLineResultSuccess) { - stringBuilder.append(String.format("%s\n", varAssert)); + variableStackHandler.CreateNewVariable(returnDataInstanceId, returnType); } else { - stringBuilder.append(String.format("// %s\n", varAssert)); + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + traceId + 1, returnDataInstanceId); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + stringBuilder.append(String.format("// %s\n", warnMessage)); + } + + returnVariableName = String.format("%s %s", returnType, returnVariableName); + } else { + String tmpReturnType = variableStackHandler.getVariableType(returnDataInstanceId); + if (!tmpReturnType.equals("var")) { + returnType = tmpReturnType; } } + + // TODO: check if type equals "var" here which would be a terrible mistake. + String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, + argumentLine); + + if (argLineResultSuccess) { + stringBuilder.append(callLine); + } else { + stringBuilder.append(String.format("// %s", callLine)); + } + + String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); + + if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { + if (argLineResultSuccess) { + stringBuilder.append(String.format("%s\n", returnAssertionLine)); + } else { + stringBuilder.append(String.format("// %s\n", returnAssertionLine)); + } + } + } else { + String callLine = String.format("%s(%s);\n", methodName, argumentLine); + + if (argLineResultSuccess) { + stringBuilder.append(callLine); + } else { + stringBuilder.append(String.format("// %s", callLine)); + } } } - private static void handleMethod(int traceId, - VariableStackHandler variableStackHandler, InstanceReference instanceData, - String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, - StringBuilder stringBuilder, List postCallParameterAssertionLine, Trace trace) - throws SerializationException { - boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() - .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); - + private static boolean handleMethodInstance(int traceId, VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, StringBuilder stringBuilder, Trace trace) throws SerializationException { InstanceReference returnData = trace.getReturnedValue(); String returnVariableName = ""; if (returnData != null) { @@ -86,40 +141,38 @@ private static void handleMethod(int traceId, // As the code simply is not generable. boolean issuesDetected = false; - if (isInstanceCall) { - // When we have an instance dependent call, we need the instance the call is - // performed onto to exist - // If it does not exist, then we cannot generate this code - // Log that, and comment out the code we would have generated. - // And make sure we do not create a variable for the return value if a thing. - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - String warnMessage = String.format( - "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", - traceId + 1, methodName, instanceData.getInstanceId(), - instanceData.getClassReference().getFullyQualifiedTypeName()); - - // Log the warning to the current string builder and the console. - System.out.println(warnMessage); - stringBuilder.append(String.format("// %s\n", warnMessage)); - - issuesDetected = true; - } + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist + // If it does not exist, then we cannot generate this code + // Log that, and comment out the code we would have generated. + // And make sure we do not create a variable for the return value if a thing. + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + traceId + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); - // An instance method call is not called by its fully qualified name (i.e. - // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. - String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; - if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + stringBuilder.append(String.format("// %s\n", warnMessage)); + + issuesDetected = true; + } + + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } else { + String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); + if (!tmpInstanceType.equals("var")) { + // TODO: use the true api type here (we know this info... but lack it in the + // trace files currently...) + methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, + instanceMethodCallName); } else { - String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); - if (!tmpInstanceType.equals("var")) { - // TODO: use the true api type here (we know this info... but lack it in the - // trace files currently...) - methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, - instanceMethodCallName); - } else { - methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); - } + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); } } @@ -185,15 +238,7 @@ private static void handleMethod(int traceId, } } - if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { - for (String varAssert : postCallParameterAssertionLine) { - if (argLineResultSuccess && !issuesDetected) { - stringBuilder.append(String.format("%s\n", varAssert)); - } else { - stringBuilder.append(String.format("// %s\n", varAssert)); - } - } - } + return !issuesDetected; } public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, @@ -209,20 +254,41 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var } ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); - String argumentLine = argLineResult.argumentsForMethodCall; - List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, - variableStackHandler); for (String str : argLineResult.variableList) { testMethodStringBuilder.append(String.format("%s\n", str)); } + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); + + boolean success = true; + if (trace.getMethodReference().getIsConstructor()) { - handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, - argLineResult.Success, testMethodStringBuilder, postCallParameterAssertionLine, trace); + handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, + argLineResult.argumentsForMethodCall, + argLineResult.Success, testMethodStringBuilder, trace); + } else if (isInstanceCall) { + success = handleMethodInstance(traceId, variableStackHandler, instanceData, instanceVariableName, + methodName, argLineResult.argumentsForMethodCall, + argLineResult.Success, testMethodStringBuilder, trace); } else { - handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, argumentLine, - argLineResult.Success, testMethodStringBuilder, postCallParameterAssertionLine, trace); + handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, + argLineResult.argumentsForMethodCall, + argLineResult.Success, testMethodStringBuilder, trace); + } + + if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { + List postCallParameterAssertionLine = AssertionUtils.traceArgumentsToAssert(trace, + variableStackHandler); + + for (String varAssert : postCallParameterAssertionLine) { + if (argLineResult.Success && success) { + testMethodStringBuilder.append(String.format("%s\n", varAssert)); + } else { + testMethodStringBuilder.append(String.format("// %s\n", varAssert)); + } + } } } } \ No newline at end of file From fa609e3149d87e7387e058a12104b7832418dd8d Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 11:37:36 +0200 Subject: [PATCH 190/244] more cleanup --- .../github/gilesi/testgenerator/TraceUtils.java | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index 51dedc69..f4cab0c1 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -242,7 +242,7 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va } public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, - StringBuilder testMethodStringBuilder) throws SerializationException { + StringBuilder stringBuilder) throws SerializationException { String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); @@ -256,7 +256,7 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); for (String str : argLineResult.variableList) { - testMethodStringBuilder.append(String.format("%s\n", str)); + stringBuilder.append(String.format("%s\n", str)); } boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() @@ -267,15 +267,15 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var if (trace.getMethodReference().getIsConstructor()) { handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, argLineResult.argumentsForMethodCall, - argLineResult.Success, testMethodStringBuilder, trace); + argLineResult.Success, stringBuilder, trace); } else if (isInstanceCall) { success = handleMethodInstance(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, argLineResult.argumentsForMethodCall, - argLineResult.Success, testMethodStringBuilder, trace); + argLineResult.Success, stringBuilder, trace); } else { handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, argLineResult.argumentsForMethodCall, - argLineResult.Success, testMethodStringBuilder, trace); + argLineResult.Success, stringBuilder, trace); } if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { @@ -284,9 +284,9 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var for (String varAssert : postCallParameterAssertionLine) { if (argLineResult.Success && success) { - testMethodStringBuilder.append(String.format("%s\n", varAssert)); + stringBuilder.append(String.format("%s\n", varAssert)); } else { - testMethodStringBuilder.append(String.format("// %s\n", varAssert)); + stringBuilder.append(String.format("// %s\n", varAssert)); } } } From f36e52edc3bdd37cd60ddb5dbf0877ace2e82379 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 16 Jul 2024 11:43:27 +0200 Subject: [PATCH 191/244] cleanup --- .../gilesi/testgenerator/TraceUtils.java | 73 ++++++++----------- 1 file changed, 29 insertions(+), 44 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index f4cab0c1..afd6a5bf 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -58,12 +58,11 @@ private static void handleMethod(int traceId, VariableStackHandler variableStack InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, StringBuilder stringBuilder, Trace trace) throws SerializationException { InstanceReference returnData = trace.getReturnedValue(); - String returnVariableName = ""; - if (returnData != null) { - returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); - } + + String callLine = ""; if (returnData != null) { + String returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); int returnDataInstanceId = returnData.getInstanceId(); // String rFQN = @@ -97,15 +96,18 @@ private static void handleMethod(int traceId, VariableStackHandler variableStack } // TODO: check if type equals "var" here which would be a terrible mistake. - String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, - argumentLine); + callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); + } else { + callLine = String.format("%s(%s);\n", methodName, argumentLine); + } - if (argLineResultSuccess) { - stringBuilder.append(callLine); - } else { - stringBuilder.append(String.format("// %s", callLine)); - } + if (argLineResultSuccess) { + stringBuilder.append(callLine); + } else { + stringBuilder.append(String.format("// %s", callLine)); + } + if (returnData != null) { String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -115,14 +117,6 @@ private static void handleMethod(int traceId, VariableStackHandler variableStack stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } } - } else { - String callLine = String.format("%s(%s);\n", methodName, argumentLine); - - if (argLineResultSuccess) { - stringBuilder.append(callLine); - } else { - stringBuilder.append(String.format("// %s", callLine)); - } } } @@ -130,10 +124,6 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, boolean argLineResultSuccess, StringBuilder stringBuilder, Trace trace) throws SerializationException { InstanceReference returnData = trace.getReturnedValue(); - String returnVariableName = ""; - if (returnData != null) { - returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); - } // Holds whenever or not an issue with instances was found // If true, we should not create new variables and we should comment out the @@ -176,7 +166,10 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va } } + String callLine = ""; + if (returnData != null) { + String returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); int returnDataInstanceId = returnData.getInstanceId(); // String rFQN = @@ -210,15 +203,18 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va } // TODO: check if type equals "var" here which would be a terrible mistake. - String callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, - argumentLine); + callLine = String.format("%s = (%s)%s(%s);\n", returnVariableName, returnType, methodName, argumentLine); + } else { + callLine = String.format("%s(%s);\n", methodName, argumentLine); + } - if (argLineResultSuccess && !issuesDetected) { - stringBuilder.append(callLine); - } else { - stringBuilder.append(String.format("// %s", callLine)); - } + if (argLineResultSuccess && !issuesDetected) { + stringBuilder.append(callLine); + } else { + stringBuilder.append(String.format("// %s", callLine)); + } + if (returnData != null) { String returnAssertionLine = AssertionUtils.traceToAssert(trace, variableStackHandler); if (returnAssertionLine != null && !returnAssertionLine.isEmpty()) { @@ -228,14 +224,6 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va stringBuilder.append(String.format("// %s\n", returnAssertionLine)); } } - } else { - String callLine = String.format("%s(%s);\n", methodName, argumentLine); - - if (argLineResultSuccess && !issuesDetected) { - stringBuilder.append(callLine); - } else { - stringBuilder.append(String.format("// %s", callLine)); - } } return !issuesDetected; @@ -266,16 +254,13 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var if (trace.getMethodReference().getIsConstructor()) { handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, - argLineResult.argumentsForMethodCall, - argLineResult.Success, stringBuilder, trace); + argLineResult.argumentsForMethodCall, argLineResult.Success, stringBuilder, trace); } else if (isInstanceCall) { success = handleMethodInstance(traceId, variableStackHandler, instanceData, instanceVariableName, - methodName, argLineResult.argumentsForMethodCall, - argLineResult.Success, stringBuilder, trace); + methodName, argLineResult.argumentsForMethodCall, argLineResult.Success, stringBuilder, trace); } else { handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, - argLineResult.argumentsForMethodCall, - argLineResult.Success, stringBuilder, trace); + argLineResult.argumentsForMethodCall, argLineResult.Success, stringBuilder, trace); } if (StaticConfiguration.GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL) { From 3288f7ad844fedcb438bed3eb2ccc632db4daaf6 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 17 Jul 2024 10:27:44 +0200 Subject: [PATCH 192/244] fix: remove some commenting out --- .../com/github/gilesi/maestro/Constants.java | 2 ++ .../gilesi/maestro/compsuite/CompSuite.java | 17 +++++---- .../testgenerator/StaticConfiguration.java | 2 ++ .../review/SerializationUtils.java | 35 ++++++++++--------- 4 files changed, 33 insertions(+), 23 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index b8986d56..ba75d772 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -33,4 +33,6 @@ public class Constants { public static final String SUREFIRE_VERSION = "2.8"; public static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; + + public static boolean SKIP_INSTRUMENTATION_RAN_ALREADY_FOR_DEBUGGING = false; } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 8f991372..66791328 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -131,14 +131,17 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } } - //String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); - //if (javaToolOptions == null) { - // continue; - //} - - //Main.logger.info("Testing old project"); TestAssertedLogger oldTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); - //ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + + if (!Constants.SKIP_INSTRUMENTATION_RAN_ALREADY_FOR_DEBUGGING) { + String javaToolOptions = actionInterface.preRunOld(incompatibility, oldDestinationProjectPath, testCmd); + if (javaToolOptions == null) { + continue; + } + + Main.logger.info("Testing old project"); + ProjectRunner.runMavenGoalOnRepository(oldDestinationProjectPath.toString(), testCmd, null, "1.8", oldTestAssertedLogger, javaToolOptions); + } actionInterface.postRunOld(incompatibility, oldDestinationProjectPath, oldTestAssertedLogger, runResult); runResults.add(runResult); diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java index 34d69317..1e2cd6de 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java @@ -7,4 +7,6 @@ public class StaticConfiguration { public static final boolean USE_ALTERNATIVE_ASSERTION_MODE = false; public static final boolean GENERATE_INPUT_VALUES_ASSERTIONS_POST_METHOD_CALL = false; + + public static final boolean SKIP_LONG_ARG_STRING_FOR_DEBUGGING = true; } \ No newline at end of file diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java index 715cc901..bf901ed5 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/review/SerializationUtils.java @@ -4,6 +4,7 @@ import com.github.gilesi.instrumentation.models.InstanceReference; import com.github.gilesi.testgenerator.DescriptorUtils; import com.github.gilesi.testgenerator.Main; +import com.github.gilesi.testgenerator.StaticConfiguration; import com.github.gilesi.testgenerator.exceptions.SerializationException; import org.apache.commons.text.StringEscapeUtils; @@ -127,28 +128,30 @@ public static String serializableDataToJava(InstanceReference serializableData, public static String generateStringJavaLine(String stringContent) { String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(stringContent)); - // int maxStringSize = (int) Math.pow(2, 16); + //int maxStringSize = (int) Math.pow(2, 16); // TODO: CHeck why this still fails int maxStringSize = 1024; if (valueAsCode.length() > maxStringSize) { - /*List sectionList = new ArrayList<>(); - - for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { - int end2 = start2 + maxStringSize; - if (start2 + maxStringSize > valueAsCode.length()) { - end2 = valueAsCode.length(); + if (!StaticConfiguration.SKIP_LONG_ARG_STRING_FOR_DEBUGGING) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = valueAsCode.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); } - - String sectionOfDataAsXml = valueAsCode.substring(start2, end2); - String readyToUseSection = "new String(\"%s\")" - .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); - sectionList.add(readyToUseSection); + + valueAsCode = String.join(" + ", sectionList.toArray(String[]::new)); + } else { + valueAsCode = "\"SNIP!\""; } - - valueAsCode = String.join(" + ", sectionList.toArray(String[]::new));*/ - - valueAsCode = "\"SNIP!\""; } return valueAsCode; From 1fc9dc5b08682ff778cb9089be435aae63dc80bc Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 17 Jul 2024 10:48:52 +0200 Subject: [PATCH 193/244] Add sample run execution script --- .../visitors/MethodInstrumentor.java | 16 +++-- .../java/com/github/gilesi/maestro/Main.java | 22 +++++-- .../gilesi/maestro/compsuite/CompSuite.java | 63 ++++++++++--------- SampleRun.sh | 16 +++++ 4 files changed, 79 insertions(+), 38 deletions(-) create mode 100755 SampleRun.sh diff --git a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java index d20b7dd6..cf205b7e 100644 --- a/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java +++ b/Instrumentation/src/main/java/com/github/gilesi/instrumentation/visitors/MethodInstrumentor.java @@ -14,7 +14,9 @@ import static net.bytebuddy.matcher.ElementMatchers.named; public class MethodInstrumentor { - private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(Class classParameter) { + // commented out due to hooking issues + // yet to investigate + /*private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(Class classParameter) { ElementMatcher.Junction descriptorMatcher = null; for (String descriptorParameter : classParameter.ClassDescriptors) { if (descriptorMatcher == null) { @@ -24,24 +26,26 @@ private static ElementMatcher.Junction getConstructorElementM } } return descriptorMatcher; - } + }*/ private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(Class classParameter) { ElementMatcher.Junction classMatcher = null; for (Method methodParameter : classParameter.ClassMethods) { ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); - ElementMatcher.Junction descriptorMatcher = null; - /*for (String descriptorParameter : methodParameter.MethodDescriptors) { + // commented out due to hooking issues + // yet to investigate + /*ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : methodParameter.MethodDescriptors) { if (descriptorMatcher == null) { descriptorMatcher = hasDescriptor(descriptorParameter); } else { descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); } - }*/ + } if (descriptorMatcher != null) { methodMatcher = methodMatcher.and(descriptorMatcher); - } + }*/ if (classMatcher == null) { classMatcher = methodMatcher; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 984b35de..09d70f57 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -20,7 +20,7 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP return; } - if (args.length != 6) { + /*if (args.length != 6) { logger.info("Usage: "); return; } @@ -32,13 +32,27 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP String dependencyVersion = args[4]; String outputTestProject = args[5]; - //Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject); + Orchestrator.handleProject(clientLocation, libraryLocation, gilesiRepositoryLocation, dependencyName, dependencyVersion, outputTestProject);*/ - String dataset = "/home/gus/Datasets/compsuite/incompatibilities.json"; String datasetOutput = "/home/gus/Datasets/compsuite3"; String GilesiRepositoryLocation = "/home/gus/Git/gilesi"; + String projectToRunOn = null; + + if (args.length < 2) { + logger.info("Usage: "); + return; + } + + datasetOutput = args[0]; + GilesiRepositoryLocation = args[1]; + + if (args.length == 3) { + projectToRunOn = args[2]; + } + + String dataset = String.format("%s/incompatibilities.json", datasetOutput); //CompSuiteFixes.copySourcesForDataset(dataset, datasetOutput); - CompSuite.runOnDataset(GilesiRepositoryLocation, dataset, datasetOutput); + CompSuite.runOnDataset(GilesiRepositoryLocation, dataset, datasetOutput, projectToRunOn); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 66791328..df8ed704 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -40,7 +40,7 @@ static void printIncompatibility(CompSuiteIncompatibility incompatibility) { Main.logger.info("-----------------------------------"); } - public static void runOldOnDataset(String dataset, String datasetOutput, CompSuiteRunnable actionInterface) throws IOException, MavenInvocationException, InterruptedException { + public static void runOldOnDataset(String dataset, String datasetOutput, CompSuiteRunnable actionInterface, String projectId) throws IOException, MavenInvocationException, InterruptedException { CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); Path datasetOutputPath = Path.of(datasetOutput); @@ -48,6 +48,10 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui List runResults = new ArrayList<>(); for (CompSuiteIncompatibility incompatibility : incompatibilities) { + if (projectId != null && !projectId.equals(incompatibility.id)) { + continue; + } + printIncompatibility(incompatibility); RunResult runResult = new RunResult(); @@ -213,7 +217,34 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } } - public static void runOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput) throws IOException, MavenInvocationException, InterruptedException { + private static String generateGradleBuildFile(String dependencyName, String dependencyVersion) { + return """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + jvmArgs = ["--add-opens=java.base/java.util=ALL-UNNAMED"] + }""".formatted(dependencyName, dependencyVersion); + } + + public static void runOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput, String projectToRunOn) throws IOException, MavenInvocationException, InterruptedException { Path datasetOutputPath = Path.of(datasetOutput); runOldOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { @@ -312,31 +343,7 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina lastMinuteCleanup(allProjectFiles); // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion - - String buildGradleProjectFile = """ - plugins { - id 'java' - } - - group = 'testProject' - version = '1.0-SNAPSHOT' - - repositories { - mavenCentral() - mavenLocal() - } - - dependencies { - testImplementation '%s:%s' - testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' - testImplementation platform('org.junit:junit-bom:5.10.0') - testImplementation 'org.junit.jupiter:junit-jupiter' - } - - test { - useJUnitPlatform() - jvmArgs = ["--add-opens=java.base/java.util=ALL-UNNAMED"] - }""".formatted(dependencyName, dependencyVersion); + String buildGradleProjectFile = generateGradleBuildFile(dependencyName, dependencyVersion); Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); Files.deleteIfExists(generatedCodeFolderPath.resolve("gradlew")); @@ -436,6 +443,6 @@ testImplementation platform('org.junit:junit-bom:5.10.0') runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion = returnCode != 0; runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedCodeFolderPath.resolve("build.gradle").toString()); } - }); + }, projectToRunOn); } } diff --git a/SampleRun.sh b/SampleRun.sh new file mode 100755 index 00000000..7af5167d --- /dev/null +++ b/SampleRun.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# maestro requires the use of other subprojects that must be precompiled before running, and pointed to it via the gilesi repo arg. +# first compile everything +sh ./compile.sh + +export MAVEN_HOME="/snap/intellij-idea-ultimate/current/plugins/maven/lib/maven3" + +# then run maestro for sample usage +# this commands starts the experience on the compsuite dataset copied at "/home/gus/Datasets/compsuite3", and limits it to just the project id "i-3" +# note that the compsuite dataset folder layout is our own format, and omitting "i-3" will run the entire experience on every project. +java -jar ./Maestro/build/libs/com.github.gilesi.maestro.jar "/home/gus/Datasets/compsuite3" "$PWD" "i-3" + +# list of configurable hardocded options scattered throughout the entire project: +# Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +# TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java \ No newline at end of file From ba5782e9cf0c7c218db701fb5aecb7c2b905a61c Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 2 Sep 2024 08:46:07 +0200 Subject: [PATCH 194/244] Remove restrictions on project ids --- .../gilesi/maestro/compsuite/CompSuite.java | 55 ------------------- 1 file changed, 55 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index df8ed704..5e80923e 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -72,61 +72,6 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui continue; } - // Heap - if (incompatibility.id.equals("i-23")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - - // Assert - if (incompatibility.id.equals("i-1")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - - // Exception loop during testing - if (incompatibility.id.equals("i-6")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - - // Assert - if (incompatibility.id.equals("i-19")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - - // Assert v2 - if (incompatibility.id.equals("i-22")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - - // Hangs and never finishes - if (incompatibility.id.equals("i-41")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - continue; - } - - // Hangs and never finishes - if (incompatibility.id.equals("i-45")) { - runResult.ProjectCannotBeInstrumented = true; - Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); - runResults.add(runResult); - continue; - } - String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); if (!incompatibility.test_cmd.equals("N/A")) { testCmd = incompatibility.test_cmd; From 5f943f58992f99ba598016f135a00a2e401a2f6b Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 4 Sep 2024 17:50:10 +0200 Subject: [PATCH 195/244] Store both the old and new test project versions --- .../com/github/gilesi/maestro/FileUtils.java | 47 +++++- .../gilesi/maestro/compsuite/CompSuite.java | 157 ++++++++++++------ 2 files changed, 150 insertions(+), 54 deletions(-) diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java b/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java index b4d1f367..8b134433 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/FileUtils.java @@ -1,7 +1,6 @@ package com.github.gilesi.maestro; -import java.io.File; -import java.io.IOException; +import java.io.*; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -84,4 +83,48 @@ public static void restoreFile(String fileLocation) throws IOException { Files.move(backupFilePath, filePath); } + + public static void copyFolder(File source, File destination) { + if (source.isDirectory()) { + if (!destination.exists()) { + destination.mkdirs(); + } + + String[] files = source.list(); + + for (String file : files) { + File srcFile = new File(source, file); + File destFile = new File(destination, file); + + copyFolder(srcFile, destFile); + } + } else { + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(source); + out = new FileOutputStream(destination); + + byte[] buffer = new byte[1024]; + + int length; + while ((length = in.read(buffer)) > 0) { + out.write(buffer, 0, length); + } + } catch (Exception e) { + try { + in.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + try { + out.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 5e80923e..1f51f2b5 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -13,6 +13,7 @@ import java.io.File; import java.io.IOException; +import java.nio.file.CopyOption; import java.nio.file.Files; import java.nio.file.Path; import java.util.ArrayList; @@ -48,6 +49,11 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui List runResults = new ArrayList<>(); for (CompSuiteIncompatibility incompatibility : incompatibilities) { + + /*if (Integer.parseInt(incompatibility.id.substring(2)) < 45) { + continue; + }*/ + if (projectId != null && !projectId.equals(incompatibility.id)) { continue; } @@ -72,6 +78,61 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui continue; } + // Heap + if (incompatibility.id.equals("i-23")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert + /*if (incompatibility.id.equals("i-1")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Exception loop during testing + if (incompatibility.id.equals("i-6")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert + if (incompatibility.id.equals("i-19")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert v2 + if (incompatibility.id.equals("i-22")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Hangs and never finishes + if (incompatibility.id.equals("i-41")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + }*/ + + // Hangs and never finishes + if (incompatibility.id.equals("i-45")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); if (!incompatibility.test_cmd.equals("N/A")) { testCmd = incompatibility.test_cmd; @@ -233,11 +294,14 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); Path generatedTracesFolderPath = generatedFolderPath.resolve("traces"); - Path generatedCodeFolderPath = generatedFolderPath.resolve("tests"); + Path generatedOldCodeFolderPath = generatedFolderPath.resolve("tests-old"); + Path generatedNewCodeFolderPath = generatedFolderPath.resolve("tests-new"); Path generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); - FileUtils.deleteDirectoryIfExists(generatedCodeFolderPath.toString()); - Files.createDirectories(generatedCodeFolderPath); + FileUtils.deleteDirectoryIfExists(generatedOldCodeFolderPath.toString()); + FileUtils.deleteDirectoryIfExists(generatedNewCodeFolderPath.toString()); + Files.createDirectories(generatedOldCodeFolderPath); + Files.createDirectories(generatedNewCodeFolderPath); String dependencyName = incompatibility.lib; String dependencyVersion = incompatibility.old; @@ -260,21 +324,23 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); - TestGen.runTestGen(GilesiRepositoryLocation, generatedTracesFolderPath.toString(), generatedCodeFolderPath.resolve("src").resolve("test").resolve("java").toString(), libraryConfig.toString()); + TestGen.runTestGen(GilesiRepositoryLocation, generatedTracesFolderPath.toString(), generatedOldCodeFolderPath.resolve("src").resolve("test").resolve("java").toString(), libraryConfig.toString()); - boolean hadGenerationFailures = !FileUtils.enumerateFiles(generatedCodeFolderPath.toString(), ".*\\.marker", true).isEmpty(); + boolean hadGenerationFailures = !FileUtils.enumerateFiles(generatedOldCodeFolderPath.toString(), ".*\\.marker", true).isEmpty(); if (hadGenerationFailures) { runResult.ProjectIsMissingSpecificTraces = true; Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS MISSING SPECIFIC TRACE FILES: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); } - boolean generatedTestSrc = !FileUtils.enumerateFiles(generatedCodeFolderPath.toString(), ".*\\.java", true).isEmpty(); + boolean generatedTestSrc = !FileUtils.enumerateFiles(generatedOldCodeFolderPath.toString(), ".*\\.java", true).isEmpty(); if (!generatedTestSrc) { runResult.ProjectFailedToGenerateAnyTraceTestSrc = true; Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO GENERATE TEST SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); return; } + FileUtils.copyFolder(generatedOldCodeFolderPath.toFile(), generatedNewCodeFolderPath.toFile()); + String clientLocation = oldDestinationProjectPath.toString(); // Modify Client Build System to use the instrumentation agent @@ -288,29 +354,29 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina lastMinuteCleanup(allProjectFiles); // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion - String buildGradleProjectFile = generateGradleBuildFile(dependencyName, dependencyVersion); + String buildOldGradleProjectFile = generateGradleBuildFile(dependencyName, dependencyVersion); - Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); - Files.deleteIfExists(generatedCodeFolderPath.resolve("gradlew")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), generatedCodeFolderPath.resolve("gradlew")); + Files.writeString(generatedOldCodeFolderPath.resolve("build.gradle"), buildOldGradleProjectFile); + Files.deleteIfExists(generatedOldCodeFolderPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), generatedOldCodeFolderPath.resolve("gradlew")); - Files.deleteIfExists(generatedCodeFolderPath.resolve("gradlew.bat")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), generatedCodeFolderPath.resolve("gradlew.bat")); + Files.deleteIfExists(generatedOldCodeFolderPath.resolve("gradlew.bat")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), generatedOldCodeFolderPath.resolve("gradlew.bat")); - FileUtils.deleteDirectoryIfExists(generatedCodeFolderPath.resolve("gradle").toString()); - Files.createDirectories(generatedCodeFolderPath.resolve("gradle").resolve("wrapper")); + FileUtils.deleteDirectoryIfExists(generatedOldCodeFolderPath.resolve("gradle").toString()); + Files.createDirectories(generatedOldCodeFolderPath.resolve("gradle").resolve("wrapper")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar")); - Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties"), generatedCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar"), generatedOldCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties"), generatedOldCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties")); int returnCode = ProcessUtils.runExternalCommand(new String[]{ "/usr/bin/env", "bash", - "%s/gradlew".formatted(generatedCodeFolderPath), + "%s/gradlew".formatted(generatedOldCodeFolderPath), "compileTestJava", "--warning-mode", "all" - }, generatedCodeFolderPath.toFile(), Main.logger); + }, generatedOldCodeFolderPath.toFile(), Main.logger); runResult.ProjectFailedToCompileGeneratedTests = returnCode != 0; @@ -322,52 +388,39 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina returnCode = ProcessUtils.runExternalCommand(new String[]{ "/usr/bin/env", "bash", - "%s/gradlew".formatted(generatedCodeFolderPath), + "%s/gradlew".formatted(generatedOldCodeFolderPath), "test", "--warning-mode", "all" - }, generatedCodeFolderPath.toFile(), Main.logger); + }, generatedOldCodeFolderPath.toFile(), Main.logger); runResult.ProjectFailedToExecuteGeneratedTests = returnCode != 0; - runResult.TestExecutionReportWithOldVersion = GradleHarness.getProjectTestReports(dependencyName, dependencyVersion, generatedCodeFolderPath.resolve("build.gradle").toString()); + runResult.TestExecutionReportWithOldVersion = GradleHarness.getProjectTestReports(dependencyName, dependencyVersion, generatedOldCodeFolderPath.resolve("build.gradle").toString()); - Files.delete(generatedCodeFolderPath.resolve("build.gradle")); + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + String buildNewGradleProjectFile = generateGradleBuildFile(dependencyName, incompatibility._new); - buildGradleProjectFile = """ - plugins { - id 'java' - } - - group = 'testProject' - version = '1.0-SNAPSHOT' - - repositories { - mavenCentral() - mavenLocal() - } - - dependencies { - testImplementation '%s:%s' - testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' - testImplementation platform('org.junit:junit-bom:5.10.0') - testImplementation 'org.junit.jupiter:junit-jupiter' - } - - test { - useJUnitPlatform() - jvmArgs = ["--add-opens=java.base/java.util=ALL-UNNAMED"] - }""".formatted(dependencyName, incompatibility._new); + Files.writeString(generatedNewCodeFolderPath.resolve("build.gradle"), buildNewGradleProjectFile); + Files.deleteIfExists(generatedNewCodeFolderPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew"), generatedNewCodeFolderPath.resolve("gradlew")); + + Files.deleteIfExists(generatedNewCodeFolderPath.resolve("gradlew.bat")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradlew.bat"), generatedNewCodeFolderPath.resolve("gradlew.bat")); + + FileUtils.deleteDirectoryIfExists(generatedNewCodeFolderPath.resolve("gradle").toString()); + Files.createDirectories(generatedNewCodeFolderPath.resolve("gradle").resolve("wrapper")); - Files.writeString(generatedCodeFolderPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar"), generatedNewCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.jar")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Maestro").resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties"), generatedNewCodeFolderPath.resolve("gradle").resolve("wrapper").resolve("gradle-wrapper.properties")); returnCode = ProcessUtils.runExternalCommand(new String[]{ "/usr/bin/env", "bash", - "%s/gradlew".formatted(generatedCodeFolderPath), + "%s/gradlew".formatted(generatedNewCodeFolderPath), "compileTestJava", "--warning-mode", "all" - }, generatedCodeFolderPath.toFile(), Main.logger); + }, generatedNewCodeFolderPath.toFile(), Main.logger); runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion = returnCode != 0; @@ -379,14 +432,14 @@ testImplementation platform('org.junit:junit-bom:5.10.0') returnCode = ProcessUtils.runExternalCommand(new String[]{ "/usr/bin/env", "bash", - "%s/gradlew".formatted(generatedCodeFolderPath), + "%s/gradlew".formatted(generatedNewCodeFolderPath), "test", "--warning-mode", "all" - }, generatedCodeFolderPath.toFile(), Main.logger); + }, generatedNewCodeFolderPath.toFile(), Main.logger); runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion = returnCode != 0; - runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedCodeFolderPath.resolve("build.gradle").toString()); + runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedNewCodeFolderPath.resolve("build.gradle").toString()); } }, projectToRunOn); } From b91bcbd71997cc2fbbbdc2f213e93b055ff2f883 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Wed, 4 Sep 2024 17:55:50 +0200 Subject: [PATCH 196/244] Test only variable data creation --- .../java/com/github/gilesi/testgenerator/TraceUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index afd6a5bf..f5ee2d0f 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -231,7 +231,7 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, StringBuilder stringBuilder) throws SerializationException { - String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + /*String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); InstanceReference instanceData = trace.getInstanceReference(); @@ -239,7 +239,7 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var String instanceVariableName = ""; if (instanceData != null) { instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); - } + }*/ ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); @@ -247,7 +247,7 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var stringBuilder.append(String.format("%s\n", str)); } - boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + /*boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); boolean success = true; @@ -274,6 +274,6 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var stringBuilder.append(String.format("// %s\n", varAssert)); } } - } + }*/ } } \ No newline at end of file From be70814e4e7f0f40eb7da5c87ad41dba16be4ec9 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 9 Sep 2024 11:05:19 +0200 Subject: [PATCH 197/244] Fork TestGen to create TraceDiff --- .../com/github/gilesi/maestro/Constants.java | 1 + .../java/com/github/gilesi/maestro/Main.java | 6 +- .../gilesi/maestro/compsuite/CompSuite.java | 281 +++++++++++++++++- .../maestro/compsuite/CompSuiteFixes.java | 32 +- .../maestro/compsuite/CompSuiteRunnable.java | 2 + SampleRun.sh | 2 +- .../TestWorkflowConfiguration.xml | 204 ------------- TraceDiff/.gitignore | 39 +++ TraceDiff/build.gradle | 77 +++++ TraceDiff/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + TraceDiff/gradlew | 246 +++++++++++++++ TraceDiff/gradlew.bat | 91 ++++++ .../github/gilesi/confgen/models/Class.java | 7 + .../models/InstrumentationParameters.java | 7 + .../github/gilesi/confgen/models/Method.java | 6 + .../instrumentation/ConfigurationReader.java | 12 + .../gilesi/instrumentation/XmlUtils.java | 51 ++++ .../models/ClassReference.java | 44 +++ .../models/GenericReference.java | 26 ++ .../models/InstanceReference.java | 49 +++ .../models/MethodReference.java | 62 ++++ .../instrumentation/models/PartialTrace.java | 57 ++++ .../models/TestTraceResults.java | 6 + .../gilesi/instrumentation/models/Trace.java | 96 ++++++ .../github/gilesi/tracediff/ClassUtils.java | 25 ++ .../gilesi/tracediff/DescriptorUtils.java | 129 ++++++++ .../com/github/gilesi/tracediff/Main.java | 74 +++++ .../github/gilesi/tracediff/TraceReader.java | 48 +++ .../github/gilesi/tracediff/TraceUtils.java | 165 ++++++++++ .../tracediff/VariableStackHandler.java | 25 ++ .../exceptions/SerializationException.java | 7 + ...UnsupportedJavaPrimitiveTypeException.java | 7 + .../review/ArgLineGenerateResult.java | 15 + .../tracediff/review/ArgumentUtils.java | 192 ++++++++++++ .../tracediff/review/SerializationUtils.java | 157 ++++++++++ compile.cmd | 12 + compile.sh | 12 + run-clean-workflow.cmd | 4 + run-clean-workflow.sh | 4 + run-test-workflow.cmd | 10 +- run-test-workflow.sh | 10 +- 42 files changed, 2092 insertions(+), 215 deletions(-) delete mode 100644 Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml create mode 100644 TraceDiff/.gitignore create mode 100644 TraceDiff/build.gradle create mode 100644 TraceDiff/gradle/wrapper/gradle-wrapper.jar create mode 100644 TraceDiff/gradle/wrapper/gradle-wrapper.properties create mode 100644 TraceDiff/gradlew create mode 100644 TraceDiff/gradlew.bat create mode 100644 TraceDiff/src/main/java/com/github/gilesi/confgen/models/Class.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/confgen/models/Method.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/Trace.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/ClassUtils.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/DescriptorUtils.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/Main.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceReader.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceUtils.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/VariableStackHandler.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/SerializationException.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/UnsupportedJavaPrimitiveTypeException.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgLineGenerateResult.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgumentUtils.java create mode 100644 TraceDiff/src/main/java/com/github/gilesi/tracediff/review/SerializationUtils.java diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java index ba75d772..d8ad8427 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Constants.java @@ -7,6 +7,7 @@ public class Constants { // These paths should already exist on the end user machine for now and never change public static final String CONF_GEN_LOCATION = "/ConfGen/build/libs/com.github.gilesi.confgen.jar"; public static final String TEST_GEN_LOCATION = "/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; + public static final String TRACE_DIFF_LOCATION = "/TraceDiff/build/libs/com.github.gilesi.tracediff.jar"; public static final String INSTRUMENTATION_LOCATION = "/Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64"; diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java index 09d70f57..91517c96 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/Main.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/Main.java @@ -52,7 +52,9 @@ public static void main(String[] args) throws MavenInvocationException, XmlPullP String dataset = String.format("%s/incompatibilities.json", datasetOutput); - //CompSuiteFixes.copySourcesForDataset(dataset, datasetOutput); - CompSuite.runOnDataset(GilesiRepositoryLocation, dataset, datasetOutput, projectToRunOn); + //CompSuiteFixes.copyOldSourcesForDataset(dataset, datasetOutput); + CompSuiteFixes.copyNewSourcesForDataset(dataset, datasetOutput); + //CompSuite.runOldOnDataset(GilesiRepositoryLocation, dataset, datasetOutput, projectToRunOn); + CompSuite.runNewOnDataset(GilesiRepositoryLocation, dataset, datasetOutput, projectToRunOn); } } \ No newline at end of file diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java index 1f51f2b5..b9855da5 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuite.java @@ -223,6 +223,188 @@ public static void runOldOnDataset(String dataset, String datasetOutput, CompSui } } + public static void runNewOnDataset(String dataset, String datasetOutput, CompSuiteRunnable actionInterface, String projectId) throws IOException, MavenInvocationException, InterruptedException { + CompSuiteIncompatibility[] incompatibilities = readDataset(dataset); + + Path datasetOutputPath = Path.of(datasetOutput); + + List runResults = new ArrayList<>(); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + + /*if (Integer.parseInt(incompatibility.id.substring(2)) < 45) { + continue; + }*/ + + if (projectId != null && !projectId.equals(incompatibility.id)) { + continue; + } + + printIncompatibility(incompatibility); + + RunResult runResult = new RunResult(); + runResult.ProjectId = incompatibility.id; + + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("new"); + + if (!incompatibility.submodule.equals("N/A")) { + newDestinationProjectPath = newDestinationProjectPath.resolve(incompatibility.submodule); + } + + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + String libraryLocation = incompatibilityFolderPath.resolve("lib-new").toString(); + if (!Files.exists(Path.of(libraryLocation))) { + runResult.ProjectIsMissingLibrarySourceCode = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT HAS NO LIB SRC: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Heap + if (incompatibility.id.equals("i-23")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert + /*if (incompatibility.id.equals("i-1")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + }*/ + + // Exception loop during testing + if (incompatibility.id.equals("i-6")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert + /*if (incompatibility.id.equals("i-19")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Assert v2 + if (incompatibility.id.equals("i-22")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + // Hangs and never finishes + if (incompatibility.id.equals("i-41")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + continue; + }*/ + + // Hangs and never finishes + if (incompatibility.id.equals("i-45")) { + runResult.ProjectCannotBeInstrumented = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT IS SKIPPED: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + runResults.add(runResult); + continue; + } + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=%s".formatted(incompatibility.test); + if (!incompatibility.test_cmd.equals("N/A")) { + testCmd = incompatibility.test_cmd; + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + } + + TestAssertedLogger newTestAssertedLogger = new TestAssertedLogger(new Log4JLogger(incompatibility.id)); + + if (!Constants.SKIP_INSTRUMENTATION_RAN_ALREADY_FOR_DEBUGGING) { + String javaToolOptions = actionInterface.preRunNew(incompatibility, newDestinationProjectPath, testCmd); + if (javaToolOptions == null) { + continue; + } + + Main.logger.info("Testing new project"); + ProjectRunner.runMavenGoalOnRepository(newDestinationProjectPath.toString(), testCmd, null, "1.8", newTestAssertedLogger, javaToolOptions); + } + + actionInterface.postRunNew(incompatibility, newDestinationProjectPath, newTestAssertedLogger, runResult); + runResults.add(runResult); + } + + Main.logger.info("ProjectId,ProjectIsMissingLibrarySourceCode,ProjectCannotBeReproduced,ProjectCannotBeInstrumented,ProjectFailedToLoadAgent,ProjectIsMissingTraceFiles,ProjectIsMissingSpecificTraces,ProjectFailedToGenerateAnyTraceTestSrc,ProjectFailedToCompileGeneratedTests,ProjectFailedToExecuteGeneratedTests,ProjectFailedToCompileGeneratedTestsWithNewVersion,ProjectFailedToExecuteGeneratedTestsWithNewVersion"); + for (RunResult runResult : runResults) { + Main.logger.info("%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s,%s".formatted( + runResult.ProjectId, + runResult.ProjectIsMissingLibrarySourceCode, + runResult.ProjectCannotBeReproduced, + runResult.ProjectCannotBeInstrumented, + runResult.ProjectFailedToLoadAgent, + runResult.ProjectIsMissingTraceFiles, + runResult.ProjectIsMissingSpecificTraces, + runResult.ProjectFailedToGenerateAnyTraceTestSrc, + runResult.ProjectFailedToCompileGeneratedTests, + runResult.ProjectFailedToExecuteGeneratedTests, + runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion, + runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion)); + } + + for (RunResult runResult : runResults) { + Main.logger.info("-----------------------------------"); + Main.logger.info("Id: %s".formatted(runResult.ProjectId)); + Main.logger.info("IsMissingLibrarySourceCode: %s".formatted(runResult.ProjectIsMissingLibrarySourceCode)); + if (runResult.ProjectIsMissingLibrarySourceCode) + continue; + Main.logger.info("CannotBeReproduced: %s".formatted(runResult.ProjectCannotBeReproduced)); + if (runResult.ProjectCannotBeReproduced) + continue; + Main.logger.info("CannotBeInstrumented: %s".formatted(runResult.ProjectCannotBeInstrumented)); + if (runResult.ProjectCannotBeInstrumented) + continue; + Main.logger.info("FailedToLoadAgent: %s".formatted(runResult.ProjectFailedToLoadAgent)); + if (runResult.ProjectFailedToLoadAgent) + continue; + Main.logger.info("IsMissingTraceFiles: %s".formatted(runResult.ProjectIsMissingTraceFiles)); + if (runResult.ProjectIsMissingTraceFiles) + continue; + Main.logger.info("IsMissingSpecificTraces: %s".formatted(runResult.ProjectIsMissingSpecificTraces)); + Main.logger.info("FailedToGenerateAnyTraceTestSrc: %s".formatted(runResult.ProjectFailedToGenerateAnyTraceTestSrc)); + if (runResult.ProjectFailedToGenerateAnyTraceTestSrc) + continue; + + Main.logger.info("FailedToCompileGeneratedTests: %s".formatted(runResult.ProjectFailedToCompileGeneratedTests)); + if (runResult.ProjectFailedToCompileGeneratedTests) + continue; + + Main.logger.info("FailedToExecuteGeneratedTests: %s".formatted(runResult.ProjectFailedToExecuteGeneratedTests)); + Main.logger.info("FailedToCompileGeneratedTestsWithNewVersion: %s".formatted(runResult.ProjectFailedToCompileGeneratedTestsWithNewVersion)); + Main.logger.info("FailedToExecuteGeneratedTestsWithNewVersion: %s".formatted(runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion)); + Main.logger.info("TestExecutionReportWithOldVersion:"); + + if (runResult.TestExecutionReportWithOldVersion != null) { + for (ReportItem item : runResult.TestExecutionReportWithOldVersion) { + Main.logger.info("\"%s\",\"%s\",\"%s\",\"%s\"".formatted(item.Name, item.Version, item.getTestName(), item.getTestResult())); + } + } + + Main.logger.info("TestExecutionReportWithNewVersion:"); + if (runResult.TestExecutionReportWithNewVersion != null) { + for (ReportItem item : runResult.TestExecutionReportWithNewVersion) { + Main.logger.info("\"%s\",\"%s\",\"%s\",\"%s\"".formatted(item.Name, item.Version, item.getTestName(), item.getTestResult())); + } + } + + Main.logger.info("-----------------------------------"); + } + } + private static String generateGradleBuildFile(String dependencyName, String dependencyVersion) { return """ plugins { @@ -250,7 +432,7 @@ testImplementation platform('org.junit:junit-bom:5.10.0') }""".formatted(dependencyName, dependencyVersion); } - public static void runOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput, String projectToRunOn) throws IOException, MavenInvocationException, InterruptedException { + public static void runOldOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput, String projectToRunOn) throws IOException, MavenInvocationException, InterruptedException { Path datasetOutputPath = Path.of(datasetOutput); runOldOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { @@ -289,13 +471,18 @@ public String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestin return javaToolOptions; } + @Override + public String preRunNew(CompSuiteIncompatibility incompatibility, Path newDestinationProjectPath, String testCmd) throws IOException, InterruptedException { + return ""; + } + @Override public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException { Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); Path generatedFolderPath = incompatibilityFolderPath.resolve("generated"); Path generatedTracesFolderPath = generatedFolderPath.resolve("traces"); - Path generatedOldCodeFolderPath = generatedFolderPath.resolve("tests-old"); - Path generatedNewCodeFolderPath = generatedFolderPath.resolve("tests-new"); + Path generatedOldCodeFolderPath = generatedFolderPath.resolve("serializationtest-old"); + Path generatedNewCodeFolderPath = generatedFolderPath.resolve("serializationtest-new"); Path generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); FileUtils.deleteDirectoryIfExists(generatedOldCodeFolderPath.toString()); @@ -319,7 +506,7 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina return; } - String libraryLocation = incompatibilityFolderPath.resolve("lib-old").toString(); + /*String libraryLocation = incompatibilityFolderPath.resolve("lib-old").toString(); Path libraryLocationPath = Path.of(libraryLocation); Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); @@ -439,7 +626,91 @@ public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestina }, generatedNewCodeFolderPath.toFile(), Main.logger); runResult.ProjectFailedToExecuteGeneratedTestsWithNewVersion = returnCode != 0; - runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedNewCodeFolderPath.resolve("build.gradle").toString()); + runResult.TestExecutionReportWithNewVersion = GradleHarness.getProjectTestReports(dependencyName, incompatibility._new, generatedNewCodeFolderPath.resolve("build.gradle").toString());*/ + } + + @Override + public void postRunNew(CompSuiteIncompatibility incompatibility, Path newDestinationProjectPath, TestAssertedLogger newTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException { + + } + }, projectToRunOn); + } + + public static void runNewOnDataset(String GilesiRepositoryLocation, String dataset, String datasetOutput, String projectToRunOn) throws IOException, MavenInvocationException, InterruptedException { + Path datasetOutputPath = Path.of(datasetOutput); + + runNewOnDataset(dataset, datasetOutput, new CompSuiteRunnable() { + @Override + public String preRunNew(CompSuiteIncompatibility incompatibility, Path newDestinationProjectPath, String testCmd) throws IOException, InterruptedException { + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + String libraryLocation = incompatibilityFolderPath.resolve("lib-new").toString(); + Path generatedFolderPath = incompatibilityFolderPath.resolve("new-generated"); + String clientLocation = newDestinationProjectPath.toString(); + + FileUtils.deleteDirectoryIfExists(generatedFolderPath.toString()); + + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), generatedFolderPath.toString(), libraryLocation); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + String javaToolOptions = "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, libraryConfig.toString()); + + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + return javaToolOptions; + } + + @Override + public String preRunOld(CompSuiteIncompatibility incompatibility, Path newDestinationProjectPath, String testCmd) throws IOException, InterruptedException { + return ""; + } + + @Override + public void postRunNew(CompSuiteIncompatibility incompatibility, Path newDestinationProjectPath, TestAssertedLogger newTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException { + Path incompatibilityFolderPath = datasetOutputPath.resolve(incompatibility.id); + Path generatedFolderPath = incompatibilityFolderPath.resolve("new-generated"); + Path generatedTracesFolderPath = generatedFolderPath.resolve("traces"); + Path generatedOldCodeFolderPath = generatedFolderPath.resolve("serializationtest-old"); + Path generatedNewCodeFolderPath = generatedFolderPath.resolve("serializationtest-new"); + Path generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); + + FileUtils.deleteDirectoryIfExists(generatedOldCodeFolderPath.toString()); + FileUtils.deleteDirectoryIfExists(generatedNewCodeFolderPath.toString()); + Files.createDirectories(generatedOldCodeFolderPath); + Files.createDirectories(generatedNewCodeFolderPath); + + if (!Files.exists(generatedMarkersFolderPath.resolve("gilesi.instrumentation_loaded_1.marker"))) { + runResult.ProjectFailedToLoadAgent = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO LOAD OUR AGENT: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + + boolean generatedTestTraces = !FileUtils.enumerateFiles(generatedTracesFolderPath.toString(), ".*\\.json", true).isEmpty(); + if (!generatedTestTraces) { + runResult.ProjectIsMissingTraceFiles = true; + Main.logger.info("+++++++++++++++++++++++++ PROJECT FAILED TO GENERATE TEST TRACES: " + incompatibility.id + " ++++++++++++++++++++++++++++++++"); + return; + } + } + + @Override + public void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException { + } }, projectToRunOn); } diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java index f8fdcc99..4a228d21 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteFixes.java @@ -10,7 +10,7 @@ import java.util.ArrayList; public class CompSuiteFixes { - public static void copySourcesForDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { + public static void copyOldSourcesForDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { CompSuiteIncompatibility[] incompatibilities = CompSuite.readDataset(dataset); Path datasetOutputPath = Path.of(datasetOutput); @@ -40,6 +40,36 @@ public static void copySourcesForDataset(String dataset, String datasetOutput) t } } + public static void copyNewSourcesForDataset(String dataset, String datasetOutput) throws IOException, MavenInvocationException { + CompSuiteIncompatibility[] incompatibilities = CompSuite.readDataset(dataset); + + Path datasetOutputPath = Path.of(datasetOutput); + + for (CompSuiteIncompatibility incompatibility : incompatibilities) { + String mavenRepoPath = "%s/%s/%s".formatted(incompatibility.lib.split(":")[0].replace(".", "/"), incompatibility.lib.split(":")[1], incompatibility._new); + Path fileSystemRepoPath = Path.of("/home/gus/.m2/repository/" + mavenRepoPath); + + CompSuite.printIncompatibility(incompatibility); + + ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); + + if (srcCandidates.size() == 0) { + Main.logger.info("%s Missing sources for lib, aborting!".formatted(incompatibility.id)); + continue; + } + + Path newDestinationProjectPath = datasetOutputPath.resolve(incompatibility.id).resolve("lib-new"); + FileUtils.deleteDirectoryIfExists(newDestinationProjectPath.toString()); + Files.createDirectories(newDestinationProjectPath); + + for (String cand : srcCandidates) { + //Files.copy(Path.of(cand), newDestinationProjectPath); + System.out.println("Extracting " + cand); + extractJar(cand, newDestinationProjectPath.toString()); + } + } + } + public static void extractJar(String jar, String destdir) throws java.io.IOException { java.util.jar.JarFile jarfile = new java.util.jar.JarFile(new java.io.File(jar)); java.util.Enumeration enu = jarfile.entries(); diff --git a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java index 51f96ee8..0f44ce56 100644 --- a/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java +++ b/Maestro/src/main/java/com/github/gilesi/maestro/compsuite/CompSuiteRunnable.java @@ -9,4 +9,6 @@ public interface CompSuiteRunnable { String preRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException; void postRunOld(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException; + String preRunNew(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, String testCmd) throws IOException, InterruptedException; + void postRunNew(CompSuiteIncompatibility incompatibility, Path oldDestinationProjectPath, TestAssertedLogger oldTestAssertedLogger, RunResult runResult) throws IOException, InterruptedException; } diff --git a/SampleRun.sh b/SampleRun.sh index 7af5167d..89986105 100755 --- a/SampleRun.sh +++ b/SampleRun.sh @@ -9,7 +9,7 @@ export MAVEN_HOME="/snap/intellij-idea-ultimate/current/plugins/maven/lib/maven3 # then run maestro for sample usage # this commands starts the experience on the compsuite dataset copied at "/home/gus/Datasets/compsuite3", and limits it to just the project id "i-3" # note that the compsuite dataset folder layout is our own format, and omitting "i-3" will run the entire experience on every project. -java -jar ./Maestro/build/libs/com.github.gilesi.maestro.jar "/home/gus/Datasets/compsuite3" "$PWD" "i-3" +java -jar ./Maestro/build/libs/com.github.gilesi.maestro.jar "/home/gus/Datasets/compsuite3" "$PWD" # list of configurable hardocded options scattered throughout the entire project: # Maestro/src/main/java/com/github/gilesi/maestro/Constants.java diff --git a/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml b/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml deleted file mode 100644 index 718e18af..00000000 --- a/Samples/Gradle/sampleclient/TestWorkflowConfiguration.xml +++ /dev/null @@ -1,204 +0,0 @@ - - - - com.github.gilesi.samples.samplelibrary.Foo2 - - - triuetyg - - (I)Ljava/lang/String; - - - - TESTING - - (Ljava/lang/String;)Ljava/lang/String; - - - - sayHelloFoo - - ()Ljava/lang/String; - - - - hello - - (Ljava/lang/String;)V - ()Ljava/lang/String; - - - - njrhbgtujhu - - (Ljava/util/Collection;)Ljava/lang/String; - - - - hellow - - (Ljava/lang/String;)Ljava/lang/String; - - - - jhgbjtjbh - - ([Ljava/lang/String;)Ljava/lang/String; - - - - - (Ljava/lang/String;)V - - - - com.github.gilesi.samples.samplelibrary.A2 - - - getOurselves - - ()Lcom/github/gilesi/samples/samplelibrary/A2; - - - - foo - - (I)I - - - - sideEffect - - ()V - - - - - (I)V - - - - com.github.gilesi.samples.samplelibrary.Foo - - - HelloEveryone2 - - (Ljava/util/Collection;)Ljava/lang/String; - - - - TESTING - - (Ljava/lang/String;)Ljava/lang/String; - - - - meaningof - - (I)Ljava/lang/String; - - - - sayHelloFoo - - ()Ljava/lang/String; - - - - hello - - (Ljava/lang/String;)V - ()Ljava/lang/String; - - - - hellow - - (Ljava/lang/String;)Ljava/lang/String; - - - - HelloEveryone - - ([Ljava/lang/String;)Ljava/lang/String; - - - - - (Ljava/lang/String;)V - - - - com.github.gilesi.samples.samplelibrary.A - - - CallBack - - (Lcom/github/gilesi/samples/samplelibrary/IDoSomething;)V - - - - foo - - (I)I - - - - - (I)V - - - - - CTest.ClientATest - CTest.Test - FooTest.TestFoo - FooTest.TestFooIsLifeNice - FooTest.mainTest - com.github.gilesi.samples.sampleclient.C1.Do - com.github.gilesi.samples.sampleclient.C2.bar - com.github.gilesi.samples.sampleclient.Main.DoWork - com.github.gilesi.samples.sampleclient.Main.main - com.github.gilesi.samples.sampleclient.Main2.main - - - CTest.CTest - FooTest.FooTest - com.github.gilesi.samples.sampleclient.C1.C1 - com.github.gilesi.samples.sampleclient.C2.C2 - com.github.gilesi.samples.sampleclient.Main.Main - com.github.gilesi.samples.sampleclient.Main2.Main2 - - - com.github.gilesi.samples.samplelibrary.A.CallBack - com.github.gilesi.samples.samplelibrary.A.foo - com.github.gilesi.samples.samplelibrary.A2.foo - com.github.gilesi.samples.samplelibrary.A2.getOurselves - com.github.gilesi.samples.samplelibrary.A2.sideEffect - com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone - com.github.gilesi.samples.samplelibrary.Foo.HelloEveryone2 - com.github.gilesi.samples.samplelibrary.Foo.TESTING - com.github.gilesi.samples.samplelibrary.Foo.hello - com.github.gilesi.samples.samplelibrary.Foo.hello - com.github.gilesi.samples.samplelibrary.Foo.hellow - com.github.gilesi.samples.samplelibrary.Foo.meaningof - com.github.gilesi.samples.samplelibrary.Foo.sayHelloFoo - com.github.gilesi.samples.samplelibrary.Foo2.TESTING - com.github.gilesi.samples.samplelibrary.Foo2.hello - com.github.gilesi.samples.samplelibrary.Foo2.hello - com.github.gilesi.samples.samplelibrary.Foo2.hellow - com.github.gilesi.samples.samplelibrary.Foo2.jhgbjtjbh - com.github.gilesi.samples.samplelibrary.Foo2.njrhbgtujhu - com.github.gilesi.samples.samplelibrary.Foo2.sayHelloFoo - com.github.gilesi.samples.samplelibrary.Foo2.triuetyg - com.github.gilesi.samples.samplelibrary.IDoSomething.Do - - - com.github.gilesi.samples.samplelibrary.A.A - com.github.gilesi.samples.samplelibrary.A2.A2 - com.github.gilesi.samples.samplelibrary.Foo.Foo - com.github.gilesi.samples.samplelibrary.Foo2.Foo2 - com.github.gilesi.samples.samplelibrary.IDoSomething.IDoSomething - - /home/gus/Git/gilesi/Results - \ No newline at end of file diff --git a/TraceDiff/.gitignore b/TraceDiff/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/TraceDiff/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/TraceDiff/build.gradle b/TraceDiff/build.gradle new file mode 100644 index 00000000..73086aa8 --- /dev/null +++ b/TraceDiff/build.gradle @@ -0,0 +1,77 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'com.github.gilesi.tracediff' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() + mavenLocal() + maven { + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.14.0' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.14.0' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.14.0' + implementation 'com.fasterxml.jackson:jackson-base:2.14.0' + implementation 'org.apache.commons:commons-text:1.11.0' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' +} + +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.tracediff.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.tracediff.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.tracediff') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.tracediff' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=2G" + ] +} \ No newline at end of file diff --git a/TraceDiff/gradle/wrapper/gradle-wrapper.jar b/TraceDiff/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/TraceDiff/gradlew.bat b/TraceDiff/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/TraceDiff/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Class.java b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Class.java new file mode 100644 index 00000000..d8e63389 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Class.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgen.models; + +public class Class { + public String ClassName; + public Method[] ClassMethods; + public String[] ClassDescriptors; +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java new file mode 100644 index 00000000..2fa9ceac --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/InstrumentationParameters.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgen.models; + +public class InstrumentationParameters { + public Class[] InstrumentedAPIClasses; + public String[] LibraryTypes; + public String traceOutputLocation; +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Method.java b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Method.java new file mode 100644 index 00000000..8ef6c1e1 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/confgen/models/Method.java @@ -0,0 +1,6 @@ +package com.github.gilesi.confgen.models; + +public class Method { + public String MethodName; + public String[] MethodDescriptors; +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java new file mode 100644 index 00000000..27f4c5ae --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/ConfigurationReader.java @@ -0,0 +1,12 @@ +package com.github.gilesi.instrumentation; + +import com.github.gilesi.confgen.models.InstrumentationParameters; + +import java.io.File; +import java.io.IOException; + +public class ConfigurationReader { + public static InstrumentationParameters parseInstrumentationparameters(File file) throws IOException { + return XmlUtils.objectMapper.readValue(file, InstrumentationParameters.class); + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java new file mode 100644 index 00000000..3b46a7f2 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/XmlUtils.java @@ -0,0 +1,51 @@ +package com.github.gilesi.instrumentation; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import java.io.File; +import java.io.FileWriter; +import java.nio.file.Files; +import java.nio.file.Paths; + +public class XmlUtils { + private static DomDriver domDriver = new DomDriver(); + private static XStream xStream = new XStream(domDriver); + private static Object syncObj = new Object(); + public static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + public static String getToXml(Object obj) { + return xStream.toXML(obj); + } + + public static String getToJson(Object obj) throws JsonProcessingException { + return objectMapper.writeValueAsString(obj); + } + + public static void saveToUniquePath(String basePath, String baseName, String baseExtension, String content) { + synchronized (syncObj) { + int padding = 1; + String finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, padding, baseExtension); + + while (Files.exists(Paths.get(finalFileName))) { + finalFileName = String.format("%s%s%s_%d.%s", basePath, File.separatorChar, baseName, ++padding, baseExtension); + } + + try { + FileWriter outputFile = new FileWriter(finalFileName); + outputFile.write(content); + outputFile.close(); + } catch (Throwable e) { + System.err.println("ERROR"); + e.printStackTrace(); + } + } + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java new file mode 100644 index 00000000..9e25ea02 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/ClassReference.java @@ -0,0 +1,44 @@ +package com.github.gilesi.instrumentation.models; + +public class ClassReference { + private String fullyQualifiedTypeName; + private ClassReference[] interfaces; + private ClassReference superClass; + private GenericReference[] genericParameters; + + public ClassReference() { + + } + + public String getFullyQualifiedTypeName() { + return fullyQualifiedTypeName; + } + + public ClassReference[] getInterfaces() { + return interfaces; + } + + public ClassReference getSuperClass() { + return superClass; + } + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + + public void setFullyQualifiedTypeName(String fullyQualifiedTypeName) { + this.fullyQualifiedTypeName = fullyQualifiedTypeName; + } + + public void setInterfaces(ClassReference[] interfaces) { + this.interfaces = interfaces; + } + + public void setSuperClass(ClassReference superClass) { + this.superClass = superClass; + } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java new file mode 100644 index 00000000..10eca61e --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/GenericReference.java @@ -0,0 +1,26 @@ +package com.github.gilesi.instrumentation.models; + +public class GenericReference { + private String name; + private ClassReference[] classBounds; + + public GenericReference() { + + } + + public String getName() { + return name; + } + + public void setName(String name) { + this.name = name; + } + + public ClassReference[] getClassBounds() { + return classBounds; + } + + public void getClassBounds(ClassReference[] classBounds) { + this.classBounds = classBounds; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java new file mode 100644 index 00000000..2170cc86 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/InstanceReference.java @@ -0,0 +1,49 @@ +package com.github.gilesi.instrumentation.models; + +public class InstanceReference { + private int instanceId = -1; + private String valueAsXmlString = null; + private String valueAsJsonString = null; + private boolean isNull = true; + private ClassReference classReference = null; + + public int getInstanceId() { + return instanceId; + } + + public String getValueAsXmlString() { + return valueAsXmlString; + } + + public String getValueAsJsonString() { + return valueAsJsonString; + } + + public boolean getIsNull() { + return isNull; + } + + public ClassReference getClassReference() { + return classReference; + } + + public void setInstanceId(int instanceId) { + this.instanceId = instanceId; + } + + public void setValueAsXmlString(String valueAsXmlString) { + this.valueAsXmlString = valueAsXmlString; + } + + public void setValueAsJsonString(String valueAsJsonString) { + this.valueAsJsonString = valueAsJsonString; + } + + public void setIsNull(boolean isNull) { + this.isNull = isNull; + } + + public void setClassReference(ClassReference classReference) { + this.classReference = classReference; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java new file mode 100644 index 00000000..94dc8eda --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/MethodReference.java @@ -0,0 +1,62 @@ +package com.github.gilesi.instrumentation.models; + +public class MethodReference { + private String methodSignature; + private ClassReference[] parameterTypes; + private ClassReference returnType; + private boolean isConstructor; + private GenericReference[] genericParameters; + private ClassReference genericReturn; + + public MethodReference() { + + } + + public String getMethodSignature() { + return methodSignature; + } + + public ClassReference[] getParameterTypes() { + return parameterTypes; + } + + public ClassReference getReturnType() { + return returnType; + } + + public boolean getIsConstructor() { + return isConstructor; + } + + public GenericReference[] getGenericParameters() { + return genericParameters; + } + + public ClassReference getGenericReturn() { + return genericReturn; + } + + public void setMethodSignature(String methodSignature) { + this.methodSignature = methodSignature; + } + + public void setParameterTypes(ClassReference[] parameterTypes) { + this.parameterTypes = parameterTypes; + } + + public void setReturnType(ClassReference returnType) { + this.returnType = returnType; + } + + public void setIsConstructor(boolean isConstructor) { + this.isConstructor = isConstructor; + } + + public void setGenericParameters(GenericReference[] genericParameters) { + this.genericParameters = genericParameters; + } + + public void setGenericReturn(ClassReference genericReturn) { + this.genericReturn = genericReturn; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java new file mode 100644 index 00000000..d2a7d482 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/PartialTrace.java @@ -0,0 +1,57 @@ +package com.github.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class PartialTrace { + private List preCallArguments; + private long timeStampEntry; + private InstanceReference instanceReference; + private MethodReference methodReference; + + @JsonCreator + public PartialTrace( + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { + this.preCallArguments = preCallArguments; + this.timeStampEntry = timeStampEntry; + this.instanceReference = instanceReference; + this.methodReference = methodReference; + } + + public List getPreCallArguments() { + return preCallArguments; + } + + public void setPreCallArguments(List preCallArguments) { + this.preCallArguments = preCallArguments; + } + + public long getTimeStampEntry() { + return timeStampEntry; + } + + public void setTimeStampEntry(long timeStampEntry) { + this.timeStampEntry = timeStampEntry; + } + + public InstanceReference getInstanceReference() { + return instanceReference; + } + + public MethodReference getMethodReference() { + return methodReference; + } + + public void setInstanceReference(InstanceReference instanceReference) { + this.instanceReference = instanceReference; + } + + public void setMethodReference(MethodReference methodReference) { + this.methodReference = methodReference; + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java new file mode 100644 index 00000000..e277a415 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/TestTraceResults.java @@ -0,0 +1,6 @@ +package com.github.gilesi.instrumentation.models; + +public class TestTraceResults { + public Trace Trace; + public String Test; +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/Trace.java b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/Trace.java new file mode 100644 index 00000000..9dee5a0a --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/instrumentation/models/Trace.java @@ -0,0 +1,96 @@ +package com.github.gilesi.instrumentation.models; + +import com.fasterxml.jackson.annotation.JsonCreator; +import com.fasterxml.jackson.annotation.JsonProperty; + +import java.util.List; + +public class Trace extends PartialTrace { + private List postCallArguments; + private InstanceReference returnedValue; + private long timeStampExit; + private InstanceReference exceptionThrown; + private String[] stackTrace; + private String confName; + private String[] confDescriptors; + + @JsonCreator + public Trace( + @JsonProperty("preCallArguments") List preCallArguments, + @JsonProperty("postCallArguments") List postCallArguments, + @JsonProperty("returnedValue") InstanceReference returnedValue, + @JsonProperty("timeStampEntry") long timeStampEntry, + @JsonProperty("timeStampExit") long timeStampExit, + @JsonProperty("exceptionThrown") InstanceReference exceptionThrown, + @JsonProperty("stackTrace") String[] stackTrace, + @JsonProperty("confName") String confName, + @JsonProperty("confDescriptors") String[] confDescriptors, + @JsonProperty("instanceReference") InstanceReference instanceReference, + @JsonProperty("methodReference") MethodReference methodReference) { + super(preCallArguments, timeStampEntry, instanceReference, methodReference); + + this.postCallArguments = postCallArguments; + this.returnedValue = returnedValue; + this.timeStampExit = timeStampExit; + this.exceptionThrown = exceptionThrown; + this.stackTrace = stackTrace; + this.confName = confName; + this.confDescriptors = confDescriptors; + } + + public List getPostCallArguments() { + return postCallArguments; + } + + public void setPostCallArguments(List postCallArguments) { + this.postCallArguments = postCallArguments; + } + + public InstanceReference getReturnedValue() { + return returnedValue; + } + + public void setReturnedValue(InstanceReference returnedValue) { + this.returnedValue = returnedValue; + } + + public long getTimeStampExit() { + return timeStampExit; + } + + public void setTimeStampExit(long timeStampExit) { + this.timeStampExit = timeStampExit; + } + + public InstanceReference getExceptionThrown() { + return exceptionThrown; + } + + public void setExceptionThrown(InstanceReference exceptionThrown) { + this.exceptionThrown = exceptionThrown; + } + + public String[] getStackTrace() { + return stackTrace; + } + + public void setStackTrace(String[] stackTrace) { + this.stackTrace = stackTrace; + } + + public String getConfName() { + return confName; + } + + public void setConfName(String confName) { + this.confName = confName; + } + + public String[] getConfDescriptors() { + return confDescriptors; + } + + public void setConfDescriptors(String[] confDescriptors) { + this.confDescriptors = confDescriptors; + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/ClassUtils.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/ClassUtils.java new file mode 100644 index 00000000..c0accac2 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/ClassUtils.java @@ -0,0 +1,25 @@ +package com.github.gilesi.tracediff; + +import java.io.IOException; +import java.util.ArrayList; + +import com.github.gilesi.instrumentation.models.Trace; + +public class ClassUtils { + public static void generateClassFile(ArrayList methodTraces, String testPath) throws IOException { + VariableStackHandler variableStackHandler = new VariableStackHandler(); + + for (int i = 0; i < methodTraces.size(); i++) { + System.out.println("Processing Trace %d out of %d".formatted(i + 1, methodTraces.size())); + + Trace trace = methodTraces.get(i); + + try { + TraceUtils.parseTrace(i, trace, variableStackHandler); + } catch (Exception e) { + System.out.println("Unable to convert trace to code!"); + e.printStackTrace(); + } + } + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/DescriptorUtils.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/DescriptorUtils.java new file mode 100644 index 00000000..ca75570e --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/DescriptorUtils.java @@ -0,0 +1,129 @@ +package com.github.gilesi.tracediff; + +import java.util.ArrayList; +import java.util.List; + +import com.github.gilesi.tracediff.exceptions.UnsupportedJavaPrimitiveTypeException; + +public class DescriptorUtils { + public static int getFirstArgLength(String name) throws UnsupportedJavaPrimitiveTypeException { + if (name.length() == 0) { + return 0; + } + + return switch (name.charAt(0)) { + case 'I' -> 1; + case 'V' -> 1; + case 'Z' -> 1; + case 'B' -> 1; + case 'C' -> 1; + case 'S' -> 1; + case 'D' -> 1; + case 'F' -> 1; + case 'J' -> 1; + case 'L' -> name.indexOf(";") + 1; + case '[' -> getFirstArgLength(name.substring(1)) + 1; + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static String getCleanedType(String FQN) { + int currentCharacterIndex = 0; + char currentCharacter = FQN.charAt(currentCharacterIndex); + while (currentCharacter == '[') { + currentCharacter = FQN.charAt(++currentCharacterIndex); + } + + if (((currentCharacter == 'I' || currentCharacter == 'V' || + currentCharacter == 'Z' || currentCharacter == 'B' || + currentCharacter == 'C' || currentCharacter == 'S' || + currentCharacter == 'D' || currentCharacter == 'F' || + currentCharacter == 'J') && FQN.length() == currentCharacterIndex + 1) || + (currentCharacter == 'L' && FQN.endsWith(";"))) { + try { + return JvmTypeToLangType(FQN).replace("$", "."); + } catch (UnsupportedJavaPrimitiveTypeException e) { + System.out.println(String.format("Unsupported Java Primitive Type Exception! %c", currentCharacter)); + e.printStackTrace(); + } + } + return FQN.replace("$", "."); + } + + private static String JvmTypeToLangType(String name) throws UnsupportedJavaPrimitiveTypeException { + return switch (name.charAt(0)) { + case 'I' -> "java.lang.Integer"; + case 'V' -> "java.lang.Void"; + case 'Z' -> "java.lang.Boolean"; + case 'B' -> "java.lang.Byte"; + case 'C' -> "java.lang.Character"; + case 'S' -> "java.lang.Short"; + case 'D' -> "java.lang.Double"; + case 'F' -> "java.lang.Float"; + case 'J' -> "java.lang.Long"; + case 'L' -> name.substring(1, name.length() - 1).replace("/", "."); + case '[' -> "%s[]".formatted(JvmTypeToLangType(name.substring(1))); + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + + public static void convertDescriptorToNormalTypesTest(String descr) throws UnsupportedJavaPrimitiveTypeException { + int startArg = descr.indexOf("("); + int endArg = descr.lastIndexOf(")"); + + String returns = descr.substring(endArg + 1, descr.length()); + String argusStr = descr.substring(startArg + 1, endArg); + + int length = 1; + List arguments = new ArrayList<>(); + String returnValue = null; + + do { + length = getFirstArgLength(argusStr); + String curArg = argusStr.substring(0, length); + argusStr = argusStr.substring(length); + if (curArg.length() != 0) { + arguments.add(getCleanedType(curArg)); + } + } while (length != 0); + + if (!returns.equals("V")) { + returnValue = getCleanedType(returns); + } + + System.out.println("Descriptor: " + descr); + + if (arguments.size() != 0) { + System.out.println("Arguments: (%s)".formatted(String.join(", ", arguments))); + } + + if (returnValue != null) { + System.out.println("Returns: " + returnValue); + } + } + + public static String getCleanedVar(String fullyQualifiedTypeName) { + String returnType = fullyQualifiedTypeName.replace("$", "."); + + try { + var el = returnType.split("\\."); + Integer.valueOf(el[el.length - 1]); + + // so this is a number, replace type with "var" as we have no idea. + returnType = "var"; + } catch (NumberFormatException e) { + // Not a number, continue + } + + if (returnType.contains("..")) { + // Bad type, use var + returnType = "var"; + } + + if (returnType.endsWith(".")) { + returnType = "var"; + } + + return returnType; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/Main.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/Main.java new file mode 100644 index 00000000..765f5528 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/Main.java @@ -0,0 +1,74 @@ +package com.github.gilesi.tracediff; + +import com.github.gilesi.confgen.models.InstrumentationParameters; +import com.github.gilesi.instrumentation.ConfigurationReader; +import com.github.gilesi.instrumentation.models.Trace; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.*; + +public class Main { + public static InstrumentationParameters instrumentationParameters; + + private static void processArguments(String[] args) throws IOException { + if (args.length != 3) { + System.out.println("Usage: "); + return; + } + + String traceXmlFolder = args[0]; + String testPath = args[1]; + String libraryConfigPath = args[2]; + + if (!Files.exists(Path.of(traceXmlFolder)) || !Files.isDirectory(Path.of(traceXmlFolder))) { + System.out.println( + "Argument 1 is not a Folder containing trace files. It either does not exist or is not a directory."); + return; + } + + Files.createDirectories(Path.of(testPath)); + + if (!Files.exists(Path.of(testPath)) || !Files.isDirectory(Path.of(testPath))) { + System.out.println( + "Argument 2 is not a path to contain generated java test code. It either does not exist or is not a directory."); + return; + } + + if (!Files.exists(Path.of(libraryConfigPath)) || Files.isDirectory(Path.of(libraryConfigPath))) { + System.out.println( + "Argument 3 is not a path to a library configuration. It either does not exist or is not a file."); + return; + } + + ArrayList methodTraces = TraceReader.readTraces(traceXmlFolder); + + if (methodTraces.isEmpty()) { + System.out.println("No traces found!"); + } + + // Get the parameters + File configurationFile = new File(libraryConfigPath); + if (!configurationFile.exists()) { + System.err.printf("ERROR: the passed in configuration file (%s) does not exist or could not be found!%n", libraryConfigPath); + return; + } + + try { + instrumentationParameters = ConfigurationReader.parseInstrumentationparameters(configurationFile); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not parse instrumentation configuration file (%s)!%n", libraryConfigPath); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + + ClassUtils.generateClassFile(methodTraces, testPath); + } + + public static void main(String[] args) throws IOException { + processArguments(args); + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceReader.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceReader.java new file mode 100644 index 00000000..9c39e883 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceReader.java @@ -0,0 +1,48 @@ +package com.github.gilesi.tracediff; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Comparator; +import java.util.List; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.instrumentation.models.TestTraceResults; +import com.github.gilesi.instrumentation.models.Trace; + +public class TraceReader { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + // .enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + // This is ugly, I know + private static int GetTraceNumber(Path i) { + return Integer.valueOf(i.getFileName().toString().split("_")[1].replace(".json", "")); + } + + public static ArrayList readTraces(String traceXmlFolder) throws IOException { + ArrayList traces = new ArrayList<>(); + + List traceFiles = Files.list(Path.of(traceXmlFolder)) + .sorted(Comparator.comparingInt(TraceReader::GetTraceNumber)).toList(); + + for (Path testTraceFile : traceFiles) { + try { + TestTraceResults testTraceResults = objectMapper.readValue(new File(testTraceFile.toString()), + TestTraceResults.class); + traces.add(testTraceResults.Trace); + } catch (Exception e) { + System.out.println("ERROR while deserializing a trace!"); + e.printStackTrace(); + } + } + + return traces; + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceUtils.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceUtils.java new file mode 100644 index 00000000..f269f9a5 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/TraceUtils.java @@ -0,0 +1,165 @@ +package com.github.gilesi.tracediff; + +import com.github.gilesi.instrumentation.models.ClassReference; +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.tracediff.review.ArgLineGenerateResult; +import com.github.gilesi.tracediff.review.ArgumentUtils; +import com.github.gilesi.tracediff.review.SerializationUtils; +import com.github.gilesi.tracediff.exceptions.SerializationException; + +public class TraceUtils { + private static void handleConstructor(VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, Trace trace) throws SerializationException { + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + if (argLineResultSuccess) { + variableStackHandler.CreateNewVariable(instanceData.getInstanceId(), methodName); + } + + instanceVariableName = String.format("%s %s", methodName, instanceVariableName); + } + } + + private static void handleMethod(int traceId, VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, Trace trace) throws SerializationException { + InstanceReference returnData = trace.getReturnedValue(); + + if (returnData != null) { + String returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); + int returnDataInstanceId = returnData.getInstanceId(); + + ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), + trace.getMethodReference().getReturnType()); + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + + if (!variableStackHandler.DoesVariableExist(returnDataInstanceId)) { + if (argLineResultSuccess) { + variableStackHandler.CreateNewVariable(returnDataInstanceId, returnType); + } else { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + traceId + 1, returnDataInstanceId); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + } + + returnVariableName = String.format("%s %s", returnType, returnVariableName); + } else { + String tmpReturnType = variableStackHandler.getVariableType(returnDataInstanceId); + if (!tmpReturnType.equals("var")) { + returnType = tmpReturnType; + } + } + } + } + + private static boolean handleMethodInstance(int traceId, VariableStackHandler variableStackHandler, + InstanceReference instanceData, String instanceVariableName, String methodName, String argumentLine, + boolean argLineResultSuccess, Trace trace) throws SerializationException { + InstanceReference returnData = trace.getReturnedValue(); + + // Holds whenever or not an issue with instances was found + // If true, we should not create new variables and we should comment out the + // whole code. + // As the code simply is not generable. + boolean issuesDetected = false; + + // When we have an instance dependent call, we need the instance the call is + // performed onto to exist + // If it does not exist, then we cannot generate this code + // Log that, and comment out the code we would have generated. + // And make sure we do not create a variable for the return value if a thing. + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call to %s cannot be generated because it depends on %d (%s) that does not already exist.", + traceId + 1, methodName, instanceData.getInstanceId(), + instanceData.getClassReference().getFullyQualifiedTypeName()); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + + issuesDetected = true; + } + + // An instance method call is not called by its fully qualified name (i.e. + // bar.man.foo() but by instanceidvar.foo()), format the method name correctly. + String instanceMethodCallName = methodName.split("\\.")[methodName.split("\\.").length - 1]; + if (!variableStackHandler.DoesVariableExist(instanceData.getInstanceId())) { + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } else { + String tmpInstanceType = variableStackHandler.getVariableType(instanceData.getInstanceId()); + if (!tmpInstanceType.equals("var")) { + // TODO: use the true api type here (we know this info... but lack it in the + // trace files currently...) + methodName = String.format("((%s)%s).%s", tmpInstanceType, instanceVariableName, + instanceMethodCallName); + } else { + methodName = String.format("%s.%s", instanceVariableName, instanceMethodCallName); + } + } + + if (returnData != null) { + String returnVariableName = VariableStackHandler.getVariableName(returnData.getInstanceId()); + int returnDataInstanceId = returnData.getInstanceId(); + + ClassReference compatibleClassReference = SerializationUtils.getBetterType(returnData.getClassReference(), + trace.getMethodReference().getReturnType()); + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + + if (!variableStackHandler.DoesVariableExist(returnDataInstanceId)) { + if (argLineResultSuccess && !issuesDetected) { + variableStackHandler.CreateNewVariable(returnDataInstanceId, returnType); + } else { + String warnMessage = String.format( + "[Trace ID: %d]: Instance Call would have created the now missing variable instance: %d.", + traceId + 1, returnDataInstanceId); + + // Log the warning to the current string builder and the console. + System.out.println(warnMessage); + } + + returnVariableName = String.format("%s %s", returnType, returnVariableName); + } else { + String tmpReturnType = variableStackHandler.getVariableType(returnDataInstanceId); + if (!tmpReturnType.equals("var")) { + returnType = tmpReturnType; + } + } + } + + return !issuesDetected; + } + + public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler) throws SerializationException { + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); + + InstanceReference instanceData = trace.getInstanceReference(); + + String instanceVariableName = ""; + if (instanceData != null) { + instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); + } + + ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); + + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); + + if (trace.getMethodReference().getIsConstructor()) { + handleConstructor(variableStackHandler, instanceData, instanceVariableName, methodName, + argLineResult.argumentsForMethodCall, argLineResult.Success, trace); + } else if (isInstanceCall) { + handleMethodInstance(traceId, variableStackHandler, instanceData, instanceVariableName, + methodName, argLineResult.argumentsForMethodCall, argLineResult.Success, trace); + } else { + handleMethod(traceId, variableStackHandler, instanceData, instanceVariableName, methodName, + argLineResult.argumentsForMethodCall, argLineResult.Success, trace); + } + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/VariableStackHandler.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/VariableStackHandler.java new file mode 100644 index 00000000..9879bb69 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/VariableStackHandler.java @@ -0,0 +1,25 @@ +package com.github.gilesi.tracediff; + +import java.util.HashMap; + +public class VariableStackHandler { + private HashMap variableInstances = new HashMap<>(); + + public void CreateNewVariable(int instanceId, String variableType) { + if (!DoesVariableExist(instanceId)) { + variableInstances.put(instanceId, variableType); + } + } + + public boolean DoesVariableExist(int instanceId) { + return variableInstances.containsKey(instanceId); + } + + public static String getVariableName(int instanceId) { + return String.format("var%d", instanceId); + } + + public String getVariableType(int instanceId) { + return variableInstances.get(instanceId); + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/SerializationException.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/SerializationException.java new file mode 100644 index 00000000..274c6689 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/SerializationException.java @@ -0,0 +1,7 @@ +package com.github.gilesi.tracediff.exceptions; + +public class SerializationException extends Exception { + public SerializationException(String message) { + super(message); + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/UnsupportedJavaPrimitiveTypeException.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/UnsupportedJavaPrimitiveTypeException.java new file mode 100644 index 00000000..3354b27f --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/exceptions/UnsupportedJavaPrimitiveTypeException.java @@ -0,0 +1,7 @@ +package com.github.gilesi.tracediff.exceptions; + +public class UnsupportedJavaPrimitiveTypeException extends Exception { + public UnsupportedJavaPrimitiveTypeException(String primitive) { + super("Unsupported primitive type: %s".formatted(primitive)); + } +} diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgLineGenerateResult.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgLineGenerateResult.java new file mode 100644 index 00000000..a763747f --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgLineGenerateResult.java @@ -0,0 +1,15 @@ +package com.github.gilesi.tracediff.review; + +import java.util.List; + +public class ArgLineGenerateResult { + public boolean Success; + public String argumentsForMethodCall; + public List variableList; + + public ArgLineGenerateResult(boolean Success, String argumentsForMethodCall, List variableList) { + this.Success = Success; + this.argumentsForMethodCall = argumentsForMethodCall; + this.variableList = variableList; + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgumentUtils.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgumentUtils.java new file mode 100644 index 00000000..0c3f20f5 --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/ArgumentUtils.java @@ -0,0 +1,192 @@ +package com.github.gilesi.tracediff.review; + +import java.util.ArrayList; +import java.util.List; + +import com.github.gilesi.instrumentation.models.ClassReference; +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.instrumentation.models.Trace; +import com.github.gilesi.tracediff.DescriptorUtils; +import com.github.gilesi.tracediff.VariableStackHandler; + +public class ArgumentUtils { + public static ArgLineGenerateResult GenerateArgLine(Trace trace, VariableStackHandler variableStackHandler) { + boolean Succeeded = true; + + List variableDeclarationList = new ArrayList<>(); + List preCallArguments = new ArrayList<>(); + + for (int i = 0; i < trace.getPreCallArguments().size(); i++) { + boolean localSucceeded = true; + String localArgumentType = ""; + int localArgumentInstanceId = 0; + boolean localAddArgument = false; + + InstanceReference preCallArgument = trace.getPreCallArguments().get(i); + + if (preCallArgument.getIsNull()) { + preCallArguments.add("null"); + continue; + } + + ClassReference correspondingMethodArg = trace.getMethodReference().getParameterTypes()[i]; + + String argFQN = DescriptorUtils.getCleanedType(correspondingMethodArg.getFullyQualifiedTypeName()); + String argReturnType = DescriptorUtils.getCleanedVar(argFQN); + + // TODO: check if type equals "var" here which would be a terrible mistake. + // Has to be defined already so no need to check here + if (!argReturnType.equals("var")) { + preCallArguments.add("(%s)%s".formatted(argReturnType, + VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); + } else { + System.out.println(String.format( + "WARNING: Unable to get a proper type for agument in method. This should NEVER happen! %d", + preCallArgument.getInstanceId())); + preCallArguments + .add("%s".formatted(VariableStackHandler.getVariableName(preCallArgument.getInstanceId()))); + } + + String argumentVariable = ""; + // It is possible for us to use the exact sane instance twice during the call to + // this method + // Therefore, also keep a list of variables we define temporarily given we + // commit this only at the end of this routine. + Integer instanceIdForArgument = preCallArgument.getInstanceId(); + boolean variableAlreadyComitted = variableStackHandler.DoesVariableExist(instanceIdForArgument); + if (variableAlreadyComitted) { + argumentVariable = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); + } else { + ClassReference compatibleClassReference = SerializationUtils + .getBetterType(preCallArgument.getClassReference(), correspondingMethodArg); + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + String returnType = DescriptorUtils.getCleanedVar(FQN); + + // We do not handle lambdas currently, so fail here. + if (preCallArgument.getClassReference().getFullyQualifiedTypeName().contains("Lambda/")) { + localSucceeded = false; + } else { + // Variable does not exist yet, commit to it later + localArgumentInstanceId = instanceIdForArgument; + localArgumentType = returnType; + localAddArgument = true; + } + + argumentVariable = String.format("%s %s", returnType, + VariableStackHandler.getVariableName(preCallArgument.getInstanceId())); + } + + String argumentValue = ""; + if (preCallArgument.getValueAsXmlString() != null && !preCallArgument.getValueAsXmlString().isEmpty()) { + try { + argumentValue = SerializationUtils.serializableDataToJava(preCallArgument, correspondingMethodArg); + } catch (Exception e) { + System.out.println("Unable to generate code for serializing data to java!"); + e.printStackTrace(); + // fail... + // We do not have a value we can deal with, see if it already exists to use this + // instead. + if (variableAlreadyComitted) { + // This is a bit redundant as we will write var1 = var1, fix later, purely + // cosmetic. + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); + } else { + // We cant do much, fail. + argumentValue = "\"%s\"".formatted(preCallArgument.getValueAsXmlString()); + localSucceeded = false; + } + } + } else { + // We do not have a value we can deal with, see if it already exists to use this + // instead. + if (variableAlreadyComitted) { + // This is a bit redundant as we will write var1 = var1, fix later, purely + // cosmetic. + argumentValue = VariableStackHandler.getVariableName(preCallArgument.getInstanceId()); + } else { + // We cant do much, fail. + argumentValue = "\"UNKNOWN_DATA_VALUE\""; + localSucceeded = false; + } + } + + if (variableAlreadyComitted) { + String definedType = variableStackHandler.getVariableType(instanceIdForArgument); + + // Define the variable before the method + // TODO: check if type equals "var" here which would be a terrible mistake. + if (!definedType.equals("var")) { + if (!definedType.equals("java.lang.Integer") && + !definedType.equals("java.lang.Void") && + !definedType.equals("java.lang.Boolean") && + !definedType.equals("java.lang.Byte") && + !definedType.equals("java.lang.Character") && + !definedType.equals("java.lang.Short") && + !definedType.equals("java.lang.Double") && + !definedType.equals("java.lang.Float") && + !definedType.equals("java.lang.Long") && + !definedType.equals("java.lang.String")) { + if (argumentValue.startsWith("-")) { + // TODO: Only works with integer! + if (localSucceeded) { + variableDeclarationList + .add("%s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("// %s = (%s)(%s);".formatted(argumentVariable, definedType, argumentValue)); + } + } else { + if (localSucceeded) { + variableDeclarationList + .add("%s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } else { + variableDeclarationList + .add("// %s = (%s)%s;".formatted(argumentVariable, definedType, argumentValue)); + } + } + } else { + if (localSucceeded) { + variableDeclarationList + .add("%s = %s;".formatted(argumentVariable, argumentValue)); + } else { + variableDeclarationList + .add("// %s = %s;".formatted(argumentVariable, argumentValue)); + } + } + } else { + System.out.println(String.format( + "WARNING: Unable to get a proper type for agument in method. This should NEVER happen! %d", + instanceIdForArgument)); + if (localSucceeded) { + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } else { + variableDeclarationList.add("// %s = %s;".formatted(argumentVariable, argumentValue)); + } + } + } else { + // Define the variable before the method + if (localSucceeded) { + variableDeclarationList.add("%s = %s;".formatted(argumentVariable, argumentValue)); + } else { + variableDeclarationList.add("// %s = %s;".formatted(argumentVariable, argumentValue)); + } + } + + if (localSucceeded && localAddArgument) { + if (!variableStackHandler.DoesVariableExist(localArgumentInstanceId)) { + variableStackHandler.CreateNewVariable(localArgumentInstanceId, localArgumentType); + } + } + + if (!localSucceeded) { + Succeeded = false; + } + } + + String formattedArgumentsForUseInMethodCall = String.join(", ", preCallArguments); + + // Return if we succeeded, the list of stuff to pass as method arguments, and + // the list of variable declarations to add if any + return new ArgLineGenerateResult(Succeeded, formattedArgumentsForUseInMethodCall, variableDeclarationList); + } +} \ No newline at end of file diff --git a/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/SerializationUtils.java b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/SerializationUtils.java new file mode 100644 index 00000000..73c6ec5d --- /dev/null +++ b/TraceDiff/src/main/java/com/github/gilesi/tracediff/review/SerializationUtils.java @@ -0,0 +1,157 @@ +package com.github.gilesi.tracediff.review; + +import com.github.gilesi.instrumentation.models.ClassReference; +import com.github.gilesi.instrumentation.models.InstanceReference; +import com.github.gilesi.tracediff.DescriptorUtils; +import com.github.gilesi.tracediff.Main; +import com.github.gilesi.tracediff.exceptions.SerializationException; +import org.apache.commons.text.StringEscapeUtils; + +import java.util.ArrayList; +import java.util.List; + +public class SerializationUtils { + public static ClassReference getCompatibleClassReference(ClassReference classReference) { + String FQN = classReference.getFullyQualifiedTypeName(); + if (FQN.startsWith("java.")) { + return classReference; + } + + if (FQN.replace("[]", "").equals("int") || + FQN.replace("[]", "").equals("void") || + FQN.replace("[]", "").equals("boolean") || + FQN.replace("[]", "").equals("byte") || + FQN.replace("[]", "").equals("char") || + FQN.replace("[]", "").equals("short") || + FQN.replace("[]", "").equals("double") || + FQN.replace("[]", "").equals("float") || + FQN.replace("[]", "").equals("long") || + FQN.replace("[]", "").equals("string")) { + return classReference; + } + + String[] libraryTypes = Main.instrumentationParameters.LibraryTypes; + + for (String libraryType : libraryTypes) { + if (FQN.equals(libraryType)) { + return classReference; + } + } + + if (classReference.getSuperClass() != null) { + ClassReference compatibleClassReference = getCompatibleClassReference(classReference.getSuperClass()); + if (compatibleClassReference != null) { + return compatibleClassReference; + } + } + + for (ClassReference interfaceClassReference : classReference.getInterfaces()) { + ClassReference compatibleClassReference = getCompatibleClassReference(interfaceClassReference); + if (compatibleClassReference != null) { + return compatibleClassReference; + } + } + + return null; + } + + public static ClassReference getBetterType(ClassReference actualType, ClassReference desiredType) { + ClassReference compatibleClassReference = getCompatibleClassReference(actualType); + boolean isValid = compatibleClassReference != null + && !compatibleClassReference.getFullyQualifiedTypeName().equals("java.lang.Object"); + + if (!isValid) { + compatibleClassReference = getCompatibleClassReference(desiredType); + isValid = compatibleClassReference != null + && !compatibleClassReference.getFullyQualifiedTypeName().equals("java.lang.Object"); + if (!isValid) { + System.out + .println("WARNING: Argument type is not supported by the library of Java Runtime Environment."); + System.out.println("WARNING: Actual Type: " + actualType.getFullyQualifiedTypeName()); + System.out.println("WARNING: Desired Type: " + desiredType.getFullyQualifiedTypeName()); + } + return desiredType; + } else { + return compatibleClassReference; + } + } + + public static String serializableDataToJava(InstanceReference serializableData, ClassReference argClass) + throws SerializationException { + String valueToBeEqualTo = serializableData.getValueAsXmlString(); + + ClassReference compatibleClassReference = getBetterType(serializableData.getClassReference(), argClass); + String FQN = DescriptorUtils.getCleanedType(compatibleClassReference.getFullyQualifiedTypeName()); + + if (!FQN.equals("java.lang.Integer") && + !FQN.equals("java.lang.Void") && + !FQN.equals("java.lang.Boolean") && + !FQN.equals("java.lang.Byte") && + !FQN.equals("java.lang.Character") && + !FQN.equals("java.lang.Short") && + !FQN.equals("java.lang.Double") && + !FQN.equals("java.lang.Float") && + !FQN.equals("java.lang.Long") && + !FQN.equals("java.lang.String")) { + + String valueAsCode = generateStringJavaLine(serializableData.getValueAsXmlString()); + valueToBeEqualTo = "getFromXml(%s)".formatted(valueAsCode); + } else { + int start = valueToBeEqualTo.indexOf(">"); + int end = valueToBeEqualTo.lastIndexOf(" valueToBeEqualTo.length() - 1 - 3) { + throw new SerializationException("Malformed XML data"); + } + + valueToBeEqualTo = valueToBeEqualTo.substring(start + 1, end); + + if (FQN.equals("java.lang.Character")) { + valueToBeEqualTo = "'%s'".formatted(valueToBeEqualTo); + if (valueToBeEqualTo.equals("''")) { + valueToBeEqualTo = "java.lang.Character.MIN_VALUE"; + } + } else if (FQN.equals("java.lang.String")) { + valueToBeEqualTo = generateStringJavaLine(valueToBeEqualTo); + } else if (FQN.equals("java.lang.Float")) { + valueToBeEqualTo = "%sF".formatted(valueToBeEqualTo); + } else if (FQN.equals("java.lang.Long")) { + valueToBeEqualTo = "%sL".formatted(valueToBeEqualTo); + } + } + + return valueToBeEqualTo; + } + + public static String generateStringJavaLine(String stringContent) { + String valueAsCode = "\"%s\"".formatted(StringEscapeUtils.escapeJava(stringContent)); + + // int maxStringSize = (int) Math.pow(2, 16); + // TODO: CHeck why this still fails + int maxStringSize = 1024; + + if (valueAsCode.length() > maxStringSize) { + List sectionList = new ArrayList<>(); + + for (int start2 = 0; start2 < valueAsCode.length(); start2 += maxStringSize) { + int end2 = start2 + maxStringSize; + if (start2 + maxStringSize > valueAsCode.length()) { + end2 = valueAsCode.length(); + } + + String sectionOfDataAsXml = valueAsCode.substring(start2, end2); + String readyToUseSection = "new String(\"%s\")" + .formatted(StringEscapeUtils.escapeJava(sectionOfDataAsXml)); + sectionList.add(readyToUseSection); + } + + valueAsCode = String.join(" + ", sectionList.toArray(String[]::new)); + } + + return valueAsCode; + } +} diff --git a/compile.cmd b/compile.cmd index d920b310..50f7973a 100644 --- a/compile.cmd +++ b/compile.cmd @@ -25,6 +25,18 @@ cd TestGenerator call .\gradlew.bat shadowJar --warning-mode all cd .. + +echo. +echo =========================================================== +echo Building TraceDiff +echo =========================================================== +echo. + +REM build tracediff +cd TraceDiff +call .\gradlew.bat shadowJar --warning-mode all +cd .. + echo. echo =========================================================== echo Building Agent diff --git a/compile.sh b/compile.sh index 02f7a5c3..5a631b5b 100755 --- a/compile.sh +++ b/compile.sh @@ -23,6 +23,18 @@ cd TestGenerator sh ./gradlew shadowJar --warning-mode all cd .. + +echo +echo =========================================================== +echo Building TraceDiff +echo =========================================================== +echo + +# build tracediff +cd TraceDiff +sh ./gradlew shadowJar --warning-mode all +cd .. + echo echo =========================================================== echo Building Agent diff --git a/run-clean-workflow.cmd b/run-clean-workflow.cmd index 7d979209..e9490cd4 100644 --- a/run-clean-workflow.cmd +++ b/run-clean-workflow.cmd @@ -13,6 +13,10 @@ cd TestGenerator rmdir /Q /S build cd .. +cd TraceDiff +rmdir /Q /S build +cd .. + cd Instrumentation rmdir /Q /S build cd .. diff --git a/run-clean-workflow.sh b/run-clean-workflow.sh index 44ed09af..44e60bce 100755 --- a/run-clean-workflow.sh +++ b/run-clean-workflow.sh @@ -13,6 +13,10 @@ cd TestGenerator rm -rf ./build cd .. +cd TraceDiff +rm -rf ./build +cd .. + cd Instrumentation rm -rf ./build cd .. diff --git a/run-test-workflow.cmd b/run-test-workflow.cmd index c5956f64..7e5f2fea 100644 --- a/run-test-workflow.cmd +++ b/run-test-workflow.cmd @@ -50,4 +50,12 @@ echo Running TestGenerator echo =========================================================== echo. -"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Results\MethodTraces.json" "%CD%\Results\TestGenerator.Output" \ No newline at end of file +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TestGenerator\build\libs\com.github.gilesi.testgenerator.jar" "%CD%\Results\MethodTraces.json" "%CD%\Results\TestGenerator.Output" + +echo. +echo =========================================================== +echo Running TraceDiff +echo =========================================================== +echo. + +"%JAVA_HOME%\bin\java.exe" -jar "%CD%\TraceDiff\build\libs\com.github.gilesi.tracediff.jar" "%CD%\Results\MethodTraces.json" "%CD%\Results\TraceDiff.Output" \ No newline at end of file diff --git a/run-test-workflow.sh b/run-test-workflow.sh index c09b910e..cb71fd47 100755 --- a/run-test-workflow.sh +++ b/run-test-workflow.sh @@ -46,4 +46,12 @@ echo Running TestGenerator echo =========================================================== echo -"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Results/generated/traces" "$PWD/Results/generated/tests/src/test/java" \ No newline at end of file +"$JAVA_HOME/bin/java" -jar "$PWD/TestGenerator/build/libs/com.github.gilesi.testgenerator.jar" "$PWD/Results/generated/traces" "$PWD/Results/generated/tests/src/test/java" + +echo +echo =========================================================== +echo Running TraceDiff +echo =========================================================== +echo + +"$JAVA_HOME/bin/java" -jar "$PWD/TraceDiff/build/libs/com.github.gilesi.tracediff.jar" "$PWD/Results/generated/traces" "$PWD/Results/generated/tests/src/test/java" \ No newline at end of file From cee7c4ec08d80a5c23b927bfc9f7f6232f404961 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 9 Sep 2024 11:05:40 +0200 Subject: [PATCH 198/244] Revert "Test only variable data creation" This reverts commit b91bcbd71997cc2fbbbdc2f213e93b055ff2f883. --- .../java/com/github/gilesi/testgenerator/TraceUtils.java | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java index f5ee2d0f..afd6a5bf 100644 --- a/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java +++ b/TestGenerator/src/main/java/com/github/gilesi/testgenerator/TraceUtils.java @@ -231,7 +231,7 @@ private static boolean handleMethodInstance(int traceId, VariableStackHandler va public static void parseTrace(int traceId, Trace trace, VariableStackHandler variableStackHandler, StringBuilder stringBuilder) throws SerializationException { - /*String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; + String methodName = trace.getMethodReference().getMethodSignature().split("\\(")[0]; methodName = methodName.split(" ")[methodName.split(" ").length - 1].replace("$", "."); InstanceReference instanceData = trace.getInstanceReference(); @@ -239,7 +239,7 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var String instanceVariableName = ""; if (instanceData != null) { instanceVariableName = VariableStackHandler.getVariableName(instanceData.getInstanceId()); - }*/ + } ArgLineGenerateResult argLineResult = ArgumentUtils.GenerateArgLine(trace, variableStackHandler); @@ -247,7 +247,7 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var stringBuilder.append(String.format("%s\n", str)); } - /*boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() + boolean isInstanceCall = instanceData != null && !instanceData.getClassReference() .getFullyQualifiedTypeName().replace("$", ".").equals(methodName); boolean success = true; @@ -274,6 +274,6 @@ public static void parseTrace(int traceId, Trace trace, VariableStackHandler var stringBuilder.append(String.format("// %s\n", varAssert)); } } - }*/ + } } } \ No newline at end of file From 86faaaf1f3e66ca629ed1079ea94113c0022cb86 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 9 Sep 2024 14:55:24 +0200 Subject: [PATCH 199/244] Enable running trace diff on site --- .idea/misc.xml | 1 + .../java/com/github/gilesi/maestro/Constants.java | 2 +- .../src/main/java/com/github/gilesi/maestro/Main.java | 4 ++-- .../github/gilesi/maestro/compsuite/CompSuite.java | 8 +++++--- .../java/com/github/gilesi/maestro/tools/TestGen.java | 11 +++++++++++ .../main/java/com/github/gilesi/tracediff/Main.java | 1 + 6 files changed, 21 insertions(+), 6 deletions(-) diff --git a/.idea/misc.xml b/.idea/misc.xml index fa8260ce..0b11c48e 100644 --- a/.idea/misc.xml +++ b/.idea/misc.xml @@ -9,6 +9,7 @@ +

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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/Illico/gradlew.bat b/Illico/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/Illico/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Illico/settings.gradle b/Illico/settings.gradle new file mode 100644 index 00000000..19c50608 --- /dev/null +++ b/Illico/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'Illico' + diff --git a/Illico/src/main/java/com/github/gilesi/illico/Constants.java b/Illico/src/main/java/com/github/gilesi/illico/Constants.java new file mode 100644 index 00000000..8e770a81 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/Constants.java @@ -0,0 +1,41 @@ +package com.github.gilesi.illico; + +import java.util.Hashtable; +import java.util.Map; + +public class Constants { + // These paths should already exist on the end user machine for now and never change + public static final String CONF_GEN_LOCATION = "ConfGen/build/libs/com.github.gilesi.confgen.jar"; + public static final String TEST_GEN_LOCATION = "TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; + public static final String TRACE_DIFF_LOCATION = "TraceDiff/build/libs/com.github.gilesi.tracediff.jar"; + public static final String INSTRUMENTATION_LOCATION = "Instrumentation/build/libs/com.github.gilesi.instrumentation.jar"; + + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64"; + + // These paths are dynamically created by the tool but must stay consistent within methods + public static final String targetAgentName = "com.github.gilesi.instrumentation.jar"; + public static final String targetConfigurationName = "TestWorkflowConfiguration.json"; + + public static final Map JAVA_VERSIONS = new Hashtable<>() { + { + put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); + put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); + put("21", JAVA_21_BINARY_LOCATION); + } + }; + + public static final String GREEN_TEST = "Green"; + public static final String RED_TEST = "Red"; + + public static final String SUREFIRE_VERSION = "2.8"; + public static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; + public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; + + public static boolean SKIP_INSTRUMENTATION_RAN_ALREADY_FOR_DEBUGGING = false; + + public static final String M2_REPOSITORY = "/home/gus/.m2/repository"; +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/FileUtils.java b/Illico/src/main/java/com/github/gilesi/illico/FileUtils.java new file mode 100644 index 00000000..dab7ee8e --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/FileUtils.java @@ -0,0 +1,130 @@ +package com.github.gilesi.illico; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Objects; +import java.util.regex.Pattern; + +public class FileUtils { + public static void deleteDirectory(File fi) { + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + file.delete(); + } + fi.delete(); + } + + public static void deleteDirectoryIfExists(String path) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + deleteDirectory(new File(path)); + } + } + + public static ArrayList enumerateDirectory(File fi, String wildcard, boolean recursive) { + ArrayList files = new ArrayList<>(); + Pattern pattern = Pattern.compile(wildcard); + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory() && recursive) { + files.addAll(enumerateDirectory(file, wildcard, true)); + } else { + if (pattern.matcher(file.getName()).matches()) { + files.add(file.getPath()); + } + } + } + return files; + } + + public static ArrayList enumerateFiles(String path, String wildcard, boolean recursive) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + return enumerateDirectory(new File(path), wildcard, recursive); + } + return new ArrayList<>(); + } + + public static void ensureDirectoryExistsAndIsEmpty(String path) throws IOException { + Path pa = Path.of(path); + deleteDirectoryIfExists(path); + Files.createDirectory(pa); + } + + public static void backupFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(filePath)) { + return; + } + + if (Files.exists(backupFilePath)) { + Files.delete(backupFilePath); + } + + Files.copy(filePath, backupFilePath); + } + + public static void restoreFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(backupFilePath)) { + return; + } + + if (Files.exists(filePath)) { + Files.delete(filePath); + } + + Files.move(backupFilePath, filePath); + } + + public static void copyFolder(File source, File destination) { + if (source.isDirectory()) { + if (!destination.exists()) { + destination.mkdirs(); + } + + String[] files = source.list(); + + for (String file : files) { + File srcFile = new File(source, file); + File destFile = new File(destination, file); + + copyFolder(srcFile, destFile); + } + } else { + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(source); + out = new FileOutputStream(destination); + + byte[] buffer = new byte[1024]; + + int length; + while ((length = in.read(buffer)) > 0) { + out.write(buffer, 0, length); + } + } catch (Exception e) { + try { + in.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + try { + out.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/Main.java b/Illico/src/main/java/com/github/gilesi/illico/Main.java new file mode 100644 index 00000000..bea25abf --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/Main.java @@ -0,0 +1,179 @@ +package com.github.gilesi.illico; + +import org.apache.maven.shared.invoker.MavenInvocationException; + +import com.github.gilesi.illico.runners.maven.Log4JLogger; +import com.github.gilesi.illico.runners.maven.ProjectRunner; +import com.github.gilesi.illico.runners.maven.TestAssertedLogger; +import com.github.gilesi.illico.tools.ConfGen; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Main { + public static final Logger logger = LogManager.getLogger("illico"); + public static final Logger loggerMaven = LogManager.getLogger("maven"); + public static final Logger loggerConfGen = LogManager.getLogger("confgen"); + public static final Logger loggerTraceDiff = LogManager.getLogger("tracediff"); + public static final Logger loggerTraceGen = LogManager.getLogger("tracegen"); + public static final Logger loggerAgent = LogManager.getLogger("agent"); + + public static void main(String[] args) throws MavenInvocationException, IOException, InterruptedException { + if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { + logger.info("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); + return; + } + + if (args.length < 4) { + logger.info("Usage: "); + return; + } + + String clientLocation = args[0]; + String libraryIdentifier = args[1]; + String outputFolder = args[2]; + String GilesiRepositoryLocation = args[3]; + + ProjectRunner.runMavenGoalOnRepository( + clientLocation, + "dependency:get -Dartifact=%s:jar:sources".formatted(libraryIdentifier), + null, + "1.8", + new Log4JLogger(), + null + ); + + Path outputPath = Path.of(outputFolder).toAbsolutePath(); + + Path libraryPath = outputPath.resolve("library-sources"); + + copyLibrarySourcesForDataset(libraryIdentifier, libraryPath, Path.of(Constants.M2_REPOSITORY)); + + String additionalJavaToolParameters = installInstrumentationAgentOntoProject(Path.of(GilesiRepositoryLocation), libraryPath, Path.of(clientLocation), outputPath.resolve("instrumentation")); + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false"; + + TestAssertedLogger testAssertedLogger = new TestAssertedLogger( + new Log4JLogger( + logger, + org.apache.maven.shared.invoker.InvokerLogger.INFO, + "%s-%s".formatted(clientLocation, clientLocation) + ) + ); + + ProjectRunner.runMavenGoalOnRepository(clientLocation, + testCmd, + null, + "1.8", + testAssertedLogger, + additionalJavaToolParameters); + + Main.logger.info("Client: %s - TEST(S) FAILED: %s".formatted(clientLocation, + testAssertedLogger.HasTestFailed())); + } + + + private static String installInstrumentationAgentOntoProject( + Path GilesiRepositoryLocationPath, + Path libraryLocationPath, + Path clientLocationPath, + Path generatedFolderPath + ) throws IOException, InterruptedException { + + FileUtils.deleteDirectoryIfExists(generatedFolderPath.toString()); + + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ConfGen.runConfGen(GilesiRepositoryLocationPath.toString(), + libraryConfig.toString(), + generatedFolderPath.toString(), + libraryLocationPath.toString()); + + Path InstrumentationAgentEffectiveLocation = GilesiRepositoryLocationPath.resolve(Constants.INSTRUMENTATION_LOCATION); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocationPath.toString(), + "pom.xml", + true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocationPath.toString(), + "build.gradle", + true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + Orchestrator.copyInstrumentationToolAndConfiguration(allProjectFiles, + InstrumentationAgentEffectiveLocation, + libraryConfig); + + String javaToolOptions = "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, + libraryConfig.toString()); + + Orchestrator.orchestrateGradleProjects(clientProjectGradleBuildFiles); + + return javaToolOptions; + } + + private static void copyLibrarySourcesForDataset(String libraryIdentifier, Path librarySourceOutputPath, Path m2RepositoryPath) throws IOException, MavenInvocationException { + String[] groupId = libraryIdentifier.split(":")[0].split("\\."); + String artifactId = libraryIdentifier.split(":")[1]; + String libraryVersion = libraryIdentifier.split(":")[2]; + + Path fileSystemRepoPath = m2RepositoryPath; + + for (String pathComponent : groupId) { + fileSystemRepoPath = fileSystemRepoPath.resolve(pathComponent); + } + + fileSystemRepoPath = fileSystemRepoPath.resolve(artifactId).resolve(libraryVersion); + + ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); + + if (srcCandidates.size() == 0) { + Main.logger.info("%s Missing sources for lib, aborting!".formatted(libraryIdentifier)); + return; + } + + FileUtils.deleteDirectoryIfExists(librarySourceOutputPath.toString()); + Files.createDirectories(librarySourceOutputPath); + + for (String cand : srcCandidates) { + System.out.println("Extracting " + cand); + System.out.println("Extracting " + librarySourceOutputPath); + extractJar(cand, librarySourceOutputPath.toString()); + } + } + + private static void extractJar(String jar, String destdir) throws java.io.IOException { + java.util.jar.JarFile jarFile = new java.util.jar.JarFile(new java.io.File(jar)); + java.util.Enumeration enu = jarFile.entries(); + while (enu.hasMoreElements()) { + java.util.jar.JarEntry je = enu.nextElement(); + + java.io.File fl = new java.io.File(destdir, je.getName()); + if (!fl.exists()) { + fl.getParentFile().mkdirs(); + fl = new java.io.File(destdir, je.getName()); + } + if (je.isDirectory()) { + continue; + } + java.io.InputStream is = jarFile.getInputStream(je); + java.io.FileOutputStream fo = new java.io.FileOutputStream(fl); + while (is.available() > 0) { + fo.write(is.read()); + } + fo.close(); + is.close(); + } + jarFile.close(); + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/Orchestrator.java b/Illico/src/main/java/com/github/gilesi/illico/Orchestrator.java new file mode 100644 index 00000000..671f82d2 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/Orchestrator.java @@ -0,0 +1,267 @@ +package com.github.gilesi.illico; + +import com.github.gilesi.illico.buildsystem.configuration.maven.PomHelper; +import com.github.gilesi.illico.runners.maven.Log4JLogger; +import com.github.gilesi.illico.runners.maven.ProjectRunner; +import com.github.gilesi.illico.tools.ConfGen; +import com.github.gilesi.illico.tools.TestGen; +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Orchestrator { + // TODO: More robust logging here using JUnit perhaps... + // TODO: Simplify required arg to run here + // TODO: Ideally we would want to deduce the version from the provided source but not always doable + // TODO: Could we also fetch source jars ourselves somehow or source loc? + // TODO: Maybe the dependency name is also doable to extract here, need to see how... + // TODO: Fix cross plat! + // TODO: picocli? + + public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation, String dependencyName, String dependencyVersion, String outputTestProject) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); + + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Create the results directory + Files.createDirectories(outputTestProjectPath); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ConfGen.runConfGen(GilesiRepositoryLocation, libraryConfig.toString(), outputTestProject, libraryLocation); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.INSTRUMENTATION_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + orchestrateMavenProjects(clientProjectPomFiles); + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + // Run the client tests + executeMavenProjectTests(clientProjectPomFiles, clientLocation); + executeGradleProjectTests(clientProjectGradleBuildFiles, clientLocation); + + TestGen.runTestGen(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString(), libraryConfig.toString()); + + lastMinuteCleanup(allProjectFiles); + + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + + String buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + }""".formatted(dependencyName, dependencyVersion); + + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Illico").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("Illico").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + + // Test test project (3 times to be sure) + + // Update test project dependency version at version dependencyNewVersion + + // Test test project with dependency at version dependencyNewVersion (3 times to be sure) + + // Collect results of the execution + + // Write report + } + + public static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + + //Files.copy(InstrumentationAgentEffectiveLocation, agentDest); + //Files.copy(libraryConfig, workflowDest); + } + } + + public static void orchestrateMavenProjects(ArrayList clientProjectPomFiles) throws IOException, XmlPullParserException { + for (String clientBuildFile : clientProjectPomFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); + } + } + + public static void orchestrateGradleProjects(ArrayList clientProjectGradleBuildFiles) throws IOException { + for (String clientBuildFile : clientProjectGradleBuildFiles) { + String clientTestingBlock = """ + testing { + \tsuites { + \t\ttest { + \t\t\tuseJUnitJupiter() + \t\t\ttargets { + \t\t\t\tall { + \t\t\t\t\ttestTask.configure { + \t\t\t\t\t\tsystemProperty 'net.bytebuddy.experimental', 'true' + \t\t\t\t\t\tjvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:%s=%s'] + \t\t\t\t\t} + \t\t\t\t} + \t\t\t} + \t\t} + \t} + }""".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + + Path clientBuildFilePath = Path.of(clientBuildFile); + + String buildFileContent = Files.readString(clientBuildFilePath); + if (!buildFileContent.contains(clientTestingBlock)) { + buildFileContent += "\n" + clientTestingBlock; + + Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + Files.writeString(clientBuildFilePath, buildFileContent); + } + } + } + + public static void executeMavenProjectTests(ArrayList clientProjectPomFiles, String clientLocation) throws MavenInvocationException { + // This is the maven path + if (!clientProjectPomFiles.isEmpty()) { + if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s%c".formatted(clientLocation, File.separatorChar), "").replace(clientLocation, "").equals("pom.xml"))) { + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); + } else { + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); + } + } + } + } + + public static void executeGradleProjectTests(ArrayList clientProjectGradleBuildFiles, String clientLocation) throws IOException, InterruptedException { + // This is the gradle path + if (!clientProjectGradleBuildFiles.isEmpty()) { + if (clientProjectGradleBuildFiles.stream().anyMatch + ( + t -> + t + .replace( + "%s%c" + .formatted( + clientLocation, + File.separatorChar + ), + "" + ) + .replace( + clientLocation, + "" + ) + .equals("build.gradle") + )) { + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + Path.of(clientLocation).resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientLocation), Main.logger); + + // TODO: Check for underlying platform + /*ProcessUtils.runExternalCommand(new String[]{ + "cmd.exe", + "-C", + Path.of(clientLocation).resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientLocation), Main.logger);*/ + } else { + for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { + Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); + Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); + + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + clientProjectLocationPath.resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString()), Main.logger); + + // TODO: Check for underlying platform + /*ProcessUtils.runExternalCommand(new String[]{ + "cmd.exe", + "-C", + clientProjectLocationPath.resolve("gradlew.bat").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString()), Main.logger);*/ + } + } + } + } + + public static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { + // Last minute cleanup + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + } + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/ProcessUtils.java b/Illico/src/main/java/com/github/gilesi/illico/ProcessUtils.java new file mode 100644 index 00000000..2b55ed7c --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/ProcessUtils.java @@ -0,0 +1,26 @@ +package com.github.gilesi.illico; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +public class ProcessUtils { + public static int runExternalCommand(String[] command, File directory, org.apache.logging.log4j.Logger logger) throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder(command); + if (directory != null) { + pb.directory(directory); + } + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + + String line; + + while ((line = reader.readLine()) != null) { + logger.info(line); + } + + return p.waitFor(); + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/RunResult.java b/Illico/src/main/java/com/github/gilesi/illico/RunResult.java new file mode 100644 index 00000000..2e153c2e --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/RunResult.java @@ -0,0 +1,22 @@ +package com.github.gilesi.illico; + +import com.github.gilesi.illico.testing.ReportItem; + +import java.util.ArrayList; + +public class RunResult { + public String ProjectId = ""; + public boolean ProjectIsMissingLibrarySourceCode = false; + public boolean ProjectCannotBeReproduced = false; // TODO + public boolean ProjectCannotBeInstrumented = false; + public boolean ProjectFailedToLoadAgent = false; + public boolean ProjectIsMissingTraceFiles = false; + public boolean ProjectIsMissingSpecificTraces = false; + public boolean ProjectFailedToGenerateAnyTraceTestSrc = false; + public boolean ProjectFailedToCompileGeneratedTests = false; + public boolean ProjectFailedToExecuteGeneratedTests = false; + public boolean ProjectFailedToCompileGeneratedTestsWithNewVersion = false; + public boolean ProjectFailedToExecuteGeneratedTestsWithNewVersion = false; + public ArrayList TestExecutionReportWithOldVersion; + public ArrayList TestExecutionReportWithNewVersion; +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/ConfigurationUtils.java b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/ConfigurationUtils.java new file mode 100644 index 00000000..3023c5da --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/ConfigurationUtils.java @@ -0,0 +1,31 @@ +package com.github.gilesi.illico.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class ConfigurationUtils { + public static Xpp3Dom getDomValueObject(String name, String value) { + Xpp3Dom domValue = new Xpp3Dom(name); + domValue.setValue(value); + return domValue; + } + + public static Xpp3Dom getDomArrayObject(String arrayName, String name, String[] values) { + Xpp3Dom valuesDom = new Xpp3Dom(arrayName); + for (String val : values) { + addStringValueIfNotEmpty(valuesDom, name, val); + } + return valuesDom; + } + + public static void addStringValueIfNotEmpty(Xpp3Dom config, String name, String value) { + if (value != null && !value.isEmpty()) { + config.addChild(getDomValueObject(name, value)); + } + } + + public static void addStringArrayValueIfNotEmpty(Xpp3Dom config, String arrayName, String name, String[] values) { + if (values != null && values.length > 0) { + config.addChild(getDomArrayObject(arrayName, name, values)); + } + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/IPluginConfiguration.java b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/IPluginConfiguration.java new file mode 100644 index 00000000..2e567e78 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/IPluginConfiguration.java @@ -0,0 +1,7 @@ +package com.github.gilesi.illico.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public interface IPluginConfiguration { + Xpp3Dom serialize(); +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/PomHelper.java b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/PomHelper.java new file mode 100644 index 00000000..f2e53748 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/PomHelper.java @@ -0,0 +1,154 @@ +package com.github.gilesi.illico.buildsystem.configuration.maven; + +import com.github.gilesi.illico.Constants; +import org.apache.maven.model.Build; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PomHelper { + + public static Model readPomFile(String pomFilePath) throws IOException, XmlPullParserException { + MavenXpp3Reader pomReader = new MavenXpp3Reader(); + Path pomPath = Path.of(pomFilePath); + InputStream pomStream = Files.newInputStream(pomPath); + Model pomModel = pomReader.read(pomStream); + pomModel.setPomFile(new File(pomFilePath)); + pomStream.close(); + return pomModel; + } + + private static void writePomFile(Model pomModel, String pomFilePath) throws IOException { + MavenXpp3Writer pomWriter = new MavenXpp3Writer(); + FileWriter pomWriteStream = new FileWriter(pomFilePath); + pomWriter.write(pomWriteStream, pomModel); + pomWriteStream.close(); + } + + private static boolean doesBuildContainPluginGroupId(Build bld, String groupId) { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static boolean doesModelContainDependencyGroupId(Model pomModel, String groupId) { + for (Dependency plg : pomModel.getDependencies()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static Plugin getPluginByGroupId(Build bld, String groupId) throws FileNotFoundException { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return plg; + } + } + throw new FileNotFoundException(); + } + + private static Xpp3Dom buildSureFireConfiguration() { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + return sureFireConfiguration.serialize(); + } + + private static Xpp3Dom buildSureFireConfiguration(String argLine) { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + sureFireConfiguration.setArgLine(argLine); + return sureFireConfiguration.serialize(); + } + + private static Plugin getSureFirePlugin() { + return buildPlugin(Constants.SUREFIRE_GROUPID, Constants.SUREFIRE_ARTIFACTID, Constants.SUREFIRE_VERSION); + } + + private static Dependency buildDependency(String groupId, String artifactId, String version) { + Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + return dependency; + } + + private static Plugin buildPlugin(String groupId, String artifactId, String version) { + Plugin plugin = new Plugin(); + plugin.setGroupId(groupId); + plugin.setArtifactId(artifactId); + plugin.setVersion(version); + return plugin; + } + + private static Plugin buildSureFirePlugin() { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static Plugin buildSureFirePlugin(String argLine) { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(argLine); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static void removeExistingPlugin(Build bld, String groupId) throws FileNotFoundException { + // Get rid of all previous instances of the plugin in case one already exists + while (doesBuildContainPluginGroupId(bld, groupId)) { + bld.removePlugin(getPluginByGroupId(bld, groupId)); + } + } + + private static void removeExistingSureFirePlugins(Build bld) throws FileNotFoundException { + removeExistingPlugin(bld, Constants.SUREFIRE_GROUPID); + } + + public static void addSureFire(String pomFilePath) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } + + public static void addSureFire(String pomFilePath, String argLine) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(argLine); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/SureFirePluginConfiguration.java b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/SureFirePluginConfiguration.java new file mode 100644 index 00000000..7498ff38 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/buildsystem/configuration/maven/SureFirePluginConfiguration.java @@ -0,0 +1,103 @@ +package com.github.gilesi.illico.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class SureFirePluginConfiguration implements IPluginConfiguration { + private int forkCount = 1; + private boolean reuseForks = false; + private String argLine = "-Xmx2G -XX:MaxMetaspaceSize=2G"; + private String parallel = "methods"; + private int threadCount = 1; + private String forkedProcessTimeoutInSeconds = "40"; + private String forkedProcessExitTimeoutInSeconds = "40"; + private String parallelTestsTimeoutInSeconds = "30"; + private String parallelTestsTimeoutForcedInSeconds = "30"; + + public int getForkCount() { + return forkCount; + } + + public void setForkCount(int forkCount) { + this.forkCount = forkCount; + } + + public int getThreadCount() { + return threadCount; + } + + public void setThreadCount(int threadCount) { + this.threadCount = threadCount; + } + + public String getArgLine() { + return argLine; + } + + public void setArgLine(String argLine) { + this.argLine = argLine; + } + + public String getForkedProcessExitTimeoutInSeconds() { + return forkedProcessExitTimeoutInSeconds; + } + + public void setForkedProcessExitTimeoutInSeconds(String forkedProcessExitTimeoutInSeconds) { + this.forkedProcessExitTimeoutInSeconds = forkedProcessExitTimeoutInSeconds; + } + + public String getForkedProcessTimeoutInSeconds() { + return forkedProcessTimeoutInSeconds; + } + + public void setForkedProcessTimeoutInSeconds(String forkedProcessTimeoutInSeconds) { + this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds; + } + + public String getParallelTestsTimeoutForcedInSeconds() { + return parallelTestsTimeoutForcedInSeconds; + } + + public void setParallelTestsTimeoutForcedInSeconds(String parallelTestsTimeoutForcedInSeconds) { + this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds; + } + + public String getParallelTestsTimeoutInSeconds() { + return parallelTestsTimeoutInSeconds; + } + + public void setParallelTestsTimeoutInSeconds(String parallelTestsTimeoutInSeconds) { + this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds; + } + + public String getParallel() { + return parallel; + } + + public void setParallel(String parallel) { + this.parallel = parallel; + } + + public boolean getReuseForks() { + return reuseForks; + } + + public void setReuseForks(boolean reuseForks) { + this.reuseForks = reuseForks; + } + + public Xpp3Dom serialize() { + Xpp3Dom config = new Xpp3Dom("configuration"); + + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkCount", Integer.toString(forkCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "reuseForks", Boolean.toString(reuseForks)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "argLine", argLine); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallel", parallel); + ConfigurationUtils.addStringValueIfNotEmpty(config, "threadCount", Integer.toString(threadCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessTimeoutInSeconds", forkedProcessTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessExitTimeoutInSeconds", forkedProcessExitTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutInSeconds", parallelTestsTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutForcedInSeconds", parallelTestsTimeoutForcedInSeconds); + + return config; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ConsoleLogger.java b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ConsoleLogger.java new file mode 100644 index 00000000..18e4c5d4 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ConsoleLogger.java @@ -0,0 +1,248 @@ +package com.github.gilesi.illico.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class ConsoleLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The threshold used to filter messages. + */ + private int threshold; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public ConsoleLogger() { + this(INFO); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param threshold The threshold for the logger. + */ + public ConsoleLogger(int threshold) { + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + String logLevel = "INFO"; + + switch (level) { + case (DEBUG) -> logLevel = "DEBUG"; + case (INFO) -> logLevel = "INFO"; + case (WARN) -> logLevel = "WARN"; + case (ERROR) -> logLevel = "ERROR"; + case (FATAL) -> logLevel = "FATAL"; + default -> { + } + } + + buffer.append("[Maven] "); + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + System.out.printf("[%s] [%s] %s%n", new Date(), logLevel, buffer); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/runners/maven/Log4JLogger.java b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/Log4JLogger.java new file mode 100644 index 00000000..d7fb41a7 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/Log4JLogger.java @@ -0,0 +1,271 @@ +package com.github.gilesi.illico.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class Log4JLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The print stream to write to, never null. + */ + private final Logger out; + + /** + * The threshold used to filter messages. + */ + private int threshold; + + private String prefix; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public Log4JLogger() { + this(LogManager.getLogger(), INFO, ""); + } + + public Log4JLogger(String prefix) { + this(LogManager.getLogger(), INFO, prefix); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param out The print stream to write to, must not be null. + * @param threshold The threshold for the logger. + */ + public Log4JLogger(Logger out, int threshold, String prefix) { + if (out == null) { + throw new NullPointerException("missing output stream"); + } + this.prefix = prefix; + this.out = out; + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + Level logLevel = Level.INFO; + + switch (level) { + case (DEBUG) -> logLevel = Level.DEBUG; + case (INFO) -> logLevel = Level.INFO; + case (WARN) -> logLevel = Level.WARN; + case (ERROR) -> logLevel = Level.ERROR; + case (FATAL) -> logLevel = Level.FATAL; + default -> { + } + } + + if (prefix != null && !prefix.isEmpty()) { + buffer.append("[%s-Maven] ".formatted(prefix)); + } else { + buffer.append("[Maven] "); + } + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + out.log(logLevel, buffer.toString()); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ProjectRunner.java b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ProjectRunner.java new file mode 100644 index 00000000..1edcb010 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/ProjectRunner.java @@ -0,0 +1,181 @@ +package com.github.gilesi.illico.runners.maven; + +import com.github.gilesi.illico.Constants; +import com.github.gilesi.illico.Main; +import org.apache.maven.model.*; +import org.apache.maven.shared.invoker.*; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static com.github.gilesi.illico.buildsystem.configuration.maven.PomHelper.readPomFile; + +public class ProjectRunner { + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, Object logger, String javaToolOptions) + throws MavenInvocationException { + + String javaVersion = "8"; + + try { + Model pomModel = readPomFile(pomFilePath); + Properties props = pomModel.getProperties(); + if (props.stringPropertyNames().contains("java.compiler.version")) { + javaVersion = props.getProperty("java.compiler.version"); + Main.logger.info("Debug: Using java.compiler.version=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.source")) { + javaVersion = props.getProperty("maven.compiler.source"); + Main.logger.info("Debug: Using maven.compiler.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.target")) { + javaVersion = props.getProperty("maven.compiler.target"); + Main.logger.info("Debug: Using maven.compiler.target=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.source")) { + javaVersion = props.getProperty("maven.compile.source"); + Main.logger.info("Debug: Using maven.compile.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.target")) { + javaVersion = props.getProperty("maven.compile.target"); + Main.logger.info("Debug: Using maven.compile.target=" + javaVersion); + } + } catch (Exception ignored) { + Main.logger.info("Debug: Getting java specific version unfortunately failed."); + } + + return runPomGoals(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaVersion, logger, + javaToolOptions); + } + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) + throws MavenInvocationException { + String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, + javaVersion, logger, javaToolOptions); + } + + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger, + String javaToolOptions) throws MavenInvocationException { + File pomFile = new File(pomFilePath); + + InvokerLogger invokerLogger = null; + InvocationOutputHandler invocationOutputHandler = null; + + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + + File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); + + Properties properties = new Properties(); + pomProperties.forEach(p -> properties.setProperty(p, "true")); + + properties.setProperty("maven.compiler.source", JavaVersion); + properties.setProperty("maven.compiler.target", JavaVersion); + properties.setProperty("maven.compile.source", JavaVersion); + properties.setProperty("maven.compile.target", JavaVersion); + + properties.setProperty("maven.source.skip", "true"); + properties.setProperty("assembly.skipAssembly", "true"); + properties.setProperty("shade.skip", "true"); + properties.setProperty("maven.war.skip", "true"); + properties.setProperty("maven.rar.skip", "true"); + properties.setProperty("changelog.skip", "true"); + properties.setProperty("checkstyle.skip", "true"); + properties.setProperty("maven.doap.skip", "true"); + properties.setProperty("maven.javadoc.skip", "true"); + properties.setProperty("maven.jxr.skip", "true"); + properties.setProperty("linkcheck.skip", "true"); + properties.setProperty("pmd.skip", "true"); + properties.setProperty("mpir.skip", "true"); + properties.setProperty("gpg.skip", "true"); + properties.setProperty("jdepend.skip", "true"); + + String javacLocation = "%s%sbin%sjavac".formatted(JavaHome, File.separator, File.separator); + pomGoals.add("-Dmaven.compiler.fork=true"); + if (Files.exists(Path.of(javacLocation))) { + pomGoals.add("-Dmaven.compiler.executable=%s".formatted(javacLocation)); + } + + InvocationRequest request = new DefaultInvocationRequest(); + + Integer timeout = 30 * 60; // 30 minutes in seconds + + request.setShellEnvironmentInherited(false); + request.setPomFile(pomFile); + request.setGoals(pomGoals); + request.setProperties(properties); + request.setAlsoMake(true); + request.setBatchMode(true); + request.setTimeoutInSeconds(timeout); + + request.setJavaHome(new File(JavaHome)); + request.setBaseDirectory(projectDirectory); + request.setInputStream(InputStream.nullInputStream()); + if (invocationOutputHandler != null) { + request.setOutputHandler(invocationOutputHandler); + request.setErrorHandler(invocationOutputHandler); + } + + if (userSettingsFilePath != null && !userSettingsFilePath.isEmpty() && !userSettingsFilePath.isBlank()) { + Path pa = Path.of(userSettingsFilePath); + if (Files.exists(pa) && Files.isRegularFile(pa)) { + request.setUserSettingsFile(new File(userSettingsFilePath)); + } + } + + if (javaToolOptions != null && !javaToolOptions.isEmpty()) { + request.addShellEnvironment("JAVA_TOOL_OPTIONS", javaToolOptions); + } + + Main.logger.info("Building with pom=%s goals=%s properties=%s%n" + .formatted(pomFilePath, + pomGoals, + properties)); + + try { + Invoker invoker = new DefaultInvoker(); + if (invokerLogger != null) { + invoker.setLogger(invokerLogger); + } + + invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); + + InvocationResult result = invoker.execute(request); + + Main.logger.info("Building with pom={} goals={} properties={} returned {}", + pomFile, + pomGoals, + properties, + result.getExitCode()); + + return result.getExitCode(); + } catch (MavenInvocationException e) { + throw e; + } + } + + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, + String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { + Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); + String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); + ArrayList goals = new ArrayList<>(); + goals.add(goal); + + if (javaVersion != null && !javaVersion.isBlank()) { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger, + javaToolOptions) == 0; + } else { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger, + javaToolOptions) == 0; + } + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/runners/maven/TestAssertedLogger.java b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/TestAssertedLogger.java new file mode 100644 index 00000000..ced5965f --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/runners/maven/TestAssertedLogger.java @@ -0,0 +1,192 @@ +package com.github.gilesi.illico.runners.maven; + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.IOException; + +public class TestAssertedLogger implements InvokerLogger, InvocationOutputHandler { + + private InvokerLogger invokerLogger = null; + private InvocationOutputHandler invocationOutputHandler = null; + private boolean testFailed = false; + + public TestAssertedLogger(Object logger) { + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + } + + + public void debug(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message); + } + } + + public void debug(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message, throwable); + } + } + + public boolean isDebugEnabled() { + if (invokerLogger != null) { + return invokerLogger.isDebugEnabled(); + } + + return false; + } + + public void info(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message); + } + } + + public void info(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message, throwable); + } + } + + public boolean isInfoEnabled() { + if (invokerLogger != null) { + return invokerLogger.isInfoEnabled(); + } + + return false; + } + + public void warn(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message); + } + } + + public void warn(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message, throwable); + } + } + + public boolean isWarnEnabled() { + if (invokerLogger != null) { + return invokerLogger.isWarnEnabled(); + } + + return false; + } + + public void error(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message); + } + } + + public void error(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message, throwable); + } + } + + public boolean isErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isErrorEnabled(); + } + + return false; + } + + public void fatalError(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message); + } + } + + public void fatalError(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message, throwable); + } + } + + public boolean isFatalErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isFatalErrorEnabled(); + } + + return false; + } + + public int getThreshold() { + if (invokerLogger != null) { + return invokerLogger.getThreshold(); + } + + return 0; + } + + public void setThreshold(int threshold) { + if (invokerLogger != null) { + invokerLogger.setThreshold(threshold); + } + } + + public void consumeLine(String line) throws IOException { + if (line.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invocationOutputHandler != null) { + invocationOutputHandler.consumeLine(line); + } + } + + public boolean HasTestFailed() { + return testFailed; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/ReportItem.java b/Illico/src/main/java/com/github/gilesi/illico/testing/ReportItem.java new file mode 100644 index 00000000..459c6778 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/ReportItem.java @@ -0,0 +1,65 @@ +package com.github.gilesi.illico.testing; + +import com.github.gilesi.illico.Constants; +import com.github.gilesi.illico.testing.models.Testcase; + +public class ReportItem { + public String Name; + public String Version; + private String TestName; + private String TestResult; + private String ErrorDetails; + + public ReportItem(String projectName, String projectCommit, Testcase testcase) { + this.TestName = "%s.%s".formatted(testcase.ClassName, testcase.Name); + this.TestResult = ((testcase.Error != null) || (testcase.Failure != null)) ? Constants.RED_TEST : Constants.GREEN_TEST; + this.ErrorDetails = (testcase.Error != null) ? testcase.Error.Message : ""; + this.Name = projectName; + this.Version = projectCommit; + } + + public String getName() { + return Name; + } + + public void setName(String name) { + Name = name; + } + + public String getVersion() { + return Version; + } + + public void setVersion(String version) { + Version = version; + } + + public String getTestName() { + return TestName; + } + + public void setTestName(String testName) { + TestName = testName; + } + + public String getTestResult() { + return TestResult; + } + + public void setTestResult(String testResult) { + TestResult = testResult; + } + + public String getErrorDetails() { + return ErrorDetails; + } + + public void setErrorDetails(String errorDetails) { + ErrorDetails = errorDetails; + } + + @Override + public String toString() { + return "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"".formatted(Name, Version, TestName, TestResult, ErrorDetails); + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/XmlParser.java b/Illico/src/main/java/com/github/gilesi/illico/testing/XmlParser.java new file mode 100644 index 00000000..4929b28b --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/XmlParser.java @@ -0,0 +1,33 @@ +package com.github.gilesi.illico.testing; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.github.gilesi.illico.testing.models.Testsuite; +import com.github.gilesi.illico.testing.models.Testsuites; + +import java.io.File; +import java.io.IOException; + +public class XmlParser { + + private static final XmlMapper mapper = XmlMapper + .builder() + .defaultUseWrapper(false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + public static Testsuite deserializeTestsuite(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuite.class); + } + + public static Testsuites deserializeTestsuites(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuites.class); + } + + public static void serialize(String XmlPath, Object obj) throws IOException { + File fi = new File(XmlPath); + mapper.writeValue(fi, obj); + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/gradle/GradleHarness.java b/Illico/src/main/java/com/github/gilesi/illico/testing/gradle/GradleHarness.java new file mode 100644 index 00000000..53b5b90f --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/gradle/GradleHarness.java @@ -0,0 +1,52 @@ +package com.github.gilesi.illico.testing.gradle; + +import com.github.gilesi.illico.FileUtils; +import com.github.gilesi.illico.Main; +import com.github.gilesi.illico.testing.ReportItem; +import com.github.gilesi.illico.testing.XmlParser; +import com.github.gilesi.illico.testing.models.Testcase; +import com.github.gilesi.illico.testing.models.Testsuite; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class GradleHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, + ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%stest-results%stest".formatted(targetLocation, File.separator, + File.separator); + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, + String buildGradleFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path buildGradleFilePath = Path.of(buildGradleFileLocation); + String targetLocation = "%s%sbuild".formatted(buildGradleFilePath.getParent().toAbsolutePath(), File.separator); + + if (Files.isDirectory(Path.of(targetLocation))) { + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + Main.logger.info(e); + } + } + + return reportItems; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Error.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Error.java new file mode 100644 index 00000000..c0b06c6c --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Error.java @@ -0,0 +1,17 @@ +package com.github.gilesi.illico.testing.models; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; + +public class Error { + @JacksonXmlProperty(isAttribute = true, localName = "message") + public String Message; + + @JacksonXmlProperty(isAttribute = true, localName = "type") + public String Type; + + @JacksonXmlText + @JacksonXmlCData + private String Data; +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Properties.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Properties.java new file mode 100644 index 00000000..5828312b --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Properties.java @@ -0,0 +1,13 @@ +package com.github.gilesi.illico.testing.models; + +public class Properties { + private Property[] property; + + public Property[] getProperty() { + return property; + } + + public void setProperty(Property[] value) { + this.property = value; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Property.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Property.java new file mode 100644 index 00000000..307faddc --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Property.java @@ -0,0 +1,22 @@ +package com.github.gilesi.illico.testing.models; + +public class Property { + private String name; + private String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testcase.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testcase.java new file mode 100644 index 00000000..c19eb2ea --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testcase.java @@ -0,0 +1,23 @@ +package com.github.gilesi.illico.testing.models; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + +public class Testcase { + @JacksonXmlElementWrapper(localName = "error") + public com.github.gilesi.illico.testing.models.Error Error; + + @JacksonXmlElementWrapper(localName = "failure") + public Error Failure; + + @JacksonXmlElementWrapper(localName = "name") + public String Name; + + @JacksonXmlElementWrapper(localName = "classname") + public String ClassName; + + @JacksonXmlElementWrapper(localName = "time") + public String Time; + + @JacksonXmlElementWrapper(localName = "system-out") + public String SystemOut; +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuite.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuite.java new file mode 100644 index 00000000..3a956c05 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuite.java @@ -0,0 +1,103 @@ +package com.github.gilesi.illico.testing.models; + +public class Testsuite { + private Properties properties; + private Testcase[] testcase; + private String xmlnsXsi; + private String xsiNoNamespaceSchemaLocation; + private String version; + private String name; + private String time; + private String tests; + private String errors; + private String skipped; + private String failures; + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties value) { + this.properties = value; + } + + public Testcase[] getTestcase() { + return testcase; + } + + public void setTestcase(Testcase[] value) { + this.testcase = value; + } + + public String getXmlnsXsi() { + return xmlnsXsi; + } + + public void setXmlnsXsi(String value) { + this.xmlnsXsi = value; + } + + public String getXsiNoNamespaceSchemaLocation() { + return xsiNoNamespaceSchemaLocation; + } + + public void setXsiNoNamespaceSchemaLocation(String value) { + this.xsiNoNamespaceSchemaLocation = value; + } + + public String getVersion() { + return version; + } + + public void setVersion(String value) { + this.version = value; + } + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getTime() { + return time; + } + + public void setTime(String value) { + this.time = value; + } + + public String getTests() { + return tests; + } + + public void setTests(String value) { + this.tests = value; + } + + public String getErrors() { + return errors; + } + + public void setErrors(String value) { + this.errors = value; + } + + public String getSkipped() { + return skipped; + } + + public void setSkipped(String value) { + this.skipped = value; + } + + public String getFailures() { + return failures; + } + + public void setFailures(String value) { + this.failures = value; + } +} \ No newline at end of file diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuites.java b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuites.java new file mode 100644 index 00000000..1114e392 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/models/Testsuites.java @@ -0,0 +1,13 @@ +package com.github.gilesi.illico.testing.models; + +public class Testsuites { + private Testsuite[] testsuites; + + public Testsuite[] getTestsuites() { + return testsuites; + } + + public void setTestsuites(Testsuite[] value) { + this.testsuites = value; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/testing/surefire/SurefireHarness.java b/Illico/src/main/java/com/github/gilesi/illico/testing/surefire/SurefireHarness.java new file mode 100644 index 00000000..f077354c --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/testing/surefire/SurefireHarness.java @@ -0,0 +1,49 @@ +package com.github.gilesi.illico.testing.surefire; + +import com.github.gilesi.illico.FileUtils; +import com.github.gilesi.illico.Main; +import com.github.gilesi.illico.testing.ReportItem; +import com.github.gilesi.illico.testing.models.Testcase; +import com.github.gilesi.illico.testing.models.Testsuite; +import com.github.gilesi.illico.testing.XmlParser; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class SurefireHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%ssurefire-reports".formatted(targetLocation, File.separator); + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, String pomFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path pomFilePath = Path.of(pomFileLocation); + String targetLocation = "%s%starget".formatted(pomFilePath.getParent().toAbsolutePath(), File.separator); + + if (Files.isDirectory(Path.of(targetLocation))) { + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + Main.logger.info(e); + } + } + + return reportItems; + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/tools/ConfGen.java b/Illico/src/main/java/com/github/gilesi/illico/tools/ConfGen.java new file mode 100644 index 00000000..489cc0af --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/tools/ConfGen.java @@ -0,0 +1,23 @@ +package com.github.gilesi.illico.tools; + +import com.github.gilesi.illico.Constants; +import com.github.gilesi.illico.Main; +import com.github.gilesi.illico.ProcessUtils; + +import java.io.IOException; +import java.nio.file.Path; + +public class ConfGen { + public static void runConfGen(String GilesiRepositoryLocation, String libraryConfig, String outputTestProject, String libraryLocation) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx8g", + "-Xms8g", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.CONF_GEN_LOCATION).toString(), + libraryConfig, + outputTestProject, + libraryLocation + }, null, Main.loggerConfGen); + } +} diff --git a/Illico/src/main/java/com/github/gilesi/illico/tools/TestGen.java b/Illico/src/main/java/com/github/gilesi/illico/tools/TestGen.java new file mode 100644 index 00000000..289ee991 --- /dev/null +++ b/Illico/src/main/java/com/github/gilesi/illico/tools/TestGen.java @@ -0,0 +1,44 @@ +package com.github.gilesi.illico.tools; + +import com.github.gilesi.illico.Constants; +import com.github.gilesi.illico.Main; +import com.github.gilesi.illico.ProcessUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestGen { + public static final Logger logger = LogManager.getLogger(); + + public static void runTestGen(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory, String libraryConfig) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx8g", + "-Xms8g", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.TEST_GEN_LOCATION).toString(), + traceFile, + outputCodeDirectory, + libraryConfig + }, null, Main.loggerTraceGen); + } + + public static void runTraceDiff(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory, String libraryConfig) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx32768m", + "-Xms16384m", + "-Xss1024m", + "-XX:ParallelGCThreads=8", + "-XX:InitiatingHeapOccupancyPercent=70", + "-XX:+UnlockDiagnosticVMOptions", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.TRACE_DIFF_LOCATION).toString(), + traceFile, + outputCodeDirectory, + libraryConfig + }, null, Main.loggerTraceDiff); + } +} \ No newline at end of file diff --git a/Illico/src/main/resources/log4j2.xml b/Illico/src/main/resources/log4j2.xml new file mode 100644 index 00000000..6ef0deaf --- /dev/null +++ b/Illico/src/main/resources/log4j2.xml @@ -0,0 +1,82 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IllicoRun.sh b/IllicoRun.sh new file mode 100755 index 00000000..5c28447b --- /dev/null +++ b/IllicoRun.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# illico requires the use of other subprojects that must be precompiled before running, and pointed to it via the gilesi repo arg. +# first compile everything +sh ./compile.sh + +export MAVEN_HOME="/snap/intellij-idea-ultimate/current/plugins/maven/lib/maven3" + +# then run illico for sample usage +# this commands starts the experience on the compsuite dataset copied at "/home/gus/Datasets/compsuite3", and limits it to just the project id "i-3" +# note that the compsuite dataset folder layout is our own format, and omitting "i-3" will run the entire experience on every project. +java -Xms8g -Xmx8g -jar ./Illico/build/libs/com.github.gilesi.illico.jar "/home/gus/Datasets/compsuite3/i-5/old" "com.ctrip.framework.apollo:apollo-client:1.4.0" "./illico-sample-results" "$PWD" + +# list of configurable hardocded options scattered throughout the entire project: +# illico/src/main/java/com/github/gilesi/illico/Constants.java +# TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java diff --git a/compile.sh b/compile.sh index 5a631b5b..cf02e391 100755 --- a/compile.sh +++ b/compile.sh @@ -57,3 +57,13 @@ cd Maestro sh ./gradlew shadowJar --warning-mode all cd .. +echo +echo =========================================================== +echo Building Illico +echo =========================================================== +echo + +# build illico +cd Illico +sh ./gradlew shadowJar --warning-mode all +cd .. From 6259e91f67c70b80c43802b76519a516a6674737 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Thu, 3 Oct 2024 13:09:35 +0200 Subject: [PATCH 216/244] Sync with local --- .../java/com/github/gilesi/illico/Main.java | 21 ++++++++++++++++--- IllicoRun.sh | 2 +- 2 files changed, 19 insertions(+), 4 deletions(-) diff --git a/Illico/src/main/java/com/github/gilesi/illico/Main.java b/Illico/src/main/java/com/github/gilesi/illico/Main.java index bea25abf..bad0bd8a 100644 --- a/Illico/src/main/java/com/github/gilesi/illico/Main.java +++ b/Illico/src/main/java/com/github/gilesi/illico/Main.java @@ -30,7 +30,7 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept } if (args.length < 4) { - logger.info("Usage: "); + logger.info("Usage: "); return; } @@ -38,10 +38,15 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept String libraryIdentifier = args[1]; String outputFolder = args[2]; String GilesiRepositoryLocation = args[3]; + String optionalCustomTestCommand = null; + + if (args.length > 4) { + optionalCustomTestCommand = args[4]; + } ProjectRunner.runMavenGoalOnRepository( - clientLocation, - "dependency:get -Dartifact=%s:jar:sources".formatted(libraryIdentifier), + clientLocation, + "dependency:sources", null, "1.8", new Log4JLogger(), @@ -58,6 +63,16 @@ public static void main(String[] args) throws MavenInvocationException, IOExcept String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false"; + if (optionalCustomTestCommand != null && + !optionalCustomTestCommand.isEmpty() && + !optionalCustomTestCommand.equals("N/A")) { + testCmd = optionalCustomTestCommand; + } + + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + TestAssertedLogger testAssertedLogger = new TestAssertedLogger( new Log4JLogger( logger, diff --git a/IllicoRun.sh b/IllicoRun.sh index 5c28447b..3fb75a7d 100755 --- a/IllicoRun.sh +++ b/IllicoRun.sh @@ -9,7 +9,7 @@ export MAVEN_HOME="/snap/intellij-idea-ultimate/current/plugins/maven/lib/maven3 # then run illico for sample usage # this commands starts the experience on the compsuite dataset copied at "/home/gus/Datasets/compsuite3", and limits it to just the project id "i-3" # note that the compsuite dataset folder layout is our own format, and omitting "i-3" will run the entire experience on every project. -java -Xms8g -Xmx8g -jar ./Illico/build/libs/com.github.gilesi.illico.jar "/home/gus/Datasets/compsuite3/i-5/old" "com.ctrip.framework.apollo:apollo-client:1.4.0" "./illico-sample-results" "$PWD" +java -Xms8g -Xmx8g -jar ./Illico/build/libs/com.github.gilesi.illico.jar "/home/gus/Datasets/compsuite3/i-7/old" "org.slf4j:slf4j-api:1.7.9" "./illico-sample-results" "$PWD" "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=Slf4jLogFilterTest#test_slf4j" # list of configurable hardocded options scattered throughout the entire project: # illico/src/main/java/com/github/gilesi/illico/Constants.java From 3bd02faa4bd017df64a5eb61d4ee8b2bc9b331f4 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 4 Nov 2024 09:46:48 +0100 Subject: [PATCH 217/244] Rename dependabot.yml to dependabot.disabled.yml --- .github/{dependabot.yml => dependabot.disabled.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{dependabot.yml => dependabot.disabled.yml} (100%) diff --git a/.github/dependabot.yml b/.github/dependabot.disabled.yml similarity index 100% rename from .github/dependabot.yml rename to .github/dependabot.disabled.yml From 31542f772290cd81006e299620ed8764e4b103ff Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:48:49 +0100 Subject: [PATCH 218/244] Bump net.bytebuddy:byte-buddy-agent in /Instrumentation (#100) Bumps [net.bytebuddy:byte-buddy-agent](https://github.com/raphw/byte-buddy) from 1.15.1 to 1.15.8. - [Release notes](https://github.com/raphw/byte-buddy/releases) - [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md) - [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.1...byte-buddy-1.15.8) --- updated-dependencies: - dependency-name: net.bytebuddy:byte-buddy-agent dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Instrumentation/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 7df27da0..5cd5195b 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -17,7 +17,7 @@ repositories { dependencies { implementation 'net.bytebuddy:byte-buddy:1.15.1' - implementation 'net.bytebuddy:byte-buddy-agent:1.15.1' + implementation 'net.bytebuddy:byte-buddy-agent:1.15.8' implementation 'com.thoughtworks.xstream:xstream:1.4.20' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' } From e58a8b7f9a2944b3357f6eb35d1cf31e4636c094 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:07 +0100 Subject: [PATCH 219/244] Bump com.fasterxml.jackson.core:jackson-core in /TestGenerator (#98) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.17.2...jackson-core-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TestGenerator/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestGenerator/build.gradle b/TestGenerator/build.gradle index 0dc7349f..427a81d1 100644 --- a/TestGenerator/build.gradle +++ b/TestGenerator/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' From cc7533d1f9102c24e868e3b251d980014ff72f3d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:15 +0100 Subject: [PATCH 220/244] Bump com.fasterxml.jackson:jackson-base in /TestGenerator (#96) Bumps [com.fasterxml.jackson:jackson-base](https://github.com/FasterXML/jackson-bom) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.2...jackson-bom-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-base dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TestGenerator/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestGenerator/build.gradle b/TestGenerator/build.gradle index 427a81d1..d057b5ad 100644 --- a/TestGenerator/build.gradle +++ b/TestGenerator/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' - implementation 'com.fasterxml.jackson:jackson-base:2.17.2' + implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.commons:commons-text:1.12.0' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } From f2647687b6a9afb0de121d150aac387b48f4afc5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:26 +0100 Subject: [PATCH 221/244] Bump org.junit:junit-bom from 5.11.0 to 5.11.3 in /Maestro (#74) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.0 to 5.11.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index fe7fc7eb..e58e6fb3 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' - testImplementation platform('org.junit:junit-bom:5.11.0') + testImplementation platform('org.junit:junit-bom:5.11.3') testImplementation 'org.junit.jupiter:junit-jupiter' implementation 'org.apache.logging.log4j:log4j-core:2.24.0' implementation 'org.apache.logging.log4j:log4j-api:2.24.0' From 7dcd220cf6c2b26f14697544d7b5d59d0c7c2dd4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:37 +0100 Subject: [PATCH 222/244] Bump org.junit:junit-bom from 5.11.0 to 5.11.3 in /CompSuiteHarness (#75) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.0 to 5.11.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index e98e3803..0f34c4ab 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -31,7 +31,7 @@ dependencies { implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' - testImplementation platform('org.junit:junit-bom:5.11.0') + testImplementation platform('org.junit:junit-bom:5.11.3') testImplementation 'org.junit.jupiter:junit-jupiter' implementation 'org.apache.logging.log4j:log4j-core:2.24.0' implementation 'org.apache.logging.log4j:log4j-api:2.24.0' From baf154d2fa8d19804f368d6b95216e4fd9a19336 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:49:53 +0100 Subject: [PATCH 223/244] Bump org.junit:junit-bom in /Samples/Gradle/samplelibrary (#76) Bumps [org.junit:junit-bom](https://github.com/junit-team/junit5) from 5.11.0 to 5.11.3. - [Release notes](https://github.com/junit-team/junit5/releases) - [Commits](https://github.com/junit-team/junit5/compare/r5.11.0...r5.11.3) --- updated-dependencies: - dependency-name: org.junit:junit-bom dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Samples/Gradle/samplelibrary/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/Gradle/samplelibrary/build.gradle b/Samples/Gradle/samplelibrary/build.gradle index 569db1c9..7068af54 100644 --- a/Samples/Gradle/samplelibrary/build.gradle +++ b/Samples/Gradle/samplelibrary/build.gradle @@ -12,7 +12,7 @@ repositories { dependencies { implementation 'com.fasterxml:jackson-xml-databind:0.6.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' - testImplementation platform('org.junit:junit-bom:5.11.0') + testImplementation platform('org.junit:junit-bom:5.11.3') testImplementation 'org.junit.jupiter:junit-jupiter' testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' } From 46d74bd30098f5c0eb76f6ea46b8f8d8e14baaf4 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:50:04 +0100 Subject: [PATCH 224/244] Bump com.fasterxml.jackson.core:jackson-annotations in /CompSuiteHarness (#79) Bumps [com.fasterxml.jackson.core:jackson-annotations](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index 0f34c4ab..d4a2aed5 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -27,7 +27,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' From 8c2b4fa10d34be8b4605345fa3d192dd13301a69 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:50:23 +0100 Subject: [PATCH 225/244] Bump com.fasterxml.jackson.core:jackson-core in /CompSuiteHarness (#82) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.17.2...jackson-core-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index d4a2aed5..d9946c6e 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' From a9f60d7b6336749d96f3de1b35bfeecbd061c595 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:50:32 +0100 Subject: [PATCH 226/244] Bump com.fasterxml.jackson.core:jackson-annotations in /Maestro (#87) Bumps [com.fasterxml.jackson.core:jackson-annotations](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-annotations dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index e58e6fb3..ab0880d2 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -27,7 +27,7 @@ dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' From af5d0389fff7bae704b4bd7bfcc4d1c067c67586 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:50:42 +0100 Subject: [PATCH 227/244] Bump com.fasterxml.jackson.core:jackson-databind (#93) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Samples/Gradle/sampleclient/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Samples/Gradle/sampleclient/build.gradle b/Samples/Gradle/sampleclient/build.gradle index 785dae04..fd2060e5 100644 --- a/Samples/Gradle/sampleclient/build.gradle +++ b/Samples/Gradle/sampleclient/build.gradle @@ -11,7 +11,7 @@ repositories { dependencies { implementation project(':samplelibrary') - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' } testing { From de846410f3fd73de9ace20496f26ca1cea96cee5 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:50:54 +0100 Subject: [PATCH 228/244] Bump com.fasterxml.jackson.core:jackson-core in /TraceDiff (#89) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.17.2...jackson-core-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TraceDiff/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TraceDiff/build.gradle b/TraceDiff/build.gradle index aa0f4112..3f4d48ce 100644 --- a/TraceDiff/build.gradle +++ b/TraceDiff/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' From fce4f722d69bdcb5d35b15627726ebc2f286bbd7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:51:11 +0100 Subject: [PATCH 229/244] Bump com.fasterxml.jackson.core:jackson-databind in /TestGenerator (#94) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TestGenerator/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TestGenerator/build.gradle b/TestGenerator/build.gradle index d057b5ad..d7f64a88 100644 --- a/TestGenerator/build.gradle +++ b/TestGenerator/build.gradle @@ -26,7 +26,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.commons:commons-text:1.12.0' From 0a3144d1092eb13793c5c5847ae044401ac17932 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:51:36 +0100 Subject: [PATCH 230/244] Bump com.fasterxml.jackson.core:jackson-core in /Maestro (#85) Bumps [com.fasterxml.jackson.core:jackson-core](https://github.com/FasterXML/jackson-core) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-core/compare/jackson-core-2.17.2...jackson-core-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-core dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index ab0880d2..57cb5d62 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -24,7 +24,7 @@ repositories { } dependencies { - implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' From bb33f49739ece68d5c80eb0e1d152797eb85b7e1 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:51:46 +0100 Subject: [PATCH 231/244] Bump com.fasterxml.jackson.core:jackson-databind in /TraceDiff (#91) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TraceDiff/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TraceDiff/build.gradle b/TraceDiff/build.gradle index 3f4d48ce..eb52b3cd 100644 --- a/TraceDiff/build.gradle +++ b/TraceDiff/build.gradle @@ -26,7 +26,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.commons:commons-text:1.12.0' From 61b4130a65b7001c4019b673c0e4644d3a4331d7 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:52:18 +0100 Subject: [PATCH 232/244] Bump com.fasterxml.jackson:jackson-base in /TraceDiff (#90) Bumps [com.fasterxml.jackson:jackson-base](https://github.com/FasterXML/jackson-bom) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.2...jackson-bom-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-base dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- TraceDiff/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/TraceDiff/build.gradle b/TraceDiff/build.gradle index eb52b3cd..2014ba84 100644 --- a/TraceDiff/build.gradle +++ b/TraceDiff/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' - implementation 'com.fasterxml.jackson:jackson-base:2.17.2' + implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.commons:commons-text:1.12.0' implementation 'com.thoughtworks.xstream:xstream:1.4.20' } From a8e71112ac81ca9d59426ede6fccd6546b1c78d5 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Tue, 5 Nov 2024 14:54:11 +0100 Subject: [PATCH 233/244] Rename dependabot.disabled.yml to dependabot.yml --- .github/{dependabot.disabled.yml => dependabot.yml} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename .github/{dependabot.disabled.yml => dependabot.yml} (100%) diff --git a/.github/dependabot.disabled.yml b/.github/dependabot.yml similarity index 100% rename from .github/dependabot.disabled.yml rename to .github/dependabot.yml From f55c89278cec7662b8e6d71d545e29c12c7e6707 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:55:04 +0100 Subject: [PATCH 234/244] Bump net.bytebuddy:byte-buddy from 1.15.1 to 1.15.10 in /Instrumentation (#108) Bumps [net.bytebuddy:byte-buddy](https://github.com/raphw/byte-buddy) from 1.15.1 to 1.15.10. - [Release notes](https://github.com/raphw/byte-buddy/releases) - [Changelog](https://github.com/raphw/byte-buddy/blob/master/release-notes.md) - [Commits](https://github.com/raphw/byte-buddy/compare/byte-buddy-1.15.1...byte-buddy-1.15.10) --- updated-dependencies: - dependency-name: net.bytebuddy:byte-buddy dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Instrumentation/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Instrumentation/build.gradle b/Instrumentation/build.gradle index 5cd5195b..77d6c6f6 100644 --- a/Instrumentation/build.gradle +++ b/Instrumentation/build.gradle @@ -16,7 +16,7 @@ repositories { } dependencies { - implementation 'net.bytebuddy:byte-buddy:1.15.1' + implementation 'net.bytebuddy:byte-buddy:1.15.10' implementation 'net.bytebuddy:byte-buddy-agent:1.15.8' implementation 'com.thoughtworks.xstream:xstream:1.4.20' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' From 0a2cdcd733e316b218a997d4120f8890a5b7c439 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:55:16 +0100 Subject: [PATCH 235/244] Bump org.apache.logging.log4j:log4j-core in /CompSuiteHarness (#107) Bumps org.apache.logging.log4j:log4j-core from 2.24.0 to 2.24.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-core dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index d9946c6e..a6a855d7 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -33,7 +33,7 @@ dependencies { implementation 'org.apache.maven.shared:maven-invoker:3.3.0' testImplementation platform('org.junit:junit-bom:5.11.3') testImplementation 'org.junit.jupiter:junit-jupiter' - implementation 'org.apache.logging.log4j:log4j-core:2.24.0' + implementation 'org.apache.logging.log4j:log4j-core:2.24.1' implementation 'org.apache.logging.log4j:log4j-api:2.24.0' } From 120459a741c4143151275363ceedbfe3437ce23e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:55:26 +0100 Subject: [PATCH 236/244] Bump org.apache.logging.log4j:log4j-api in /Maestro (#106) Bumps org.apache.logging.log4j:log4j-api from 2.24.0 to 2.24.1. --- updated-dependencies: - dependency-name: org.apache.logging.log4j:log4j-api dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index 57cb5d62..6c0ec371 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -34,7 +34,7 @@ dependencies { testImplementation platform('org.junit:junit-bom:5.11.3') testImplementation 'org.junit.jupiter:junit-jupiter' implementation 'org.apache.logging.log4j:log4j-core:2.24.0' - implementation 'org.apache.logging.log4j:log4j-api:2.24.0' + implementation 'org.apache.logging.log4j:log4j-api:2.24.1' } jar { From 27278a27a796a56f50be04110fea1d8ca1edcfe0 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:55:54 +0100 Subject: [PATCH 237/244] Bump com.fasterxml.jackson.dataformat:jackson-dataformat-xml in /Maestro (#103) Bumps [com.fasterxml.jackson.dataformat:jackson-dataformat-xml](https://github.com/FasterXML/jackson-dataformat-xml) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-dataformat-xml/compare/jackson-dataformat-xml-2.17.2...jackson-dataformat-xml-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-xml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index 6c0ec371..88f64cf3 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -25,7 +25,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' From d2f660956dd01c41854698c79cb28a779998590d Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:56:04 +0100 Subject: [PATCH 238/244] Bump com.fasterxml.jackson.core:jackson-databind in /CompSuiteHarness (#102) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index a6a855d7..8f134a07 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -26,7 +26,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' implementation 'org.apache.maven:maven-core:3.9.9' From c2a0c1d70a50cc83b59951cc97f9821369fbf3e6 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:56:44 +0100 Subject: [PATCH 239/244] Bump com.fasterxml.jackson.dataformat:jackson-dataformat-xml (#80) Bumps [com.fasterxml.jackson.dataformat:jackson-dataformat-xml](https://github.com/FasterXML/jackson-dataformat-xml) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-dataformat-xml/compare/jackson-dataformat-xml-2.17.2...jackson-dataformat-xml-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.dataformat:jackson-dataformat-xml dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index 8f134a07..e961d1de 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -25,7 +25,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' - implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.17.2' From ce324f67cfe9f014ad886f7dde681e9bb6606565 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:56:53 +0100 Subject: [PATCH 240/244] Bump com.fasterxml.jackson:jackson-base in /CompSuiteHarness (#81) Bumps [com.fasterxml.jackson:jackson-base](https://github.com/FasterXML/jackson-bom) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.2...jackson-bom-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-base dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index e961d1de..6c2c8439 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' - implementation 'com.fasterxml.jackson:jackson-base:2.17.2' + implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' testImplementation platform('org.junit:junit-bom:5.11.3') From e40b46cdcb09e3fdc1480cd3a47e07303857f8c9 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:57:14 +0100 Subject: [PATCH 241/244] Bump com.fasterxml.jackson:jackson-base in /Maestro (#84) Bumps [com.fasterxml.jackson:jackson-base](https://github.com/FasterXML/jackson-bom) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.17.2...jackson-bom-2.18.1) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-base dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index 88f64cf3..b0a91e9d 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' - implementation 'com.fasterxml.jackson:jackson-base:2.17.2' + implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' testImplementation platform('org.junit:junit-bom:5.11.3') From 5a67f2f7f64c683560dde39400613877f244f32e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Tue, 5 Nov 2024 14:57:31 +0100 Subject: [PATCH 242/244] Bump com.fasterxml.jackson.core:jackson-databind in /Maestro (#86) Bumps [com.fasterxml.jackson.core:jackson-databind](https://github.com/FasterXML/jackson) from 2.17.2 to 2.18.1. - [Commits](https://github.com/FasterXML/jackson/commits) --- updated-dependencies: - dependency-name: com.fasterxml.jackson.core:jackson-databind dependency-type: direct:production update-type: version-update:semver-minor ... Signed-off-by: dependabot[bot] Co-authored-by: dependabot[bot] <49699333+dependabot[bot]@users.noreply.github.com> --- Maestro/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Maestro/build.gradle b/Maestro/build.gradle index b0a91e9d..0bdfc681 100644 --- a/Maestro/build.gradle +++ b/Maestro/build.gradle @@ -26,7 +26,7 @@ repositories { dependencies { implementation 'com.fasterxml.jackson.core:jackson-core:2.18.1' implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' - implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' implementation 'com.fasterxml.jackson:jackson-base:2.18.1' implementation 'org.apache.maven:maven-core:3.9.9' From 3f93c5d47aea199d86197763cbb014bffd1df503 Mon Sep 17 00:00:00 2001 From: Gustave Monce Date: Mon, 18 Nov 2024 09:16:49 +0100 Subject: [PATCH 243/244] Coverage Tools --- ConfGenCoverage/.gitignore | 39 +++ ConfGenCoverage/build.gradle | 81 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + ConfGenCoverage/gradlew | 246 ++++++++++++++++ ConfGenCoverage/gradlew.bat | 91 ++++++ .../gilesi/confgencoverage/CodeType.java | 11 + .../github/gilesi/confgencoverage/Main.java | 177 ++++++++++++ .../confgencoverage/RoseauDescriptor.java | 88 ++++++ ...UnsupportedJavaPrimitiveTypeException.java | 7 + .../gilesi/confgencoverage/models/Class.java | 9 + .../models/InstrumentationParameters.java | 8 + .../gilesi/confgencoverage/models/Method.java | 8 + .../spoon/SpoonLauncherUtilities.java | 222 ++++++++++++++ Coverage/.gitignore | 39 +++ Coverage/build.gradle | 78 +++++ Coverage/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 63375 bytes .../gradle/wrapper/gradle-wrapper.properties | 7 + Coverage/gradlew | 246 ++++++++++++++++ Coverage/gradlew.bat | 91 ++++++ Coverage/settings.gradle | 2 + .../gilesi/confgencoverage/models/Class.java | 7 + .../models/CoverageParameters.java | 6 + .../gilesi/confgencoverage/models/Method.java | 6 + .../com/github/gilesi/coverage/Agent.java | 149 ++++++++++ .../gilesi/coverage/ConfigurationReader.java | 21 ++ .../com/github/gilesi/coverage/Logger.java | 58 ++++ .../gilesi/coverage/ReachedCollector.java | 39 +++ .../gilesi/coverage/RunMilestoneService.java | 46 +++ .../coverage/visitors/CommonAdvisor.java | 150 ++++++++++ .../coverage/visitors/ConstructorAdvisor.java | 26 ++ .../coverage/visitors/LoggingListener.java | 50 ++++ .../coverage/visitors/MethodAdvisor.java | 27 ++ .../coverage/visitors/MethodInstrumentor.java | 82 ++++++ IllicoCoverage/.gitignore | 39 +++ IllicoCoverage/build.gradle | 81 ++++++ .../gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 60756 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + IllicoCoverage/gradlew | 234 +++++++++++++++ IllicoCoverage/gradlew.bat | 89 ++++++ IllicoCoverage/settings.gradle | 2 + .../gilesi/illicocoverage/Constants.java | 41 +++ .../gilesi/illicocoverage/FileUtils.java | 130 +++++++++ .../github/gilesi/illicocoverage/Main.java | 194 +++++++++++++ .../gilesi/illicocoverage/Orchestrator.java | 267 +++++++++++++++++ .../gilesi/illicocoverage/ProcessUtils.java | 26 ++ .../gilesi/illicocoverage/RunResult.java | 22 ++ .../maven/ConfigurationUtils.java | 31 ++ .../maven/IPluginConfiguration.java | 7 + .../configuration/maven/PomHelper.java | 154 ++++++++++ .../maven/SureFirePluginConfiguration.java | 103 +++++++ .../runners/maven/ConsoleLogger.java | 248 ++++++++++++++++ .../runners/maven/Log4JLogger.java | 271 ++++++++++++++++++ .../runners/maven/ProjectRunner.java | 181 ++++++++++++ .../runners/maven/TestAssertedLogger.java | 192 +++++++++++++ .../illicocoverage/testing/ReportItem.java | 65 +++++ .../illicocoverage/testing/XmlParser.java | 33 +++ .../testing/gradle/GradleHarness.java | 52 ++++ .../illicocoverage/testing/models/Error.java | 17 ++ .../testing/models/Properties.java | 13 + .../testing/models/Property.java | 22 ++ .../testing/models/Testcase.java | 23 ++ .../testing/models/Testsuite.java | 103 +++++++ .../testing/models/Testsuites.java | 13 + .../testing/surefire/SurefireHarness.java | 49 ++++ .../illicocoverage/tools/ConfGenCoverage.java | 23 ++ .../gilesi/illicocoverage/tools/TestGen.java | 44 +++ IllicoCoverage/src/main/resources/log4j2.xml | 82 ++++++ IllicoCoverageRun.sh | 16 ++ compile.sh | 33 +++ 70 files changed, 5030 insertions(+) create mode 100644 ConfGenCoverage/.gitignore create mode 100644 ConfGenCoverage/build.gradle create mode 100644 ConfGenCoverage/gradle/wrapper/gradle-wrapper.jar create mode 100644 ConfGenCoverage/gradle/wrapper/gradle-wrapper.properties create mode 100755 ConfGenCoverage/gradlew create mode 100644 ConfGenCoverage/gradlew.bat create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/CodeType.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/Main.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/RoseauDescriptor.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/exceptions/UnsupportedJavaPrimitiveTypeException.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/InstrumentationParameters.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java create mode 100644 ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/spoon/SpoonLauncherUtilities.java create mode 100644 Coverage/.gitignore create mode 100644 Coverage/build.gradle create mode 100644 Coverage/gradle/wrapper/gradle-wrapper.jar create mode 100644 Coverage/gradle/wrapper/gradle-wrapper.properties create mode 100755 Coverage/gradlew create mode 100644 Coverage/gradlew.bat create mode 100644 Coverage/settings.gradle create mode 100644 Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java create mode 100644 Coverage/src/main/java/com/github/gilesi/confgencoverage/models/CoverageParameters.java create mode 100644 Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/Agent.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/ConfigurationReader.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/Logger.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/ReachedCollector.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/RunMilestoneService.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/visitors/CommonAdvisor.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/visitors/ConstructorAdvisor.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/visitors/LoggingListener.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodAdvisor.java create mode 100644 Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodInstrumentor.java create mode 100644 IllicoCoverage/.gitignore create mode 100644 IllicoCoverage/build.gradle create mode 100644 IllicoCoverage/gradle/wrapper/gradle-wrapper.jar create mode 100644 IllicoCoverage/gradle/wrapper/gradle-wrapper.properties create mode 100755 IllicoCoverage/gradlew create mode 100644 IllicoCoverage/gradlew.bat create mode 100644 IllicoCoverage/settings.gradle create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Constants.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/FileUtils.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Main.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Orchestrator.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/ProcessUtils.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/RunResult.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/ConfigurationUtils.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/IPluginConfiguration.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/PomHelper.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/SureFirePluginConfiguration.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ConsoleLogger.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/Log4JLogger.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ProjectRunner.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/TestAssertedLogger.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/ReportItem.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/XmlParser.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/gradle/GradleHarness.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Error.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Properties.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Property.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testcase.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuite.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuites.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/surefire/SurefireHarness.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/ConfGenCoverage.java create mode 100644 IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/TestGen.java create mode 100644 IllicoCoverage/src/main/resources/log4j2.xml create mode 100755 IllicoCoverageRun.sh diff --git a/ConfGenCoverage/.gitignore b/ConfGenCoverage/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/ConfGenCoverage/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/ConfGenCoverage/build.gradle b/ConfGenCoverage/build.gradle new file mode 100644 index 00000000..cd077321 --- /dev/null +++ b/ConfGenCoverage/build.gradle @@ -0,0 +1,81 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'com.github.gilesi.confgencoverage' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() + //mavenLocal() + maven { + name = "IntelliJ" + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } + maven { + name = "Roseau" + url = "https://maven.pkg.github.com/alien-tools/roseau" + credentials { + username = project.findProperty("gpr.user") + password = project.findProperty("gpr.key") + } + } +} + +dependencies { + implementation 'com.github.maracas:roseau:0.0.2-SNAPSHOT' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' +} + +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.confgencoverage.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.confgencoverage.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.confgencoverage') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.confgencoverage' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=2G" + ] +} diff --git a/ConfGenCoverage/gradle/wrapper/gradle-wrapper.jar b/ConfGenCoverage/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 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≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/ConfGenCoverage/gradlew.bat b/ConfGenCoverage/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/ConfGenCoverage/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/CodeType.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/CodeType.java new file mode 100644 index 00000000..f4f0594e --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/CodeType.java @@ -0,0 +1,11 @@ +package com.github.gilesi.confgencoverage; + +import java.util.EnumSet; + +public enum CodeType { + MAIN, + TEST, + SAMPLE; + + public static final EnumSet ALL = EnumSet.allOf(CodeType.class); +} diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/Main.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/Main.java new file mode 100644 index 00000000..c32b23a9 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/Main.java @@ -0,0 +1,177 @@ +package com.github.gilesi.confgencoverage; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.confgencoverage.exceptions.UnsupportedJavaPrimitiveTypeException; +import com.github.gilesi.confgencoverage.models.Class; +import com.github.gilesi.confgencoverage.models.InstrumentationParameters; +import com.github.gilesi.confgencoverage.models.Method; +import com.github.gilesi.confgencoverage.spoon.SpoonLauncherUtilities; +import com.github.maracas.roseau.api.SpoonAPIExtractor; +import com.github.maracas.roseau.api.model.*; +import com.thoughtworks.xstream.XStream; +import com.thoughtworks.xstream.io.xml.DomDriver; +import spoon.Launcher; +import spoon.reflect.CtModel; + +import java.io.BufferedWriter; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.StandardOpenOption; +import java.util.*; + +public class Main { + private static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + private static String getClassNameFromFQN(String fullyQualifiedName) { + String parameterLessQualifiedName = fullyQualifiedName; + + if (fullyQualifiedName.contains("(")) { + parameterLessQualifiedName = fullyQualifiedName.split("\\(")[0]; + } + + String[] nameElements = parameterLessQualifiedName.split("\\."); + + return String.join(".", Arrays.stream(nameElements).limit(nameElements.length - 1).toArray(String[]::new)); + } + + private static String getMethodNameFromFQN(String fullyQualifiedName) { + String parameterLessQualifiedName = fullyQualifiedName; + + if (fullyQualifiedName.contains("(")) { + parameterLessQualifiedName = fullyQualifiedName.split("\\(")[0]; + } + + String[] nameElements = parameterLessQualifiedName.split("\\."); + + return nameElements[nameElements.length - 1]; + } + + private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String methodName, String methodDescriptor) { + for (Class classToInstrument : instrumentationParameters.InstrumentedAPIClasses) { + if (classToInstrument.ClassName.equals(className)) { + for (Method methodParameter : classToInstrument.ClassMethods) { + if (methodParameter.MethodName.equals(methodName)) { + for (String descriptorToInstrument : methodParameter.MethodDescriptors) { + if (descriptorToInstrument.equals(methodDescriptor)) { + // Element is already in the config, return now + return; + } + } + + // Element doesn't have a descriptor in the config, add now + methodParameter.MethodDescriptors.add(methodDescriptor); + return; + } + } + + // Element doesn't have a method in the config, add now + Method methodParameter = new Method(); + methodParameter.MethodName = methodName; + methodParameter.MethodDescriptors = new ArrayList<>(); + methodParameter.MethodDescriptors.add(methodDescriptor); + + classToInstrument.ClassMethods.add(methodParameter); + return; + } + } + + // Element doesn't have a class in the config, add now + Class classParameter = new Class(); + classParameter.ClassName = className; + classParameter.ClassMethods = new ArrayList<>(); + classParameter.ClassDescriptors = new ArrayList<>(); + Method methodParameter = new Method(); + methodParameter.MethodName = methodName; + methodParameter.MethodDescriptors = new ArrayList<>(); + methodParameter.MethodDescriptors.add(methodDescriptor); + classParameter.ClassMethods.add(methodParameter); + + instrumentationParameters.InstrumentedAPIClasses.add(classParameter); + } + + private static void addToInstrumentationObject(InstrumentationParameters instrumentationParameters, String className, String constructorDescriptor) { + for (Class classToInstrument : instrumentationParameters.InstrumentedAPIClasses) { + if (classToInstrument.ClassName.equals(className)) { + for (String descriptorToInstrument : classToInstrument.ClassDescriptors) { + if (descriptorToInstrument.equals(constructorDescriptor)) { + // Element is already in the config, return now + return; + } + + // Element doesn't have a descriptor in the config, add now + classToInstrument.ClassDescriptors.add(constructorDescriptor); + return; + } + } + } + + // Element doesn't have a class in the config, add now + Class classParameter = new Class(); + classParameter.ClassName = className; + classParameter.ClassMethods = new ArrayList<>(); + classParameter.ClassDescriptors = new ArrayList<>(); + classParameter.ClassDescriptors.add(constructorDescriptor); + + instrumentationParameters.InstrumentedAPIClasses.add(classParameter); + } + + public static void main(String[] args) throws UnsupportedJavaPrimitiveTypeException, IOException { + String apiReportOutputLocation = args[0]; + String traceOutputLocation = args[1]; + String libraryProjectLocation = args[2]; + + Path apiReportOutputPath = Path.of(apiReportOutputLocation); + + System.out.println("Processing Library Project..."); + + Launcher libraryLauncher = SpoonLauncherUtilities.getCommonLauncherInstance(); + SpoonLauncherUtilities.applyProjectToLauncher(libraryLauncher, Path.of(libraryProjectLocation), EnumSet.of(CodeType.MAIN)); + CtModel libraryModel = libraryLauncher.buildModel(); + + // API model for libraries + API libraryApiModel = new SpoonAPIExtractor().extractAPI(libraryModel); + + InstrumentationParameters instrumentationParameters = new InstrumentationParameters(); + instrumentationParameters.InstrumentedAPIClasses = new ArrayList<>(); + instrumentationParameters.traceOutputLocation = traceOutputLocation; + + for (ClassDecl classDecl : libraryApiModel.getExportedTypes() + .filter(ClassDecl.class::isInstance) + .map(ClassDecl.class::cast).toList()) { + + for (ConstructorDecl constructor : classDecl.getConstructors()) { + String className = getClassNameFromFQN(constructor.getQualifiedName()); + String methodDescriptor = RoseauDescriptor.getDescriptor(constructor, false); + + addToInstrumentationObject(instrumentationParameters, className, methodDescriptor); + } + + for (MethodDecl method : classDecl.getAllMethods().toList()) { + String FQN = method.getQualifiedName(); + String className = getClassNameFromFQN(FQN); + String methodName = getMethodNameFromFQN(FQN); + String methodDescriptor = RoseauDescriptor.getDescriptor(method, false); + + addToInstrumentationObject(instrumentationParameters, className, methodName, methodDescriptor); + } + } + + BufferedWriter bufferedWriter = Files.newBufferedWriter(apiReportOutputPath, StandardOpenOption.CREATE); + + try { + String serializedJsonString = objectMapper.writeValueAsString(instrumentationParameters); + bufferedWriter.write(serializedJsonString); + } catch (Exception e) { + System.out.println(String.format("ERROR: Cannot serialize specific argument: %s", e)); + } + + bufferedWriter.close(); + } +} \ No newline at end of file diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/RoseauDescriptor.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/RoseauDescriptor.java new file mode 100644 index 00000000..19be6166 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/RoseauDescriptor.java @@ -0,0 +1,88 @@ +package com.github.gilesi.confgencoverage; + +import com.github.gilesi.confgencoverage.exceptions.UnsupportedJavaPrimitiveTypeException; +import com.github.maracas.roseau.api.model.ConstructorDecl; +import com.github.maracas.roseau.api.model.MethodDecl; +import com.github.maracas.roseau.api.model.ParameterDecl; +import com.github.maracas.roseau.api.model.reference.*; + +import java.util.List; + +public class RoseauDescriptor { + public static String getDescriptor(ConstructorDecl constructorDecl, boolean handleTypeArgs) throws UnsupportedJavaPrimitiveTypeException { + StringBuilder descriptor = new StringBuilder().append('('); + for (ParameterDecl parameterType : constructorDecl.getParameters()) { + descriptor.append(getDescriptor(parameterType, handleTypeArgs)); + } + return descriptor.append(")V").toString(); + } + + public static String getDescriptor(MethodDecl methodDecl, boolean handleTypeArgs) throws UnsupportedJavaPrimitiveTypeException { + StringBuilder descriptor = new StringBuilder().append('('); + for (ParameterDecl parameterType : methodDecl.getParameters()) { + descriptor.append(getDescriptor(parameterType, handleTypeArgs)); + } + return descriptor.append(')').append(getDescriptor(methodDecl.getType(), handleTypeArgs)).toString(); + } + + public static String getDescriptor(ParameterDecl parameterDecl, boolean handleTypeArgs) throws UnsupportedJavaPrimitiveTypeException { + return getDescriptor(parameterDecl.type(), handleTypeArgs); + } + + public static String getDescriptor(ITypeReference iTypeReference, boolean handleTypeArgs) throws UnsupportedJavaPrimitiveTypeException { + switch (iTypeReference) { + case ArrayTypeReference arrayTypeReference -> { + String rest = getDescriptor(arrayTypeReference.componentType(), handleTypeArgs); + for (int i = 0; i < arrayTypeReference.dimension(); i++) { + rest = "[" + rest; + } + return rest; + } + case PrimitiveTypeReference primitiveTypeReference -> { + String name = primitiveTypeReference.getQualifiedName(); + return switch (name) { + case "int" -> "I"; + case "void" -> "V"; + case "boolean" -> "Z"; + case "byte" -> "B"; + case "char" -> "C"; + case "short" -> "S"; + case "double" -> "D"; + case "float" -> "F"; + case "long" -> "J"; + default -> throw new UnsupportedJavaPrimitiveTypeException(name); + }; + } + case TypeParameterReference ignored -> { + //String name = typeParameterReference.getQualifiedName(); + //return "L" + name.replace('.', '/') + ";"; + // That's going to be U getSmething() in the JVM, so return object. + return "Ljava/lang/Object;"; + } + case WildcardTypeReference ignored -> { + //String name = typeDecl.getQualifiedName(); + //return name; + // That's going to be U getSmething() in the JVM, so return object. + return "Ljava/lang/Object;"; + } + case TypeReference typeReference -> { + String typeArgumentString = ""; + if (handleTypeArgs) { + List typeArgs = typeReference.getTypeArguments(); + if (!typeArgs.isEmpty()) { + // Check join string here to be very sure against spec and test it + typeArgumentString = "<%s>".formatted(String.join("", typeArgs.stream().map(t -> { + try { + return getDescriptor(t, true); + } catch (UnsupportedJavaPrimitiveTypeException e) { + throw new RuntimeException(e); + } + }).toList())); + } + } + String name = typeReference.getQualifiedName(); + return "L%s%s;".formatted(name.replace('.', '/'), typeArgumentString); + } + } + } +} diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/exceptions/UnsupportedJavaPrimitiveTypeException.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/exceptions/UnsupportedJavaPrimitiveTypeException.java new file mode 100644 index 00000000..f324c951 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/exceptions/UnsupportedJavaPrimitiveTypeException.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgencoverage.exceptions; + +public class UnsupportedJavaPrimitiveTypeException extends Exception { + public UnsupportedJavaPrimitiveTypeException(String primitive) { + super("Unsupported primitive type: %s".formatted(primitive)); + } +} diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java new file mode 100644 index 00000000..934695c9 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java @@ -0,0 +1,9 @@ +package com.github.gilesi.confgencoverage.models; + +import java.util.List; + +public class Class { + public String ClassName; + public List ClassMethods; + public List ClassDescriptors; +} diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/InstrumentationParameters.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/InstrumentationParameters.java new file mode 100644 index 00000000..ddac58e6 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/InstrumentationParameters.java @@ -0,0 +1,8 @@ +package com.github.gilesi.confgencoverage.models; + +import java.util.List; + +public class InstrumentationParameters { + public List InstrumentedAPIClasses; + public String traceOutputLocation; +} diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java new file mode 100644 index 00000000..1c7ddc75 --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java @@ -0,0 +1,8 @@ +package com.github.gilesi.confgencoverage.models; + +import java.util.List; + +public class Method { + public String MethodName; + public List MethodDescriptors; +} \ No newline at end of file diff --git a/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/spoon/SpoonLauncherUtilities.java b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/spoon/SpoonLauncherUtilities.java new file mode 100644 index 00000000..ab7ef5ab --- /dev/null +++ b/ConfGenCoverage/src/main/java/com/github/gilesi/confgencoverage/spoon/SpoonLauncherUtilities.java @@ -0,0 +1,222 @@ +package com.github.gilesi.confgencoverage.spoon; + +import spoon.Launcher; +import spoon.MavenLauncher; +import spoon.SpoonException; +import spoon.support.StandardEnvironment; +import spoon.support.compiler.SpoonPom; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Path; +import java.security.InvalidParameterException; +import java.util.*; +import java.util.regex.Pattern; + +import com.github.gilesi.confgencoverage.CodeType; + +public class SpoonLauncherUtilities { + public static Launcher getCommonLauncherInstance() { + Launcher launcher = new Launcher(); + + // Ignore missing types/classpath related errors + launcher.getEnvironment().setNoClasspath(true); + // Proceed even if we find the same type twice; affects the precision of the result + launcher.getEnvironment().setIgnoreDuplicateDeclarations(true); + // Ignore files with syntax/JLS violations and proceed + launcher.getEnvironment().setIgnoreSyntaxErrors(true); + // Ignore comments + launcher.getEnvironment().setCommentEnabled(false); + // Set Java version + // Note: even when using the MavenLauncher, it's sometimes not properly inferred, better be safe + launcher.getEnvironment().setComplianceLevel(17); + + return launcher; + } + + private static Collection getPomProjectPaths(String mavenProject, spoon.MavenLauncher.SOURCE_TYPE sourceType) throws SpoonException { + SpoonPom model; + ArrayList paths = new ArrayList<>(); + + File mavenProjectFile = new File(mavenProject); + if (!mavenProjectFile.exists()) { + throw new SpoonException("%s does not exist.".formatted(mavenProject)); + } + + Pattern profileFilter = Pattern.compile("^$"); + + try { + model = new SpoonPom(mavenProject, sourceType, new StandardEnvironment(), profileFilter); + } catch (Exception e) { + throw new SpoonException("Unable to read the pom", e); + } + + // app source + if (spoon.MavenLauncher.SOURCE_TYPE.APP_SOURCE == sourceType || spoon.MavenLauncher.SOURCE_TYPE.ALL_SOURCE == sourceType) { + List sourceDirectories = model.getSourceDirectories(); + for (File sourceDirectory : sourceDirectories) { + System.out.printf("Detected Project MAIN Source Directory at: %s%n", sourceDirectory); + paths.add(sourceDirectory.toPath()); + } + } + + // test source + if (spoon.MavenLauncher.SOURCE_TYPE.TEST_SOURCE == sourceType || spoon.MavenLauncher.SOURCE_TYPE.ALL_SOURCE == sourceType) { + List testSourceDirectories = model.getTestDirectories(); + for (File sourceDirectory : testSourceDirectories) { + System.out.printf("Detected Project TEST Source Directory at: %s%n", sourceDirectory); + paths.add(sourceDirectory.toPath()); + } + } + + return paths; + } + + private static int getPomProjectSourceComplianceLevel(String mavenProject) throws SpoonException { + SpoonPom model; + + File mavenProjectFile = new File(mavenProject); + if (!mavenProjectFile.exists()) { + throw new SpoonException("%s does not exist.".formatted(mavenProject)); + } + + Pattern profileFilter = Pattern.compile("^$"); + + try { + model = new SpoonPom(mavenProject, MavenLauncher.SOURCE_TYPE.ALL_SOURCE, new StandardEnvironment(), profileFilter); + } catch (Exception e) { + throw new SpoonException("Unable to read the pom", e); + } + + return model.getSourceVersion(); + } + + public static int getProjectSourceComplianceLevel(Path location) { + try { + return getPomProjectSourceComplianceLevel(location.toAbsolutePath().toString()); + } catch (Exception ignore) { + System.out.println("Unable to get project source compliance level. %s".formatted(ignore)); + } + + return 11; + } + + private static Path getPossibleSamplePath(Path location) { + Path examplesPath = location.resolve("examples"); + Path samplesPath = location.resolve("samples"); + Path srcPath = location.resolve("src"); + + if (Files.exists(examplesPath)) { + return examplesPath; + } + + if (Files.exists(samplesPath)) { + return samplesPath; + } + + if (Files.exists(srcPath)) { + return getPossibleSamplePath(srcPath); + } + + return null; + } + + private static Path getPossibleMainPath(Path location) { + Path mainPath = location.resolve("main"); + Path srcPath = location.resolve("src"); + + if (Files.exists(mainPath)) { + return mainPath; + } + + if (Files.exists(srcPath)) { + return getPossibleMainPath(srcPath); + } + + return null; + } + + private static Path getPossibleTestPath(Path location) { + Path testPath = location.resolve("test"); + Path srcPath = location.resolve("src"); + + if (Files.exists(testPath)) { + return testPath; + } + + if (Files.exists(srcPath)) { + return getPossibleTestPath(srcPath); + } + + return null; + } + + private static MavenLauncher.SOURCE_TYPE getSourceTypeValue(EnumSet codeTypes) throws InvalidParameterException { + if (codeTypes.contains(CodeType.MAIN) && codeTypes.contains(CodeType.TEST)) { + return MavenLauncher.SOURCE_TYPE.ALL_SOURCE; + } else if (codeTypes.contains(CodeType.MAIN)) { + return MavenLauncher.SOURCE_TYPE.APP_SOURCE; + } else if (codeTypes.contains(CodeType.TEST)) { + return MavenLauncher.SOURCE_TYPE.TEST_SOURCE; + } else { + throw new InvalidParameterException(); + } + } + + public static void applyProjectToLauncher(Launcher launcher, Path projectLocation, EnumSet codeTypes) { + launcher.getEnvironment().setComplianceLevel(getProjectSourceComplianceLevel(projectLocation)); + + Collection paths = getProjectPaths(projectLocation, codeTypes); + for (Path path : paths) { + launcher.addInputResource(path.toAbsolutePath().toString()); + } + } + + public static Collection getProjectPaths(Path projectLocation, EnumSet codeTypes) { + Collection paths = new HashSet<>(); + + System.out.printf("Trying to detect source directories for project: %s with types: %s%n", projectLocation, codeTypes); + + if (codeTypes.contains(CodeType.MAIN) || codeTypes.contains(CodeType.TEST)) { + try { + MavenLauncher.SOURCE_TYPE sourceType = getSourceTypeValue(codeTypes); + paths.addAll(getPomProjectPaths(projectLocation.toString(), sourceType)); + } catch (Exception ignored) { + System.out.println("Unable to get project code %s".formatted(ignored)); + System.out.println("WARNING: Falling back to manual detection of project source paths because no maven pom could be parsed for the passed project"); + if (codeTypes.contains(CodeType.MAIN)) { + Path mainPath = getPossibleMainPath(projectLocation); + if (mainPath != null) { + System.out.printf("Detected Project MAIN Source Directory at: %s%n", mainPath); + paths.add(mainPath); + } + } + + if (codeTypes.contains(CodeType.TEST)) { + Path testPath = getPossibleTestPath(projectLocation); + if (testPath != null) { + System.out.printf("Detected Project TEST Source Directory at: %s%n", testPath); + paths.add(testPath); + } + } + } + } + + if (codeTypes.contains(CodeType.SAMPLE)) { + Path samplePath = getPossibleSamplePath(projectLocation); + if (samplePath != null) { + System.out.printf("Detected Project SAMPLE Source Directory at: %s%n", samplePath); + paths.add(samplePath); + } + } + + if (paths.isEmpty()) { + System.out.println("WARNING: Adding the entire directory because no project got detected and CodeTypes = ALL!"); + paths.add(projectLocation); + } + + System.out.printf("Finished detecting source directories for project: %s%n", projectLocation); + + return paths; + } +} diff --git a/Coverage/.gitignore b/Coverage/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/Coverage/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/Coverage/build.gradle b/Coverage/build.gradle new file mode 100644 index 00000000..130749be --- /dev/null +++ b/Coverage/build.gradle @@ -0,0 +1,78 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +java { + sourceCompatibility = JavaVersion.VERSION_1_8 + targetCompatibility = JavaVersion.VERSION_1_8 +} + +group = 'com.github.gilesi.coverage' +version = '1.0-SNAPSHOT' + +repositories { + mavenCentral() +} + +dependencies { + implementation 'net.bytebuddy:byte-buddy:1.15.10' + implementation 'net.bytebuddy:byte-buddy-agent:1.15.8' + implementation 'com.thoughtworks.xstream:xstream:1.4.20' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.14.2' +} + +jar { + manifest { + attributes 'Premain-Class': 'com.github.gilesi.coverage.Agent', + 'Agent-Class': 'com.github.gilesi.coverage.Agent', + 'Launcher-Agent-Class': 'com.github.gilesi.coverage.Agent', + 'Can-Retransform-Classes': 'true', + 'Can-Redefine-Classes': 'true', + 'Main-Class': 'com.github.gilesi.coverage.Agent', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.coverage.Agent' +} + +description = 'Agent distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.coverage') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() + + // Filtering shadow jar contents by file pattern. + exclude('LICENSE.txt') + exclude('META-INF/LICENSE') + exclude('META-INF/LICENSE.txt') + exclude('META-INF/NOTICE') + exclude('META-INF/NOTICE.txt') + + // Relocating dependencies. + relocate('com.fasterxml', 'gilesi.com.fasterxml') + relocate('com.thoughtworks', 'gilesi.com.thoughtworks') + relocate('net', 'gilesi.net') + relocate('io', 'gilesi.io') + //relocate('org', 'gilesi.org') // causes issues with xtream if done +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.coverage' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} \ No newline at end of file diff --git a/Coverage/gradle/wrapper/gradle-wrapper.jar b/Coverage/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..033e24c4cdf41af1ab109bc7f253b2b887023340 GIT binary patch literal 63375 zcmb5VV{~QRw)Y#`wrv{~+qP{x72B%VwzFc}c2cp;N~)5ZbDrJayPv(!dGEd-##*zr z)#n-$y^sH|_dchh3@8{H5D*j;5D<{i*8l5IFJ|DjL!e)upfGNX(kojugZ3I`oH1PvW`wFW_ske0j@lB9bX zO;2)`y+|!@X(fZ1<2n!Qx*)_^Ai@Cv-dF&(vnudG?0CsddG_&Wtae(n|K59ew)6St z#dj7_(Cfwzh$H$5M!$UDd8=4>IQsD3xV=lXUq($;(h*$0^yd+b{qq63f0r_de#!o_ zXDngc>zy`uor)4A^2M#U*DC~i+dc<)Tb1Tv&~Ev@oM)5iJ4Sn#8iRw16XXuV50BS7 zdBL5Mefch(&^{luE{*5qtCZk$oFr3RH=H!c3wGR=HJ(yKc_re_X9pD` zJ;uxPzUfVpgU>DSq?J;I@a+10l0ONXPcDkiYcihREt5~T5Gb}sT0+6Q;AWHl`S5dV>lv%-p9l#xNNy7ZCr%cyqHY%TZ8Q4 zbp&#ov1*$#grNG#1vgfFOLJCaNG@K|2!W&HSh@3@Y%T?3YI75bJp!VP*$*!< z;(ffNS_;@RJ`=c7yX04!u3JP*<8jeqLHVJu#WV&v6wA!OYJS4h<_}^QI&97-;=ojW zQ-1t)7wnxG*5I%U4)9$wlv5Fr;cIizft@&N+32O%B{R1POm$oap@&f| zh+5J{>U6ftv|vAeKGc|zC=kO(+l7_cLpV}-D#oUltScw})N>~JOZLU_0{Ka2e1evz z{^a*ZrLr+JUj;)K&u2CoCAXLC2=fVScI(m_p~0FmF>>&3DHziouln?;sxW`NB}cSX z8?IsJB)Z=aYRz!X=yJn$kyOWK%rCYf-YarNqKzmWu$ZvkP12b4qH zhS9Q>j<}(*frr?z<%9hl*i^#@*O2q(Z^CN)c2c z>1B~D;@YpG?G!Yk+*yn4vM4sO-_!&m6+`k|3zd;8DJnxsBYtI;W3We+FN@|tQ5EW= z!VU>jtim0Mw#iaT8t_<+qKIEB-WwE04lBd%Letbml9N!?SLrEG$nmn7&W(W`VB@5S zaY=sEw2}i@F_1P4OtEw?xj4@D6>_e=m=797#hg}f*l^`AB|Y0# z9=)o|%TZFCY$SzgSjS|8AI-%J4x}J)!IMxY3_KYze`_I=c1nmrk@E8c9?MVRu)7+Ue79|)rBX7tVB7U|w4*h(;Gi3D9le49B38`wuv zp7{4X^p+K4*$@gU(Tq3K1a#3SmYhvI42)GzG4f|u zwQFT1n_=n|jpi=70-yE9LA+d*T8u z`=VmmXJ_f6WmZveZPct$Cgu^~gFiyL>Lnpj*6ee>*0pz=t$IJ}+rE zsf@>jlcG%Wx;Cp5x)YSVvB1$yyY1l&o zvwX=D7k)Dn;ciX?Z)Pn8$flC8#m`nB&(8?RSdBvr?>T9?E$U3uIX7T?$v4dWCa46 z+&`ot8ZTEgp7G+c52oHJ8nw5}a^dwb_l%MOh(ebVj9>_koQP^$2B~eUfSbw9RY$_< z&DDWf2LW;b0ZDOaZ&2^i^g+5uTd;GwO(-bbo|P^;CNL-%?9mRmxEw~5&z=X^Rvbo^WJW=n_%*7974RY}JhFv46> zd}`2|qkd;89l}R;i~9T)V-Q%K)O=yfVKNM4Gbacc7AOd>#^&W&)Xx!Uy5!BHnp9kh z`a(7MO6+Ren#>R^D0K)1sE{Bv>}s6Rb9MT14u!(NpZOe-?4V=>qZ>}uS)!y~;jEUK z&!U7Fj&{WdgU#L0%bM}SYXRtM5z!6M+kgaMKt%3FkjWYh=#QUpt$XX1!*XkpSq-pl zhMe{muh#knk{9_V3%qdDcWDv}v)m4t9 zQhv{;} zc{}#V^N3H>9mFM8`i`0p+fN@GqX+kl|M94$BK3J-X`Hyj8r!#x6Vt(PXjn?N)qedP z=o1T^#?1^a{;bZ&x`U{f?}TMo8ToN zkHj5v|}r}wDEi7I@)Gj+S1aE-GdnLN+$hw!=DzglMaj#{qjXi_dwpr|HL(gcCXwGLEmi|{4&4#OZ4ChceA zKVd4K!D>_N=_X;{poT~4Q+!Le+ZV>=H7v1*l%w`|`Dx8{)McN@NDlQyln&N3@bFpV z_1w~O4EH3fF@IzJ9kDk@7@QctFq8FbkbaH7K$iX=bV~o#gfh?2JD6lZf(XP>~DACF)fGFt)X%-h1yY~MJU{nA5 ze2zxWMs{YdX3q5XU*9hOH0!_S24DOBA5usB+Ws$6{|AMe*joJ?RxfV}*7AKN9V*~J zK+OMcE@bTD>TG1*yc?*qGqjBN8mgg@h1cJLDv)0!WRPIkC` zZrWXrceVw;fB%3`6kq=a!pq|hFIsQ%ZSlo~)D z|64!aCnw-?>}AG|*iOl44KVf8@|joXi&|)1rB;EQWgm+iHfVbgllP$f!$Wf42%NO5b(j9Bw6L z;0dpUUK$5GX4QbMlTmLM_jJt!ur`_0~$b#BB7FL*%XFf<b__1o)Ao3rlobbN8-(T!1d-bR8D3S0@d zLI!*GMb5s~Q<&sjd}lBb8Nr0>PqE6_!3!2d(KAWFxa{hm`@u|a(%#i(#f8{BP2wbs zt+N_slWF4IF_O|{w`c~)Xvh&R{Au~CFmW#0+}MBd2~X}t9lz6*E7uAD`@EBDe$>7W zzPUkJx<`f$0VA$=>R57^(K^h86>09?>_@M(R4q($!Ck6GG@pnu-x*exAx1jOv|>KH zjNfG5pwm`E-=ydcb+3BJwuU;V&OS=6yM^4Jq{%AVqnTTLwV`AorIDD}T&jWr8pB&j28fVtk_y*JRP^t@l*($UZ z6(B^-PBNZ+z!p?+e8@$&jCv^EWLb$WO=}Scr$6SM*&~B95El~;W_0(Bvoha|uQ1T< zO$%_oLAwf1bW*rKWmlD+@CP&$ObiDy=nh1b2ejz%LO9937N{LDe7gle4i!{}I$;&Y zkexJ9Ybr+lrCmKWg&}p=`2&Gf10orS?4$VrzWidT=*6{KzOGMo?KI0>GL0{iFWc;C z+LPq%VH5g}6V@-tg2m{C!-$fapJ9y}c$U}aUmS{9#0CM*8pC|sfer!)nG7Ji>mfRh z+~6CxNb>6eWKMHBz-w2{mLLwdA7dA-qfTu^A2yG1+9s5k zcF=le_UPYG&q!t5Zd_*E_P3Cf5T6821bO`daa`;DODm8Ih8k89=RN;-asHIigj`n=ux>*f!OC5#;X5i;Q z+V!GUy0|&Y_*8k_QRUA8$lHP;GJ3UUD08P|ALknng|YY13)}!!HW@0z$q+kCH%xet zlWf@BXQ=b=4}QO5eNnN~CzWBbHGUivG=`&eWK}beuV*;?zt=P#pM*eTuy3 zP}c#}AXJ0OIaqXji78l;YrP4sQe#^pOqwZUiiN6^0RCd#D271XCbEKpk`HI0IsN^s zES7YtU#7=8gTn#lkrc~6)R9u&SX6*Jk4GFX7){E)WE?pT8a-%6P+zS6o&A#ml{$WX zABFz#i7`DDlo{34)oo?bOa4Z_lNH>n;f0nbt$JfAl~;4QY@}NH!X|A$KgMmEsd^&Y zt;pi=>AID7ROQfr;MsMtClr5b0)xo|fwhc=qk33wQ|}$@?{}qXcmECh>#kUQ-If0$ zseb{Wf4VFGLNc*Rax#P8ko*=`MwaR-DQ8L8V8r=2N{Gaips2_^cS|oC$+yScRo*uF zUO|5=?Q?{p$inDpx*t#Xyo6=s?bbN}y>NNVxj9NZCdtwRI70jxvm3!5R7yiWjREEd zDUjrsZhS|P&|Ng5r+f^kA6BNN#|Se}_GF>P6sy^e8kBrgMv3#vk%m}9PCwUWJg-AD zFnZ=}lbi*mN-AOm zCs)r=*YQAA!`e#1N>aHF=bb*z*hXH#Wl$z^o}x##ZrUc=kh%OHWhp=7;?8%Xj||@V?1c ziWoaC$^&04;A|T)!Zd9sUzE&$ODyJaBpvqsw19Uiuq{i#VK1!htkdRWBnb z`{rat=nHArT%^R>u#CjjCkw-7%g53|&7z-;X+ewb?OLWiV|#nuc8mp*LuGSi3IP<<*Wyo9GKV7l0Noa4Jr0g3p_$ z*R9{qn=?IXC#WU>48-k5V2Oc_>P;4_)J@bo1|pf=%Rcbgk=5m)CJZ`caHBTm3%!Z9 z_?7LHr_BXbKKr=JD!%?KhwdYSdu8XxPoA{n8^%_lh5cjRHuCY9Zlpz8g+$f@bw@0V z+6DRMT9c|>1^3D|$Vzc(C?M~iZurGH2pXPT%F!JSaAMdO%!5o0uc&iqHx?ImcX6fI zCApkzc~OOnfzAd_+-DcMp&AOQxE_EsMqKM{%dRMI5`5CT&%mQO?-@F6tE*xL?aEGZ z8^wH@wRl`Izx4sDmU>}Ym{ybUm@F83qqZPD6nFm?t?(7>h*?`fw)L3t*l%*iw0Qu#?$5eq!Qc zpQvqgSxrd83NsdO@lL6#{%lsYXWen~d3p4fGBb7&5xqNYJ)yn84!e1PmPo7ChVd%4 zHUsV0Mh?VpzZD=A6%)Qrd~i7 z96*RPbid;BN{Wh?adeD_p8YU``kOrGkNox3D9~!K?w>#kFz!4lzOWR}puS(DmfjJD z`x0z|qB33*^0mZdM&6$|+T>fq>M%yoy(BEjuh9L0>{P&XJ3enGpoQRx`v6$txXt#c z0#N?b5%srj(4xmPvJxrlF3H%OMB!jvfy z;wx8RzU~lb?h_}@V=bh6p8PSb-dG|-T#A?`c&H2`_!u+uenIZe`6f~A7r)`9m8atC zt(b|6Eg#!Q*DfRU=Ix`#B_dK)nnJ_+>Q<1d7W)eynaVn`FNuN~%B;uO2}vXr5^zi2 z!ifIF5@Zlo0^h~8+ixFBGqtweFc`C~JkSq}&*a3C}L?b5Mh-bW=e)({F_g4O3 zb@SFTK3VD9QuFgFnK4Ve_pXc3{S$=+Z;;4+;*{H}Rc;845rP?DLK6G5Y-xdUKkA6E3Dz&5f{F^FjJQ(NSpZ8q-_!L3LL@H* zxbDF{gd^U3uD;)a)sJwAVi}7@%pRM&?5IaUH%+m{E)DlA_$IA1=&jr{KrhD5q&lTC zAa3c)A(K!{#nOvenH6XrR-y>*4M#DpTTOGQEO5Jr6kni9pDW`rvY*fs|ItV;CVITh z=`rxcH2nEJpkQ^(;1c^hfb8vGN;{{oR=qNyKtR1;J>CByul*+=`NydWnSWJR#I2lN zTvgnR|MBx*XFsfdA&;tr^dYaqRZp*2NwkAZE6kV@1f{76e56eUmGrZ>MDId)oqSWw z7d&r3qfazg+W2?bT}F)4jD6sWaw`_fXZGY&wnGm$FRPFL$HzVTH^MYBHWGCOk-89y zA+n+Q6EVSSCpgC~%uHfvyg@ufE^#u?JH?<73A}jj5iILz4Qqk5$+^U(SX(-qv5agK znUkfpke(KDn~dU0>gdKqjTkVk`0`9^0n_wzXO7R!0Thd@S;U`y)VVP&mOd-2 z(hT(|$=>4FY;CBY9#_lB$;|Wd$aOMT5O_3}DYXEHn&Jrc3`2JiB`b6X@EUOD zVl0S{ijm65@n^19T3l%>*;F(?3r3s?zY{thc4%AD30CeL_4{8x6&cN}zN3fE+x<9; zt2j1RRVy5j22-8U8a6$pyT+<`f+x2l$fd_{qEp_bfxfzu>ORJsXaJn4>U6oNJ#|~p z`*ZC&NPXl&=vq2{Ne79AkQncuxvbOG+28*2wU$R=GOmns3W@HE%^r)Fu%Utj=r9t` zd;SVOnA(=MXgnOzI2@3SGKHz8HN~Vpx&!Ea+Df~`*n@8O=0!b4m?7cE^K*~@fqv9q zF*uk#1@6Re_<^9eElgJD!nTA@K9C732tV~;B`hzZ321Ph=^BH?zXddiu{Du5*IPg} zqDM=QxjT!Rp|#Bkp$(mL)aar)f(dOAXUiw81pX0DC|Y4;>Vz>>DMshoips^8Frdv} zlTD=cKa48M>dR<>(YlLPOW%rokJZNF2gp8fwc8b2sN+i6&-pHr?$rj|uFgktK@jg~ zIFS(%=r|QJ=$kvm_~@n=ai1lA{7Z}i+zj&yzY+!t$iGUy|9jH#&oTNJ;JW-3n>DF+ z3aCOzqn|$X-Olu_p7brzn`uk1F*N4@=b=m;S_C?#hy{&NE#3HkATrg?enaVGT^$qIjvgc61y!T$9<1B@?_ibtDZ{G zeXInVr5?OD_nS_O|CK3|RzzMmu+8!#Zb8Ik;rkIAR%6?$pN@d<0dKD2c@k2quB%s( zQL^<_EM6ow8F6^wJN1QcPOm|ehA+dP(!>IX=Euz5qqIq}Y3;ibQtJnkDmZ8c8=Cf3 zu`mJ!Q6wI7EblC5RvP*@)j?}W=WxwCvF3*5Up_`3*a~z$`wHwCy)2risye=1mSp%p zu+tD6NAK3o@)4VBsM!@);qgsjgB$kkCZhaimHg&+k69~drbvRTacWKH;YCK(!rC?8 zP#cK5JPHSw;V;{Yji=55X~S+)%(8fuz}O>*F3)hR;STU`z6T1aM#Wd+FP(M5*@T1P z^06O;I20Sk!bxW<-O;E081KRdHZrtsGJflFRRFS zdi5w9OVDGSL3 zNrC7GVsGN=b;YH9jp8Z2$^!K@h=r-xV(aEH@#JicPy;A0k1>g1g^XeR`YV2HfmqXY zYbRwaxHvf}OlCAwHoVI&QBLr5R|THf?nAevV-=~V8;gCsX>jndvNOcFA+DI+zbh~# zZ7`qNk&w+_+Yp!}j;OYxIfx_{f0-ONc?mHCiCUak=>j>~>YR4#w# zuKz~UhT!L~GfW^CPqG8Lg)&Rc6y^{%3H7iLa%^l}cw_8UuG;8nn9)kbPGXS}p3!L_ zd#9~5CrH8xtUd?{d2y^PJg+z(xIfRU;`}^=OlehGN2=?}9yH$4Rag}*+AWotyxfCJ zHx=r7ZH>j2kV?%7WTtp+-HMa0)_*DBBmC{sd$)np&GEJ__kEd`xB5a2A z*J+yx>4o#ZxwA{;NjhU*1KT~=ZK~GAA;KZHDyBNTaWQ1+;tOFFthnD)DrCn`DjBZ% zk$N5B4^$`n^jNSOr=t(zi8TN4fpaccsb`zOPD~iY=UEK$0Y70bG{idLx@IL)7^(pL z{??Bnu=lDeguDrd%qW1)H)H`9otsOL-f4bSu};o9OXybo6J!Lek`a4ff>*O)BDT_g z<6@SrI|C9klY(>_PfA^qai7A_)VNE4c^ZjFcE$Isp>`e5fLc)rg@8Q_d^Uk24$2bn z9#}6kZ2ZxS9sI(RqT7?El2@B+($>eBQrNi_k#CDJ8D9}8$mmm z4oSKO^F$i+NG)-HE$O6s1--6EzJa?C{x=QgK&c=)b(Q9OVoAXYEEH20G|q$}Hue%~ zO3B^bF=t7t48sN zWh_zA`w~|){-!^g?6Mqf6ieV zFx~aPUOJGR=4{KsW7I?<=J2|lY`NTU=lt=%JE9H1vBpkcn=uq(q~=?iBt_-r(PLBM zP-0dxljJO>4Wq-;stY)CLB4q`-r*T$!K2o}?E-w_i>3_aEbA^MB7P5piwt1dI-6o!qWCy0 ztYy!x9arGTS?kabkkyv*yxvsPQ7Vx)twkS6z2T@kZ|kb8yjm+^$|sEBmvACeqbz)RmxkkDQX-A*K!YFziuhwb|ym>C$}U|J)4y z$(z#)GH%uV6{ec%Zy~AhK|+GtG8u@c884Nq%w`O^wv2#A(&xH@c5M`Vjk*SR_tJnq z0trB#aY)!EKW_}{#L3lph5ow=@|D5LzJYUFD6 z7XnUeo_V0DVSIKMFD_T0AqAO|#VFDc7c?c-Q%#u00F%!_TW1@JVnsfvm@_9HKWflBOUD~)RL``-!P;(bCON_4eVdduMO>?IrQ__*zE@7(OX zUtfH@AX*53&xJW*Pu9zcqxGiM>xol0I~QL5B%Toog3Jlenc^WbVgeBvV8C8AX^Vj& z^I}H})B=VboO%q1;aU5ACMh{yK4J;xlMc`jCnZR^!~LDs_MP&8;dd@4LDWw~*>#OT zeZHwdQWS!tt5MJQI~cw|Ka^b4c|qyd_ly(+Ql2m&AAw^ zQeSXDOOH!!mAgzAp0z)DD>6Xo``b6QwzUV@w%h}Yo>)a|xRi$jGuHQhJVA%>)PUvK zBQ!l0hq<3VZ*RnrDODP)>&iS^wf64C;MGqDvx>|p;35%6(u+IHoNbK z;Gb;TneFo*`zUKS6kwF*&b!U8e5m4YAo03a_e^!5BP42+r)LFhEy?_7U1IR<; z^0v|DhCYMSj<-;MtY%R@Fg;9Kky^pz_t2nJfKWfh5Eu@_l{^ph%1z{jkg5jQrkvD< z#vdK!nku*RrH~TdN~`wDs;d>XY1PH?O<4^U4lmA|wUW{Crrv#r%N>7k#{Gc44Fr|t z@UZP}Y-TrAmnEZ39A*@6;ccsR>)$A)S>$-Cj!=x$rz7IvjHIPM(TB+JFf{ehuIvY$ zsDAwREg*%|=>Hw$`us~RP&3{QJg%}RjJKS^mC_!U;E5u>`X`jW$}P`Mf}?7G7FX#{ zE(9u1SO;3q@ZhDL9O({-RD+SqqPX)`0l5IQu4q)49TUTkxR(czeT}4`WV~pV*KY&i zAl3~X%D2cPVD^B43*~&f%+Op)wl<&|D{;=SZwImydWL6@_RJjxP2g)s=dH)u9Npki zs~z9A+3fj0l?yu4N0^4aC5x)Osnm0qrhz@?nwG_`h(71P znbIewljU%T*cC=~NJy|)#hT+lx#^5MuDDnkaMb*Efw9eThXo|*WOQzJ*#3dmRWm@! zfuSc@#kY{Um^gBc^_Xdxnl!n&y&}R4yAbK&RMc+P^Ti;YIUh|C+K1|=Z^{nZ}}rxH*v{xR!i%qO~o zTr`WDE@k$M9o0r4YUFFeQO7xCu_Zgy)==;fCJ94M_rLAv&~NhfvcLWCoaGg2ao~3e zBG?Ms9B+efMkp}7BhmISGWmJsKI@a8b}4lLI48oWKY|8?zuuNc$lt5Npr+p7a#sWu zh!@2nnLBVJK!$S~>r2-pN||^w|fY`CT{TFnJy`B|e5;=+_v4l8O-fkN&UQbA4NKTyntd zqK{xEKh}U{NHoQUf!M=2(&w+eef77VtYr;xs%^cPfKLObyOV_9q<(%76-J%vR>w9!us-0c-~Y?_EVS%v!* z15s2s3eTs$Osz$JayyH|5nPAIPEX=U;r&p;K14G<1)bvn@?bM5kC{am|C5%hyxv}a z(DeSKI5ZfZ1*%dl8frIX2?);R^^~LuDOpNpk-2R8U1w92HmG1m&|j&J{EK=|p$;f9 z7Rs5|jr4r8k5El&qcuM+YRlKny%t+1CgqEWO>3;BSRZi(LA3U%Jm{@{y+A+w(gzA< z7dBq6a1sEWa4cD0W7=Ld9z0H7RI^Z7vl(bfA;72j?SWCo`#5mVC$l1Q2--%V)-uN* z9ha*s-AdfbDZ8R8*fpwjzx=WvOtmSzGFjC#X)hD%Caeo^OWjS(3h|d9_*U)l%{Ab8 zfv$yoP{OuUl@$(-sEVNt{*=qi5P=lpxWVuz2?I7Dc%BRc+NGNw+323^ z5BXGfS71oP^%apUo(Y#xkxE)y?>BFzEBZ}UBbr~R4$%b7h3iZu3S(|A;&HqBR{nK& z$;GApNnz=kNO^FL&nYcfpB7Qg;hGJPsCW44CbkG1@l9pn0`~oKy5S777uH)l{irK!ru|X+;4&0D;VE*Ii|<3P zUx#xUqvZT5kVQxsF#~MwKnv7;1pR^0;PW@$@T7I?s`_rD1EGUdSA5Q(C<>5SzE!vw z;{L&kKFM-MO>hy#-8z`sdVx})^(Dc-dw;k-h*9O2_YZw}|9^y-|8RQ`BWJUJL(Cer zP5Z@fNc>pTXABbTRY-B5*MphpZv6#i802giwV&SkFCR zGMETyUm(KJbh+&$8X*RB#+{surjr;8^REEt`2&Dubw3$mx>|~B5IKZJ`s_6fw zKAZx9&PwBqW1Oz0r0A4GtnZd7XTKViX2%kPfv+^X3|_}RrQ2e3l=KG_VyY`H?I5&CS+lAX5HbA%TD9u6&s#v!G> zzW9n4J%d5ye7x0y`*{KZvqyXUfMEE^ZIffzI=Hh|3J}^yx7eL=s+TPH(Q2GT-sJ~3 zI463C{(ag7-hS1ETtU;_&+49ABt5!A7CwLwe z=SoA8mYZIQeU;9txI=zcQVbuO%q@E)JI+6Q!3lMc=Gbj(ASg-{V27u>z2e8n;Nc*pf}AqKz1D>p9G#QA+7mqqrEjGfw+85Uyh!=tTFTv3|O z+)-kFe_8FF_EkTw!YzwK^Hi^_dV5x-Ob*UWmD-})qKj9@aE8g240nUh=g|j28^?v7 zHRTBo{0KGaWBbyX2+lx$wgXW{3aUab6Bhm1G1{jTC7ota*JM6t+qy)c5<@ zpc&(jVdTJf(q3xB=JotgF$X>cxh7k*(T`-V~AR+`%e?YOeALQ2Qud( zz35YizXt(aW3qndR}fTw1p()Ol4t!D1pitGNL95{SX4ywzh0SF;=!wf=?Q?_h6!f* zh7<+GFi)q|XBsvXZ^qVCY$LUa{5?!CgwY?EG;*)0ceFe&=A;!~o`ae}Z+6me#^sv- z1F6=WNd6>M(~ z+092z>?Clrcp)lYNQl9jN-JF6n&Y0mp7|I0dpPx+4*RRK+VQI~>en0Dc;Zfl+x z_e_b7s`t1_A`RP3$H}y7F9_na%D7EM+**G_Z0l_nwE+&d_kc35n$Fxkd4r=ltRZhh zr9zER8>j(EdV&Jgh(+i}ltESBK62m0nGH6tCBr90!4)-`HeBmz54p~QP#dsu%nb~W z7sS|(Iydi>C@6ZM(Us!jyIiszMkd)^u<1D+R@~O>HqZIW&kearPWmT>63%_t2B{_G zX{&a(gOYJx!Hq=!T$RZ&<8LDnxsmx9+TBL0gTk$|vz9O5GkK_Yx+55^R=2g!K}NJ3 zW?C;XQCHZl7H`K5^BF!Q5X2^Mj93&0l_O3Ea3!Ave|ixx+~bS@Iv18v2ctpSt4zO{ zp#7pj!AtDmti$T`e9{s^jf(ku&E|83JIJO5Qo9weT6g?@vX!{7)cNwymo1+u(YQ94 zopuz-L@|5=h8A!(g-MXgLJC0MA|CgQF8qlonnu#j z;uCeq9ny9QSD|p)9sp3ebgY3rk#y0DA(SHdh$DUm^?GI<>%e1?&}w(b zdip1;P2Z=1wM+$q=TgLP$}svd!vk+BZ@h<^4R=GS2+sri7Z*2f`9 z5_?i)xj?m#pSVchk-SR!2&uNhzEi+#5t1Z$o0PoLGz*pT64%+|Wa+rd5Z}60(j?X= z{NLjtgRb|W?CUADqOS@(*MA-l|E342NxRaxLTDqsOyfWWe%N(jjBh}G zm7WPel6jXijaTiNita+z(5GCO0NM=Melxud57PP^d_U## zbA;9iVi<@wr0DGB8=T9Ab#2K_#zi=$igyK48@;V|W`fg~7;+!q8)aCOo{HA@vpSy-4`^!ze6-~8|QE||hC{ICKllG9fbg_Y7v z$jn{00!ob3!@~-Z%!rSZ0JO#@>|3k10mLK0JRKP-Cc8UYFu>z93=Ab-r^oL2 zl`-&VBh#=-?{l1TatC;VweM^=M7-DUE>m+xO7Xi6vTEsReyLs8KJ+2GZ&rxw$d4IT zPXy6pu^4#e;;ZTsgmG+ZPx>piodegkx2n0}SM77+Y*j^~ICvp#2wj^BuqRY*&cjmL zcKp78aZt>e{3YBb4!J_2|K~A`lN=u&5j!byw`1itV(+Q_?RvV7&Z5XS1HF)L2v6ji z&kOEPmv+k_lSXb{$)of~(BkO^py&7oOzpjdG>vI1kcm_oPFHy38%D4&A4h_CSo#lX z2#oqMCTEP7UvUR3mwkPxbl8AMW(e{ARi@HCYLPSHE^L<1I}OgZD{I#YH#GKnpRmW3 z2jkz~Sa(D)f?V?$gNi?6)Y;Sm{&?~2p=0&BUl_(@hYeX8YjaRO=IqO7neK0RsSNdYjD zaw$g2sG(>JR=8Iz1SK4`*kqd_3-?;_BIcaaMd^}<@MYbYisWZm2C2|Np_l|8r9yM|JkUngSo@?wci(7&O9a z%|V(4C1c9pps0xxzPbXH=}QTxc2rr7fXk$9`a6TbWKPCz&p=VsB8^W96W=BsB|7bc zf(QR8&Ktj*iz)wK&mW`#V%4XTM&jWNnDF56O+2bo<3|NyUhQ%#OZE8$Uv2a@J>D%t zMVMiHh?es!Ex19q&6eC&L=XDU_BA&uR^^w>fpz2_`U87q_?N2y;!Z!bjoeKrzfC)} z?m^PM=(z{%n9K`p|7Bz$LuC7!>tFOuN74MFELm}OD9?%jpT>38J;=1Y-VWtZAscaI z_8jUZ#GwWz{JqvGEUmL?G#l5E=*m>`cY?m*XOc*yOCNtpuIGD+Z|kn4Xww=BLrNYS zGO=wQh}Gtr|7DGXLF%|`G>J~l{k^*{;S-Zhq|&HO7rC_r;o`gTB7)uMZ|WWIn@e0( zX$MccUMv3ABg^$%_lNrgU{EVi8O^UyGHPNRt%R!1#MQJn41aD|_93NsBQhP80yP<9 zG4(&0u7AtJJXLPcqzjv`S~5;Q|5TVGccN=Uzm}K{v)?f7W!230C<``9(64}D2raRU zAW5bp%}VEo{4Rko`bD%Ehf=0voW?-4Mk#d3_pXTF!-TyIt6U+({6OXWVAa;s-`Ta5 zTqx&8msH3+DLrVmQOTBOAj=uoxKYT3DS1^zBXM?1W+7gI!aQNPYfUl{3;PzS9*F7g zWJN8x?KjBDx^V&6iCY8o_gslO16=kh(|Gp)kz8qlQ`dzxQv;)V&t+B}wwdi~uBs4? zu~G|}y!`3;8#vIMUdyC7YEx6bb^1o}G!Jky4cN?BV9ejBfN<&!4M)L&lRKiuMS#3} z_B}Nkv+zzxhy{dYCW$oGC&J(Ty&7%=5B$sD0bkuPmj7g>|962`(Q{ZZMDv%YMuT^KweiRDvYTEop3IgFv#)(w>1 zSzH>J`q!LK)c(AK>&Ib)A{g`Fdykxqd`Yq@yB}E{gnQV$K!}RsgMGWqC3DKE(=!{}ekB3+(1?g}xF>^icEJbc z5bdxAPkW90atZT+&*7qoLqL#p=>t-(-lsnl2XMpZcYeW|o|a322&)yO_8p(&Sw{|b zn(tY$xn5yS$DD)UYS%sP?c|z>1dp!QUD)l;aW#`%qMtQJjE!s2z`+bTSZmLK7SvCR z=@I4|U^sCwZLQSfd*ACw9B@`1c1|&i^W_OD(570SDLK`MD0wTiR8|$7+%{cF&){$G zU~|$^Ed?TIxyw{1$e|D$050n8AjJvvOWhLtLHbSB|HIfhMpqVf>AF&}ZQHhOJ14Bz zww+XL+qP}nww+W`F>b!by|=&a(cM4JIDhsTXY8@|ntQG}-}jm0&Bcj|LV(#sc=BNS zRjh;k9l>EdAFdd)=H!U`~$WP*}~^3HZ_?H>gKw>NBa;tA8M1{>St|)yDF_=~{KEPAGkg3VB`QCHol!AQ0|?e^W?81f{@()Wy!vQ$bY; z0ctx)l7VK83d6;dp!s{Nu=SwXZ8lHQHC*J2g@P0a={B8qHdv(+O3wV=4-t4HK1+smO#=S; z3cSI#Nh+N@AqM#6wPqjDmQM|x95JG|l1#sAU|>I6NdF*G@bD?1t|ytHlkKD+z9}#j zbU+x_cR-j9yX4s{_y>@zk*ElG1yS({BInGJcIT>l4N-DUs6fufF#GlF2lVUNOAhJT zGZThq54GhwCG(h4?yWR&Ax8hU<*U)?g+HY5-@{#ls5CVV(Wc>Bavs|l<}U|hZn z_%m+5i_gaakS*Pk7!v&w3&?R5Xb|AkCdytTY;r+Z7f#Id=q+W8cn)*9tEet=OG+Y} z58U&!%t9gYMx2N=8F?gZhIjtkH!`E*XrVJ?$2rRxLhV1z82QX~PZi8^N5z6~f-MUE zLKxnNoPc-SGl7{|Oh?ZM$jq67sSa)Wr&3)0YxlJt(vKf!-^L)a|HaPv*IYXb;QmWx zsqM>qY;tpK3RH-omtta+Xf2Qeu^$VKRq7`e$N-UCe1_2|1F{L3&}M0XbJ@^xRe&>P zRdKTgD6601x#fkDWkoYzRkxbn#*>${dX+UQ;FbGnTE-+kBJ9KPn)501#_L4O_k`P3 zm+$jI{|EC?8BXJY{P~^f-{**E53k%kVO$%p+=H5DiIdwMmUo>2euq0UzU90FWL!>; z{5@sd0ecqo5j!6AH@g6Mf3keTP$PFztq}@)^ZjK;H6Go$#SV2|2bAFI0%?aXgVH$t zb4Kl`$Xh8qLrMbZUS<2*7^F0^?lrOE=$DHW+O zvLdczsu0^TlA6RhDy3=@s!k^1D~Awulk!Iyo#}W$xq8{yTAK!CLl={H0@YGhg-g~+ z(u>pss4k#%8{J%~%8=H5!T`rqK6w^es-cNVE}=*lP^`i&K4R=peg1tdmT~UAbDKc& zg%Y*1E{hBf<)xO>HDWV7BaMWX6FW4ou1T2m^6{Jb!Su1UaCCYY8RR8hAV$7ho|FyEyP~ zEgK`@%a$-C2`p zV*~G>GOAs*3KN;~IY_UR$ISJxB(N~K>=2C2V6>xTmuX4klRXdrJd&UPAw7&|KEwF8Zcy2j-*({gSNR1^p02Oj88GN9a_Hq;Skdp}kO0;FLbje%2ZvPiltDZgv^ z#pb4&m^!79;O8F+Wr9X71laPY!CdNXG?J6C9KvdAE2xWW1>U~3;0v≫L+crb^Bz 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + if ! command -v java >/dev/null 2>&1 + then + die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/Coverage/gradlew.bat b/Coverage/gradlew.bat new file mode 100644 index 00000000..4b4ef2d7 --- /dev/null +++ b/Coverage/gradlew.bat @@ -0,0 +1,91 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/Coverage/settings.gradle b/Coverage/settings.gradle new file mode 100644 index 00000000..43813bd7 --- /dev/null +++ b/Coverage/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'gilesi' + diff --git a/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java new file mode 100644 index 00000000..10b23867 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Class.java @@ -0,0 +1,7 @@ +package com.github.gilesi.confgencoverage.models; + +public class Class { + public String ClassName; + public Method[] ClassMethods; + public String[] ClassDescriptors; +} diff --git a/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/CoverageParameters.java b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/CoverageParameters.java new file mode 100644 index 00000000..5a43b75b --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/CoverageParameters.java @@ -0,0 +1,6 @@ +package com.github.gilesi.confgencoverage.models; + +public class CoverageParameters { + public Class[] InstrumentedAPIClasses; + public String traceOutputLocation; +} diff --git a/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java new file mode 100644 index 00000000..1e88a5f9 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/confgencoverage/models/Method.java @@ -0,0 +1,6 @@ +package com.github.gilesi.confgencoverage.models; + +public class Method { + public String MethodName; + public String[] MethodDescriptors; +} \ No newline at end of file diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/Agent.java b/Coverage/src/main/java/com/github/gilesi/coverage/Agent.java new file mode 100644 index 00000000..1603c373 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/Agent.java @@ -0,0 +1,149 @@ +package com.github.gilesi.coverage; + +import com.github.gilesi.confgencoverage.models.Class; +import com.github.gilesi.confgencoverage.models.CoverageParameters; +import com.github.gilesi.coverage.visitors.MethodInstrumentor; +import net.bytebuddy.agent.ByteBuddyAgent; + +import java.io.File; +import java.io.IOException; +import java.lang.instrument.Instrumentation; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; + +/* + Our main agent class + */ +public class Agent { + public static Path generatedLogsFolderPath; + public static Path generatedMarkersFolderPath; + public static Path generatedReachedListFolderPath; + + /* + Our primary method to install the agent required to trace methods during execution + We take in as parameter an XML file with the list of methods to instrument and their class + */ + private static void installAgent(String arg, Instrumentation inst) { + if (!RunMilestoneService.shouldRun()) { + return; + } + + // Get the parameters + File configurationFile = new File(arg); + if (!configurationFile.exists()) { + System.err.printf("ERROR: the passed in configuration file (%s) does not exist or could not be found!%n", arg); + return; + } + + CoverageParameters coverageParameters; + + try { + coverageParameters = ConfigurationReader.parseCoverageparameters(configurationFile); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not parse coverage configuration file (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + + String generatedFolderLocation = coverageParameters.traceOutputLocation; + Path generatedFolderPath = Paths.get(generatedFolderLocation); + generatedLogsFolderPath = generatedFolderPath.resolve("logs"); + generatedMarkersFolderPath = generatedFolderPath.resolve("markers"); + generatedReachedListFolderPath = generatedFolderPath.resolve("reached"); + + if (!Files.isDirectory(generatedFolderPath)) { + try { + Files.createDirectory(generatedFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + if (!Files.isDirectory(generatedLogsFolderPath)) { + try { + Files.createDirectory(generatedLogsFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create logs output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + if (!Files.isDirectory(generatedMarkersFolderPath)) { + try { + Files.createDirectory(generatedMarkersFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create markers output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + if (!Files.isDirectory(generatedReachedListFolderPath)) { + try { + Files.createDirectory(generatedReachedListFolderPath); + } catch (IOException ioException) { + System.err.printf("ERROR: Could not create reached list output directory (%s)!%n", arg); + System.err.println(ioException.getMessage()); + ioException.printStackTrace(); + return; + } + } + + RunMilestoneService.writeMarker(); + + // Add a shutdown hook to save all logs at exit + Runtime.getRuntime().addShutdownHook(new Thread(Logger::SaveLogResults)); + Runtime.getRuntime().addShutdownHook(new Thread(ReachedCollector::SaveReacedResults)); + + setupCoverage(inst, coverageParameters.InstrumentedAPIClasses); + } + + private static void setupCoverage(Instrumentation inst, Class[] InstrumentedAPIClasses) { + // First, install the ByteBuddy Agent required to redefine classes during execution + // Sometimes this can fail, so try to catch it + try { + ByteBuddyAgent.install(); + } catch (Throwable e) { + System.err.println("ERROR: Could not install byte buddy agent!"); + System.err.println(e.getMessage()); + e.printStackTrace(); + return; + } + + // Instrument every class + for (Class coverageParameter : InstrumentedAPIClasses) { + MethodInstrumentor.instrumentClassForTracingAgent(inst, coverageParameter); + } + } + + /* + premain is invoked when an agent is started before the application. + Agents invoked using premain are specified with the -javaagent switch. + (https://stackoverflow.com/a/19789168) + */ + public static void premain(String arg, Instrumentation inst) { + installAgent(arg, inst); + } + + /* + agentmain is invoked when an agent is started after the application is already running. + Agents started with agentmain can be attached programmatically using the Sun tools API (for Sun/Oracle JVMs only + -- the method for introducing dynamic agents is implementation-dependent). + (https://stackoverflow.com/a/19789168) + */ + public static void agentmain(String arg, Instrumentation inst) { + installAgent(arg, inst); + } + + public static void main(String[] args) { + System.err.println("This program cannot be executed standalone."); + } +} diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/ConfigurationReader.java b/Coverage/src/main/java/com/github/gilesi/coverage/ConfigurationReader.java new file mode 100644 index 00000000..29c280a6 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/ConfigurationReader.java @@ -0,0 +1,21 @@ +package com.github.gilesi.coverage; + +import com.fasterxml.jackson.databind.ObjectMapper; +import com.fasterxml.jackson.databind.SerializationFeature; +import com.github.gilesi.confgencoverage.models.CoverageParameters; + +import java.io.File; +import java.io.IOException; + +public class ConfigurationReader { + public static final ObjectMapper objectMapper = new ObjectMapper() + .enable(SerializationFeature.INDENT_OUTPUT) + //.enable(SerializationFeature.WRITE_SELF_REFERENCES_AS_NULL) + .disable(SerializationFeature.FAIL_ON_EMPTY_BEANS) + .disable(SerializationFeature.FAIL_ON_SELF_REFERENCES) + .disable(SerializationFeature.FAIL_ON_UNWRAPPED_TYPE_IDENTIFIERS); + + public static CoverageParameters parseCoverageparameters(File file) throws IOException { + return objectMapper.readValue(file, CoverageParameters.class); + } +} diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/Logger.java b/Coverage/src/main/java/com/github/gilesi/coverage/Logger.java new file mode 100644 index 00000000..7fe41f0e --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/Logger.java @@ -0,0 +1,58 @@ +package com.github.gilesi.coverage; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Map; + +public class Logger { + private static final Map> LOGGER = new HashMap<>(); + private static int LOGGERINSTANCE = 0; + + public static void SaveLogResults() { + int mainPadding = 1; + String logFileName = String.format("%s%sgilesi.coverage_%d.log", Agent.generatedLogsFolderPath, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(logFileName))) { + logFileName = String.format("%s%sgilesi.coverage_%d.log", Agent.generatedLogsFolderPath, File.separatorChar, ++mainPadding); + } + + ArrayList logLines = new ArrayList<>(); + for (int loggerInstance = 0; loggerInstance < LOGGERINSTANCE; loggerInstance++) { + ArrayList logs = LOGGER.get(loggerInstance); + if (logs != null) { + for (String log : logs) { + logLines.add(String.format("%d: %s", loggerInstance, log)); + } + } + } + + if (logLines.isEmpty()) { + return; + } + + try { + Files.write(new File(logFileName).toPath(), logLines); + } catch (Throwable e) { + System.err.println("ERROR while saving logs"); + e.printStackTrace(); + } + } + + public static int GetInstance() { + return LOGGERINSTANCE++; + } + + public static void Log(int loggerInstance, String log) { + if (LOGGER.containsKey(loggerInstance)) { + ArrayList logs = LOGGER.get(loggerInstance); + logs.add(log); + } else { + ArrayList logs = new ArrayList<>(); + logs.add(log); + LOGGER.put(loggerInstance, logs); + } + } +} diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/ReachedCollector.java b/Coverage/src/main/java/com/github/gilesi/coverage/ReachedCollector.java new file mode 100644 index 00000000..94cd1819 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/ReachedCollector.java @@ -0,0 +1,39 @@ +package com.github.gilesi.coverage; + +import java.io.File; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.ArrayList; + +public class ReachedCollector { + private static final ArrayList LOGGER = new ArrayList<>(); + + public static void SaveReacedResults() { + int mainPadding = 1; + String logFileName = String.format("%s%sgilesi.coverage_list_%d.log", Agent.generatedReachedListFolderPath, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(logFileName))) { + logFileName = String.format("%s%sgilesi.coverage_list_%d.log", Agent.generatedReachedListFolderPath, File.separatorChar, ++mainPadding); + } + + ArrayList logLines = new ArrayList<>(); + for (String log : LOGGER) { + logLines.add(log); + } + + if (logLines.isEmpty()) { + return; + } + + try { + Files.write(new File(logFileName).toPath(), logLines); + } catch (Throwable e) { + System.err.println("ERROR while saving reached results"); + e.printStackTrace(); + } + } + + public static void Log(String log) { + LOGGER.add(log); + } +} diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/RunMilestoneService.java b/Coverage/src/main/java/com/github/gilesi/coverage/RunMilestoneService.java new file mode 100644 index 00000000..bafac676 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/RunMilestoneService.java @@ -0,0 +1,46 @@ +package com.github.gilesi.coverage; + +import java.io.File; +import java.lang.management.ManagementFactory; +import java.lang.management.RuntimeMXBean; +import java.nio.file.Files; +import java.nio.file.Paths; +import java.util.List; + +public class RunMilestoneService { + public static void writeMarker() { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + + int mainPadding = 1; + String tracesFileName = String.format("%s%sgilesi.coverage_loaded_%d.marker", Agent.generatedMarkersFolderPath, File.separatorChar, mainPadding); + + while (Files.exists(Paths.get(tracesFileName))) { + tracesFileName = String.format("%s%sgilesi.coverage_loaded_%d.marker", Agent.generatedMarkersFolderPath, File.separatorChar, ++mainPadding); + } + + try { + Files.write(new File(tracesFileName).toPath(), arguments); + } catch (Throwable e) { + System.err.println("ERROR while saving marker"); + e.printStackTrace(); + } + } + + public static boolean shouldRun() { + RuntimeMXBean runtimeMxBean = ManagementFactory.getRuntimeMXBean(); + List arguments = runtimeMxBean.getInputArguments(); + + for (String argument : arguments) { + if (argument.startsWith("-Dmaven.home=")) { + return false; + } else if (argument.startsWith("-Dorg.gradle.appname=")) { + return false; + } else if (argument.startsWith("-Dnet.bytebuddy.agent.attacher.dump=")) { + return false; + } + } + + return true; + } +} diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/visitors/CommonAdvisor.java b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/CommonAdvisor.java new file mode 100644 index 00000000..f09254ba --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/CommonAdvisor.java @@ -0,0 +1,150 @@ +package com.github.gilesi.coverage.visitors; + +import com.github.gilesi.coverage.Logger; +import com.github.gilesi.coverage.ReachedCollector; + +import java.util.ArrayList; +import java.util.Arrays; + +public class CommonAdvisor { + private static final String JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN = "org.junit.platform.commons.util.ReflectionUtils.invokeMethod"; + private static final String JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL = "org.junit.runners.model.FrameworkMethod$1.runReflectiveCall"; + private static final String UNKNOWN_TEST_METHOD_NAME = "UnknownTestPackage.UnknownTestClass.Unknown"; + private static final ArrayList StackTraces = new ArrayList<>(); + + public static Object commonEnter() { + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + String[] stackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + + if (isAcceptedTrace(stackTrace)) { + // Print reached api method here. + + ReachedCollector.Log(StackTraces.get(StackTraces.size() - 1)[0]); + + return "valid"; + } else { + return null; + } + } + + public static void commonExit(Object entryContext) { + if (entryContext == null) { + return; + } + + StackTraceElement[] stackTraceElements = new Throwable().getStackTrace(); + String[] currentStackTrace = Arrays.stream(stackTraceElements).skip(2).map(t -> String.format("%s.%s", t.getClassName(), t.getMethodName())).toArray(String[]::new); + + synchronized (StackTraces) { + // Remove existing stacktrace + for (int StoredPreviousStackTraceIndex = 0; StoredPreviousStackTraceIndex < StackTraces.size(); StoredPreviousStackTraceIndex++) { + String[] StoredPreviousStackTrace = StackTraces.get(StoredPreviousStackTraceIndex); + + if (StoredPreviousStackTrace.length != currentStackTrace.length) { + continue; + } + + boolean match = true; + + for (int i = 0; i < StoredPreviousStackTrace.length; i++) { + String methodName = StoredPreviousStackTrace[i]; + if (!methodName.equals(currentStackTrace[i])) { + match = false; + break; + } + } + + if (match) { + StackTraces.remove(StoredPreviousStackTraceIndex); + break; + } + } + } + } + + private static String getTestMethodName(String[] stackTrace) { + for (int i = 3; i < stackTrace.length; i++) { + String methodName = stackTrace[i]; + if (methodName.equals(JUNIT_REFLECTION_UTILS_INVOKE_METHOD_FQN)) { + return stackTrace[i - 3]; + } + } + + for (int i = 5; i < stackTrace.length; i++) { + String methodName = stackTrace[i]; + if (methodName.equals(JUNIT_FRAMEWORK_METHOD_RUN_REFLECTIVE_CALL)) { + return stackTrace[i - 5]; + } + } + + return UNKNOWN_TEST_METHOD_NAME; + } + + private static String[] getCutOffStackTrace(String[] stackTrace) { + String testName = getTestMethodName(stackTrace); + ArrayList cutOffStackTrace = new ArrayList<>(); + for (String stackTraceMethodName : stackTrace) { + if (stackTraceMethodName.startsWith("org.junit.") || + stackTraceMethodName.startsWith("sun.") || + stackTraceMethodName.startsWith("jdk.") || + stackTraceMethodName.startsWith("java.")) { + continue; + } + + cutOffStackTrace.add(stackTraceMethodName); + + if (stackTraceMethodName.equals(testName)) { + break; + } + } + + return cutOffStackTrace.stream().toArray(String[]::new); + } + + private static boolean isAcceptedTrace(String[] stackTrace) { + synchronized (StackTraces) { + int loggerInstance = Logger.GetInstance(); + + stackTrace = getCutOffStackTrace(stackTrace); + + Logger.Log(loggerInstance, "++CommonAdvisor::isAcceptedTrace"); + + Logger.Log(loggerInstance, " Incoming StackTrace:"); + for (String methodName : stackTrace) { + Logger.Log(loggerInstance, String.format(" %s", methodName)); + } + + for (String[] previousStackTrace : StackTraces) { + previousStackTrace = getCutOffStackTrace(previousStackTrace); + + // An existing stacktrace can only be smaller than us if they overlap + if (previousStackTrace.length >= stackTrace.length) { + continue; + } + + boolean matchesExistingStackTrace = true; + for (int i = 0; i < previousStackTrace.length; i++) { + String oldMethod = previousStackTrace[previousStackTrace.length - 1 - i]; + String newMethod = stackTrace[stackTrace.length - 1 -i]; + + if (!oldMethod.equals(newMethod)) { + matchesExistingStackTrace = false; + break; + } + } + + if (matchesExistingStackTrace) { + Logger.Log(loggerInstance, " Rejected Trace"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); + + return false; + } + } + + Logger.Log(loggerInstance, " Accepted Trace"); + Logger.Log(loggerInstance, "--CommonAdvisor::isAcceptedTrace"); + StackTraces.add(stackTrace); + return true; + } + } +} \ No newline at end of file diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/visitors/ConstructorAdvisor.java b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/ConstructorAdvisor.java new file mode 100644 index 00000000..5c2be157 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/ConstructorAdvisor.java @@ -0,0 +1,26 @@ +package com.github.gilesi.coverage.visitors; + +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Executable; + +public class ConstructorAdvisor { + @Advice.OnMethodEnter(inline = false) + public static Object enter( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + return CommonAdvisor.commonEnter(); + } + + @Advice.OnMethodExit(inline = false) + public static void exit( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) String entryTrace) { + CommonAdvisor.commonExit(entryTrace); + } +} \ No newline at end of file diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/visitors/LoggingListener.java b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/LoggingListener.java new file mode 100644 index 00000000..778272bb --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/LoggingListener.java @@ -0,0 +1,50 @@ +package com.github.gilesi.coverage.visitors; + +import com.github.gilesi.coverage.Logger; +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.description.type.TypeDescription; +import net.bytebuddy.dynamic.DynamicType; +import net.bytebuddy.utility.JavaModule; + +import java.io.PrintWriter; +import java.io.StringWriter; + +public class LoggingListener implements AgentBuilder.Listener { + private int loggerInstance = Logger.GetInstance(); + + @Override + public void onDiscovery(String typeName, ClassLoader classLoader, JavaModule module, + boolean loaded) { + } + + @Override + public void onTransformation(TypeDescription typeDescription, ClassLoader classLoader, + JavaModule module, boolean loaded, DynamicType dynamicType) { + + } + + @Override + public void onIgnored(TypeDescription typeDescription, ClassLoader classLoader, + JavaModule module, boolean loaded) { + } + + @Override + public void onError(String typeName, ClassLoader classLoader, JavaModule module, + boolean loaded, Throwable throwable) { + Logger.Log(loggerInstance, String.format("BYTEBUDDY INSTRUMENTATION ERROR:")); + Logger.Log(loggerInstance, String.format("Type Name: %s", typeName)); + Logger.Log(loggerInstance, String.format("Loaded: %s", loaded)); + Logger.Log(loggerInstance, String.format("Exception: %s", throwable)); + + StringWriter writer = new StringWriter(); + throwable.printStackTrace(new PrintWriter(writer)); + String stackTrace = writer.toString(); + + Logger.Log(loggerInstance, String.format("Stack Trace: %s", stackTrace)); + } + + @Override + public void onComplete(String typeName, ClassLoader classLoader, JavaModule module, + boolean loaded) { + } +} \ No newline at end of file diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodAdvisor.java b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodAdvisor.java new file mode 100644 index 00000000..5bcc1dd2 --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodAdvisor.java @@ -0,0 +1,27 @@ +package com.github.gilesi.coverage.visitors; + +import net.bytebuddy.asm.Advice; +import net.bytebuddy.implementation.bytecode.assign.Assigner; + +import java.lang.reflect.Executable; + +public class MethodAdvisor { + @Advice.OnMethodEnter(inline = false) + public static Object enter( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance) { + return CommonAdvisor.commonEnter(); + } + + @Advice.OnMethodExit(onThrowable = Throwable.class, inline = false) + public static void exit( + @Advice.Origin Executable origin, + @Advice.AllArguments(typing = Assigner.Typing.DYNAMIC) Object[] arguments, + @Advice.Return(typing = Assigner.Typing.DYNAMIC) Object returned, + @Advice.This(typing = Assigner.Typing.DYNAMIC, optional = true) Object instance, + @Advice.Thrown Throwable thrown, + @Advice.Enter(typing = Assigner.Typing.DYNAMIC) String entryTrace) { + CommonAdvisor.commonExit(entryTrace); + } +} \ No newline at end of file diff --git a/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodInstrumentor.java b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodInstrumentor.java new file mode 100644 index 00000000..f501c9dd --- /dev/null +++ b/Coverage/src/main/java/com/github/gilesi/coverage/visitors/MethodInstrumentor.java @@ -0,0 +1,82 @@ +package com.github.gilesi.coverage.visitors; + +import net.bytebuddy.agent.builder.AgentBuilder; +import net.bytebuddy.asm.Advice; +import net.bytebuddy.description.method.MethodDescription; +import net.bytebuddy.matcher.ElementMatcher; +import net.bytebuddy.matcher.ElementMatchers; + +import java.lang.instrument.Instrumentation; + +import com.github.gilesi.confgencoverage.models.Class; +import com.github.gilesi.confgencoverage.models.Method; + +import static net.bytebuddy.matcher.ElementMatchers.named; + +public class MethodInstrumentor { + // commented out due to hooking issues + // yet to investigate + /*private static ElementMatcher.Junction getConstructorElementMatcherFromClassParameter(Class classParameter) { + ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : classParameter.ClassDescriptors) { + if (descriptorMatcher == null) { + descriptorMatcher = hasDescriptor(descriptorParameter); + } else { + descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); + } + } + return descriptorMatcher; + }*/ + + private static ElementMatcher.Junction getMethodElementMatcherFromClassParameter(Class classParameter) { + ElementMatcher.Junction classMatcher = null; + for (Method methodParameter : classParameter.ClassMethods) { + ElementMatcher.Junction methodMatcher = named(methodParameter.MethodName); + // commented out due to hooking issues + // yet to investigate + /*ElementMatcher.Junction descriptorMatcher = null; + for (String descriptorParameter : methodParameter.MethodDescriptors) { + if (descriptorMatcher == null) { + descriptorMatcher = hasDescriptor(descriptorParameter); + } else { + descriptorMatcher = descriptorMatcher.or(hasDescriptor(descriptorParameter)); + } + } + + if (descriptorMatcher != null) { + methodMatcher = methodMatcher.and(descriptorMatcher); + }*/ + + if (classMatcher == null) { + classMatcher = methodMatcher; + } else { + classMatcher = classMatcher.or(methodMatcher); + } + } + return classMatcher; + } + + public static void instrumentClassForTracingAgent(Instrumentation inst, Class classParameter) { + ElementMatcher.Junction methodMatcher = getMethodElementMatcherFromClassParameter(classParameter); + //ElementMatcher.Junction constructorMatcher = getConstructorElementMatcherFromClassParameter(classParameter); + + new AgentBuilder.Default() + .with(new LoggingListener()) + .type(named(classParameter.ClassName)) + .transform((builder, + typeDescription, + classLoader, + javaModule, + protectionDomain) -> + builder + .visit( + Advice.to(MethodAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer().or(ElementMatchers.isConstructor())).and(methodMatcher)) + ) + .visit( + Advice.to(ConstructorAdvisor.class).on(ElementMatchers.not(ElementMatchers.isTypeInitializer()).and(ElementMatchers.isConstructor())/*.and(constructorMatcher)*/) + ) + ) + .with(AgentBuilder.RedefinitionStrategy.REDEFINITION) + .with(AgentBuilder.TypeStrategy.Default.REDEFINE).installOn(inst); + } +} \ No newline at end of file diff --git a/IllicoCoverage/.gitignore b/IllicoCoverage/.gitignore new file mode 100644 index 00000000..d4c6a6aa --- /dev/null +++ b/IllicoCoverage/.gitignore @@ -0,0 +1,39 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/* +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/IllicoCoverage/build.gradle b/IllicoCoverage/build.gradle new file mode 100644 index 00000000..1f4ed4fd --- /dev/null +++ b/IllicoCoverage/build.gradle @@ -0,0 +1,81 @@ +plugins { + id 'application' + id 'com.github.johnrengelman.shadow' version '8.1.1' +} + +group 'com.github.gilesi.illicocoverage' +version '1.0-SNAPSHOT' + + +compileJava { + options.encoding = 'UTF-8' +} + +tasks.withType(JavaCompile).configureEach { + options.encoding = 'UTF-8' +} + +repositories { + mavenCentral() + mavenLocal() + maven { + url 'https://packages.jetbrains.team/maven/p/ij/intellij-dependencies' + } +} + +dependencies { + implementation 'com.fasterxml.jackson.core:jackson-core:2.17.2' + implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-databind:2.17.2' + implementation 'com.fasterxml.jackson.core:jackson-annotations:2.17.2' + implementation 'com.fasterxml.jackson:jackson-base:2.17.2' + implementation 'org.apache.maven:maven-core:3.9.9' + implementation 'org.apache.maven.shared:maven-invoker:3.3.0' + testImplementation platform('org.junit:junit-bom:5.11.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + implementation 'org.apache.logging.log4j:log4j-core:2.24.0' + implementation 'org.apache.logging.log4j:log4j-api:2.24.0' +} + +jar { + manifest { + attributes 'Main-Class': 'com.github.gilesi.illicocoverage.Main', + 'Multi-Release': 'true' + } +} + +application { + mainClass = 'com.github.gilesi.illicocoverage.Main' +} + +description = 'Main distribution.' + +shadowJar { + archiveBaseName.set('com.github.gilesi.illicocoverage') + archiveClassifier.set('') + archiveVersion.set('') + mergeServiceFiles() +} + +distributions { + shadow { + distributionBaseName = 'com.github.gilesi.illicocoverage' + } +} + +apply plugin: 'java' +apply plugin: 'idea' + +idea { + module { + downloadJavadoc = true + downloadSources = true + } +} + +run { + jvmArgs = [ + "-XX:InitialHeapSize=2G", + "-XX:MaxHeapSize=32G" + ] +} \ No newline at end of file diff --git a/IllicoCoverage/gradle/wrapper/gradle-wrapper.jar b/IllicoCoverage/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..249e5832f090a2944b7473328c07c9755baa3196 GIT binary patch literal 60756 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 '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +APP_NAME="Gradle" +APP_BASE_NAME=${0##*/} + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/IllicoCoverage/gradlew.bat b/IllicoCoverage/gradlew.bat new file mode 100644 index 00000000..107acd32 --- /dev/null +++ b/IllicoCoverage/gradlew.bat @@ -0,0 +1,89 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%" == "" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%" == "" set DIRNAME=. +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if "%ERRORLEVEL%" == "0" goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if "%ERRORLEVEL%"=="0" goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 +exit /b 1 + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/IllicoCoverage/settings.gradle b/IllicoCoverage/settings.gradle new file mode 100644 index 00000000..19c50608 --- /dev/null +++ b/IllicoCoverage/settings.gradle @@ -0,0 +1,2 @@ +rootProject.name = 'Illico' + diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Constants.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Constants.java new file mode 100644 index 00000000..b6fb3846 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Constants.java @@ -0,0 +1,41 @@ +package com.github.gilesi.illicocoverage; + +import java.util.Hashtable; +import java.util.Map; + +public class Constants { + // These paths should already exist on the end user machine for now and never change + public static final String CONF_GEN_COVERAGE_LOCATION = "ConfGenCoverage/build/libs/com.github.gilesi.confgencoverage.jar"; + public static final String TEST_GEN_LOCATION = "TestGenerator/build/libs/com.github.gilesi.testgenerator.jar"; + public static final String TRACE_DIFF_LOCATION = "TraceDiff/build/libs/com.github.gilesi.tracediff.jar"; + public static final String COVERAGE_LOCATION = "Coverage/build/libs/com.github.gilesi.coverage.jar"; + + public static final String JAVA_21_BINARY_LOCATION = "/usr/lib/jvm/java-21-openjdk-amd64"; + + // These paths are dynamically created by the tool but must stay consistent within methods + public static final String targetAgentName = "com.github.gilesi.coverage.jar"; + public static final String targetConfigurationName = "TestWorkflowConfigurationCoverage.json"; + + public static final Map JAVA_VERSIONS = new Hashtable<>() { + { + put("1.5", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.6", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.7", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("1.8", "/usr/lib/jvm/java-8-openjdk-amd64"); + put("11", "/usr/lib/jvm/java-11-openjdk-amd64"); + put("17", "/usr/lib/jvm/java-17-openjdk-amd64"); + put("21", JAVA_21_BINARY_LOCATION); + } + }; + + public static final String GREEN_TEST = "Green"; + public static final String RED_TEST = "Red"; + + public static final String SUREFIRE_VERSION = "2.8"; + public static final String SUREFIRE_GROUPID = "org.apache.maven.plugins"; + public static final String SUREFIRE_ARTIFACTID = "maven-surefire-plugin"; + + public static boolean SKIP_INSTRUMENTATION_RAN_ALREADY_FOR_DEBUGGING = false; + + public static final String M2_REPOSITORY = "/home/gus/.m2/repository"; +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/FileUtils.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/FileUtils.java new file mode 100644 index 00000000..162bc6b0 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/FileUtils.java @@ -0,0 +1,130 @@ +package com.github.gilesi.illicocoverage; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.Objects; +import java.util.regex.Pattern; + +public class FileUtils { + public static void deleteDirectory(File fi) { + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory()) { + deleteDirectory(file); + } + file.delete(); + } + fi.delete(); + } + + public static void deleteDirectoryIfExists(String path) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + deleteDirectory(new File(path)); + } + } + + public static ArrayList enumerateDirectory(File fi, String wildcard, boolean recursive) { + ArrayList files = new ArrayList<>(); + Pattern pattern = Pattern.compile(wildcard); + for (File file : Objects.requireNonNull(fi.listFiles())) { + if (file.isDirectory() && recursive) { + files.addAll(enumerateDirectory(file, wildcard, true)); + } else { + if (pattern.matcher(file.getName()).matches()) { + files.add(file.getPath()); + } + } + } + return files; + } + + public static ArrayList enumerateFiles(String path, String wildcard, boolean recursive) { + Path pa = Path.of(path); + if (Files.exists(pa)) { + return enumerateDirectory(new File(path), wildcard, recursive); + } + return new ArrayList<>(); + } + + public static void ensureDirectoryExistsAndIsEmpty(String path) throws IOException { + Path pa = Path.of(path); + deleteDirectoryIfExists(path); + Files.createDirectory(pa); + } + + public static void backupFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(filePath)) { + return; + } + + if (Files.exists(backupFilePath)) { + Files.delete(backupFilePath); + } + + Files.copy(filePath, backupFilePath); + } + + public static void restoreFile(String fileLocation) throws IOException { + Path filePath = Path.of(fileLocation); + Path backupFilePath = Path.of("%s.orig".formatted(fileLocation)); + + if (!Files.exists(backupFilePath)) { + return; + } + + if (Files.exists(filePath)) { + Files.delete(filePath); + } + + Files.move(backupFilePath, filePath); + } + + public static void copyFolder(File source, File destination) { + if (source.isDirectory()) { + if (!destination.exists()) { + destination.mkdirs(); + } + + String[] files = source.list(); + + for (String file : files) { + File srcFile = new File(source, file); + File destFile = new File(destination, file); + + copyFolder(srcFile, destFile); + } + } else { + InputStream in = null; + OutputStream out = null; + + try { + in = new FileInputStream(source); + out = new FileOutputStream(destination); + + byte[] buffer = new byte[1024]; + + int length; + while ((length = in.read(buffer)) > 0) { + out.write(buffer, 0, length); + } + } catch (Exception e) { + try { + in.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + + try { + out.close(); + } catch (IOException e1) { + e1.printStackTrace(); + } + } + } + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Main.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Main.java new file mode 100644 index 00000000..74b554d6 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Main.java @@ -0,0 +1,194 @@ +package com.github.gilesi.illicocoverage; + +import org.apache.maven.shared.invoker.MavenInvocationException; + +import com.github.gilesi.illicocoverage.runners.maven.Log4JLogger; +import com.github.gilesi.illicocoverage.runners.maven.ProjectRunner; +import com.github.gilesi.illicocoverage.runners.maven.TestAssertedLogger; +import com.github.gilesi.illicocoverage.tools.ConfGenCoverage; + +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Main { + public static final Logger logger = LogManager.getLogger("illicocoverage"); + public static final Logger loggerMaven = LogManager.getLogger("maven"); + public static final Logger loggerConfGenCoverage = LogManager.getLogger("confgencoverage"); + public static final Logger loggerTraceDiff = LogManager.getLogger("tracediff"); + public static final Logger loggerTraceGen = LogManager.getLogger("tracegen"); + public static final Logger loggerAgent = LogManager.getLogger("agent"); + + public static void main(String[] args) throws MavenInvocationException, IOException, InterruptedException { + if (System.getenv("MAVEN_HOME") == null || !Files.exists(Path.of(System.getenv("MAVEN_HOME"))) || Files.isRegularFile(Path.of(System.getenv("MAVEN_HOME")))) { + logger.info("You must specify the MAVEN_HOME environment variable pointing to a valid Maven directory"); + return; + } + + if (args.length < 4) { + logger.info("Usage: "); + return; + } + + String clientLocation = args[0]; + String libraryIdentifier = args[1]; + String outputFolder = args[2]; + String GilesiRepositoryLocation = args[3]; + String optionalCustomTestCommand = null; + + if (args.length > 4) { + optionalCustomTestCommand = args[4]; + } + + ProjectRunner.runMavenGoalOnRepository( + clientLocation, + "dependency:sources", + null, + "1.8", + new Log4JLogger(), + null + ); + + Path outputPath = Path.of(outputFolder).toAbsolutePath(); + + Path libraryPath = outputPath.resolve("library-sources"); + + copyLibrarySourcesForDataset(libraryIdentifier, libraryPath, Path.of(Constants.M2_REPOSITORY)); + + String additionalJavaToolParameters = installInstrumentationAgentOntoProject(Path.of(GilesiRepositoryLocation), libraryPath, Path.of(clientLocation), outputPath.resolve("coverage")); + + String testCmd = "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false"; + + if (optionalCustomTestCommand != null && + !optionalCustomTestCommand.isEmpty() && + !optionalCustomTestCommand.equals("N/A")) { + testCmd = optionalCustomTestCommand; + } + + if (testCmd.startsWith("mvn ")) { + testCmd = testCmd.substring(4); + } + + TestAssertedLogger testAssertedLogger = new TestAssertedLogger( + new Log4JLogger( + logger, + org.apache.maven.shared.invoker.InvokerLogger.INFO, + "%s-%s".formatted(clientLocation, clientLocation) + ) + ); + + ProjectRunner.runMavenGoalOnRepository(clientLocation, + testCmd, + null, + "1.8", + testAssertedLogger, + additionalJavaToolParameters); + + Main.logger.info("Client: %s - TEST(S) FAILED: %s".formatted(clientLocation, + testAssertedLogger.HasTestFailed())); + } + + + private static String installInstrumentationAgentOntoProject( + Path GilesiRepositoryLocationPath, + Path libraryLocationPath, + Path clientLocationPath, + Path generatedFolderPath + ) throws IOException, InterruptedException { + + FileUtils.deleteDirectoryIfExists(generatedFolderPath.toString()); + + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ConfGenCoverage.runConfGenCoverage(GilesiRepositoryLocationPath.toString(), + libraryConfig.toString(), + generatedFolderPath.toString(), + libraryLocationPath.toString()); + + Path InstrumentationAgentEffectiveLocation = GilesiRepositoryLocationPath.resolve(Constants.COVERAGE_LOCATION); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocationPath.toString(), + "pom.xml", + true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocationPath.toString(), + "build.gradle", + true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + Orchestrator.copyInstrumentationToolAndConfiguration(allProjectFiles, + InstrumentationAgentEffectiveLocation, + libraryConfig); + + String javaToolOptions = "-javaagent:%s=%s".formatted(InstrumentationAgentEffectiveLocation, + libraryConfig.toString()); + + Orchestrator.orchestrateGradleProjects(clientProjectGradleBuildFiles); + + return javaToolOptions; + } + + private static void copyLibrarySourcesForDataset(String libraryIdentifier, Path librarySourceOutputPath, Path m2RepositoryPath) throws IOException, MavenInvocationException { + String[] groupId = libraryIdentifier.split(":")[0].split("\\."); + String artifactId = libraryIdentifier.split(":")[1]; + String libraryVersion = libraryIdentifier.split(":")[2]; + + Path fileSystemRepoPath = m2RepositoryPath; + + for (String pathComponent : groupId) { + fileSystemRepoPath = fileSystemRepoPath.resolve(pathComponent); + } + + fileSystemRepoPath = fileSystemRepoPath.resolve(artifactId).resolve(libraryVersion); + + ArrayList srcCandidates = FileUtils.enumerateFiles(fileSystemRepoPath.toString(), ".*sources\\.jar", false); + + if (srcCandidates.size() == 0) { + Main.logger.info("%s Missing sources for lib, aborting!".formatted(libraryIdentifier)); + return; + } + + FileUtils.deleteDirectoryIfExists(librarySourceOutputPath.toString()); + Files.createDirectories(librarySourceOutputPath); + + for (String cand : srcCandidates) { + System.out.println("Extracting " + cand); + System.out.println("Extracting " + librarySourceOutputPath); + extractJar(cand, librarySourceOutputPath.toString()); + } + } + + private static void extractJar(String jar, String destdir) throws java.io.IOException { + java.util.jar.JarFile jarFile = new java.util.jar.JarFile(new java.io.File(jar)); + java.util.Enumeration enu = jarFile.entries(); + while (enu.hasMoreElements()) { + java.util.jar.JarEntry je = enu.nextElement(); + + java.io.File fl = new java.io.File(destdir, je.getName()); + if (!fl.exists()) { + fl.getParentFile().mkdirs(); + fl = new java.io.File(destdir, je.getName()); + } + if (je.isDirectory()) { + continue; + } + java.io.InputStream is = jarFile.getInputStream(je); + java.io.FileOutputStream fo = new java.io.FileOutputStream(fl); + while (is.available() > 0) { + fo.write(is.read()); + } + fo.close(); + is.close(); + } + jarFile.close(); + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Orchestrator.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Orchestrator.java new file mode 100644 index 00000000..7b7b7d84 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/Orchestrator.java @@ -0,0 +1,267 @@ +package com.github.gilesi.illicocoverage; + +import com.github.gilesi.illicocoverage.buildsystem.configuration.maven.PomHelper; +import com.github.gilesi.illicocoverage.runners.maven.Log4JLogger; +import com.github.gilesi.illicocoverage.runners.maven.ProjectRunner; +import com.github.gilesi.illicocoverage.tools.ConfGenCoverage; +import com.github.gilesi.illicocoverage.tools.TestGen; +import org.apache.maven.shared.invoker.MavenInvocationException; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class Orchestrator { + // TODO: More robust logging here using JUnit perhaps... + // TODO: Simplify required arg to run here + // TODO: Ideally we would want to deduce the version from the provided source but not always doable + // TODO: Could we also fetch source jars ourselves somehow or source loc? + // TODO: Maybe the dependency name is also doable to extract here, need to see how... + // TODO: Fix cross plat! + // TODO: picocli? + + public static void handleProject(String clientLocation, String libraryLocation, String GilesiRepositoryLocation, String dependencyName, String dependencyVersion, String outputTestProject) throws XmlPullParserException, IOException, MavenInvocationException, InterruptedException { + FileUtils.deleteDirectoryIfExists(outputTestProject); + Path outputTestProjectPath = Path.of(outputTestProject); + + Path libraryLocationPath = Path.of(libraryLocation); + Path libraryConfig = libraryLocationPath.resolve(Constants.targetConfigurationName); + + // Create the results directory + Files.createDirectories(outputTestProjectPath); + + // Run ConfGen on Library first + // TODO: Check how meta projects get handled here exactly... + ConfGenCoverage.runConfGenCoverage(GilesiRepositoryLocation, libraryConfig.toString(), outputTestProject, libraryLocation); + + Path InstrumentationAgentEffectiveLocation = Path.of("%s%s".formatted(GilesiRepositoryLocation, Constants.COVERAGE_LOCATION)); + + // Modify Client Build System to use the instrumentation agent + ArrayList clientProjectPomFiles = FileUtils.enumerateFiles(clientLocation, "pom.xml", true); + ArrayList clientProjectGradleBuildFiles = FileUtils.enumerateFiles(clientLocation, "build.gradle", true); + + ArrayList allProjectFiles = new ArrayList<>(); + allProjectFiles.addAll(clientProjectPomFiles); + allProjectFiles.addAll(clientProjectGradleBuildFiles); + + copyInstrumentationToolAndConfiguration(allProjectFiles, InstrumentationAgentEffectiveLocation, libraryConfig); + + orchestrateMavenProjects(clientProjectPomFiles); + orchestrateGradleProjects(clientProjectGradleBuildFiles); + + // Run the client tests + executeMavenProjectTests(clientProjectPomFiles, clientLocation); + executeGradleProjectTests(clientProjectGradleBuildFiles, clientLocation); + + TestGen.runTestGen(GilesiRepositoryLocation, outputTestProject, outputTestProjectPath.resolve("src").resolve("test").resolve("java").toString(), libraryConfig.toString()); + + lastMinuteCleanup(allProjectFiles); + + // Generate Gradle test project here in dir outputTestProject, with dep dependencyName of version dependencyVersion + + String buildGradleProjectFile = """ + plugins { + id 'java' + } + + group = 'testProject' + version = '1.0-SNAPSHOT' + + repositories { + mavenCentral() + mavenLocal() + } + + dependencies { + testImplementation '%s:%s' + testImplementation 'com.thoughtworks.xstream:xstream:1.4.20' + testImplementation platform('org.junit:junit-bom:5.10.0') + testImplementation 'org.junit.jupiter:junit-jupiter' + } + + test { + useJUnitPlatform() + }""".formatted(dependencyName, dependencyVersion); + + Files.writeString(outputTestProjectPath.resolve("build.gradle"), buildGradleProjectFile); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("IllicoCoverage").resolve("gradlew"), outputTestProjectPath.resolve("gradlew")); + Files.copy(Path.of(GilesiRepositoryLocation).resolve("IllicoCoverage").resolve("gradlew.bat"), outputTestProjectPath.resolve("gradlew.bat")); + + // Test test project (3 times to be sure) + + // Update test project dependency version at version dependencyNewVersion + + // Test test project with dependency at version dependencyNewVersion (3 times to be sure) + + // Collect results of the execution + + // Write report + } + + public static void copyInstrumentationToolAndConfiguration(ArrayList allProjectFiles, Path InstrumentationAgentEffectiveLocation, Path libraryConfig) throws IOException { + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + + //Files.copy(InstrumentationAgentEffectiveLocation, agentDest); + //Files.copy(libraryConfig, workflowDest); + } + } + + public static void orchestrateMavenProjects(ArrayList clientProjectPomFiles) throws IOException, XmlPullParserException { + for (String clientBuildFile : clientProjectPomFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Files.copy(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + + String clientSurefireArgLine = "-Dnet.bytebuddy.experimental=true -javaagent:%s=%s".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + PomHelper.addSureFire(clientBuildFile, clientSurefireArgLine); + } + } + + public static void orchestrateGradleProjects(ArrayList clientProjectGradleBuildFiles) throws IOException { + for (String clientBuildFile : clientProjectGradleBuildFiles) { + String clientTestingBlock = """ + testing { + \tsuites { + \t\ttest { + \t\t\tuseJUnitJupiter() + \t\t\ttargets { + \t\t\t\tall { + \t\t\t\t\ttestTask.configure { + \t\t\t\t\t\tsystemProperty 'net.bytebuddy.experimental', 'true' + \t\t\t\t\t\tjvmArgs = ['-XX:+EnableDynamicAgentLoading', '-javaagent:%s=%s'] + \t\t\t\t\t} + \t\t\t\t} + \t\t\t} + \t\t} + \t} + }""".formatted(Constants.targetAgentName, Constants.targetConfigurationName); + + Path clientBuildFilePath = Path.of(clientBuildFile); + + String buildFileContent = Files.readString(clientBuildFilePath); + if (!buildFileContent.contains(clientTestingBlock)) { + buildFileContent += "\n" + clientTestingBlock; + + Files.move(clientBuildFilePath, Path.of("%s.gilesi.bak".formatted(clientBuildFile))); + Files.writeString(clientBuildFilePath, buildFileContent); + } + } + } + + public static void executeMavenProjectTests(ArrayList clientProjectPomFiles, String clientLocation) throws MavenInvocationException { + // This is the maven path + if (!clientProjectPomFiles.isEmpty()) { + if (clientProjectPomFiles.stream().anyMatch(t -> t.replace("%s%c".formatted(clientLocation, File.separatorChar), "").replace(clientLocation, "").equals("pom.xml"))) { + ProjectRunner.runMavenGoalOnRepository(clientLocation, "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); + } else { + for (String clientPomFile : clientProjectPomFiles) { + Path clientPomFilePath = Path.of(clientPomFile); + Path clientProjectLocationPath = clientPomFilePath.getParent().toAbsolutePath(); + + ProjectRunner.runMavenGoalOnRepository(clientProjectLocationPath.toString(), "-fn test -Danimal.sniffer.skip=true", null, "21", new Log4JLogger(), null); + } + } + } + } + + public static void executeGradleProjectTests(ArrayList clientProjectGradleBuildFiles, String clientLocation) throws IOException, InterruptedException { + // This is the gradle path + if (!clientProjectGradleBuildFiles.isEmpty()) { + if (clientProjectGradleBuildFiles.stream().anyMatch + ( + t -> + t + .replace( + "%s%c" + .formatted( + clientLocation, + File.separatorChar + ), + "" + ) + .replace( + clientLocation, + "" + ) + .equals("build.gradle") + )) { + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + Path.of(clientLocation).resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientLocation), Main.logger); + + // TODO: Check for underlying platform + /*ProcessUtils.runExternalCommand(new String[]{ + "cmd.exe", + "-C", + Path.of(clientLocation).resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientLocation), Main.logger);*/ + } else { + for (String clientGradleBuildFile : clientProjectGradleBuildFiles) { + Path clientGradleBuildFilePath = Path.of(clientGradleBuildFile); + Path clientProjectLocationPath = clientGradleBuildFilePath.getParent().toAbsolutePath(); + + ProcessUtils.runExternalCommand(new String[]{ + "/usr/bin/env", + "bash", + clientProjectLocationPath.resolve("gradlew").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString()), Main.logger); + + // TODO: Check for underlying platform + /*ProcessUtils.runExternalCommand(new String[]{ + "cmd.exe", + "-C", + clientProjectLocationPath.resolve("gradlew.bat").toString(), + "test", + "--warning-mode", + "all" + }, new File(clientProjectLocationPath.toString()), Main.logger);*/ + } + } + } + } + + public static void lastMinuteCleanup(ArrayList allProjectFiles) throws IOException { + // Last minute cleanup + for (String clientBuildFile : allProjectFiles) { + Path clientBuildFilePath = Path.of(clientBuildFile); + Path clientProjectLocationPath = clientBuildFilePath.getParent().toAbsolutePath(); + Path agentDest = clientProjectLocationPath.resolve(Constants.targetAgentName); + Path workflowDest = clientProjectLocationPath.resolve(Constants.targetConfigurationName); + + Path clientBuildFileBackup = Path.of("%s.gilesi.bak".formatted(clientBuildFile)); + if (Files.exists(clientBuildFileBackup)) { + Files.deleteIfExists(clientBuildFilePath); + Files.move(clientBuildFileBackup, clientBuildFilePath); + } + + Files.deleteIfExists(agentDest); + Files.deleteIfExists(workflowDest); + } + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/ProcessUtils.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/ProcessUtils.java new file mode 100644 index 00000000..d83f9c72 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/ProcessUtils.java @@ -0,0 +1,26 @@ +package com.github.gilesi.illicocoverage; + +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; + +public class ProcessUtils { + public static int runExternalCommand(String[] command, File directory, org.apache.logging.log4j.Logger logger) throws IOException, InterruptedException { + ProcessBuilder pb = new ProcessBuilder(command); + if (directory != null) { + pb.directory(directory); + } + pb.redirectErrorStream(true); + Process p = pb.start(); + BufferedReader reader = new BufferedReader(new InputStreamReader(p.getInputStream())); + + String line; + + while ((line = reader.readLine()) != null) { + logger.info(line); + } + + return p.waitFor(); + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/RunResult.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/RunResult.java new file mode 100644 index 00000000..dd3629fd --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/RunResult.java @@ -0,0 +1,22 @@ +package com.github.gilesi.illicocoverage; + +import com.github.gilesi.illicocoverage.testing.ReportItem; + +import java.util.ArrayList; + +public class RunResult { + public String ProjectId = ""; + public boolean ProjectIsMissingLibrarySourceCode = false; + public boolean ProjectCannotBeReproduced = false; // TODO + public boolean ProjectCannotBeInstrumented = false; + public boolean ProjectFailedToLoadAgent = false; + public boolean ProjectIsMissingTraceFiles = false; + public boolean ProjectIsMissingSpecificTraces = false; + public boolean ProjectFailedToGenerateAnyTraceTestSrc = false; + public boolean ProjectFailedToCompileGeneratedTests = false; + public boolean ProjectFailedToExecuteGeneratedTests = false; + public boolean ProjectFailedToCompileGeneratedTestsWithNewVersion = false; + public boolean ProjectFailedToExecuteGeneratedTestsWithNewVersion = false; + public ArrayList TestExecutionReportWithOldVersion; + public ArrayList TestExecutionReportWithNewVersion; +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/ConfigurationUtils.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/ConfigurationUtils.java new file mode 100644 index 00000000..d6b50802 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/ConfigurationUtils.java @@ -0,0 +1,31 @@ +package com.github.gilesi.illicocoverage.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class ConfigurationUtils { + public static Xpp3Dom getDomValueObject(String name, String value) { + Xpp3Dom domValue = new Xpp3Dom(name); + domValue.setValue(value); + return domValue; + } + + public static Xpp3Dom getDomArrayObject(String arrayName, String name, String[] values) { + Xpp3Dom valuesDom = new Xpp3Dom(arrayName); + for (String val : values) { + addStringValueIfNotEmpty(valuesDom, name, val); + } + return valuesDom; + } + + public static void addStringValueIfNotEmpty(Xpp3Dom config, String name, String value) { + if (value != null && !value.isEmpty()) { + config.addChild(getDomValueObject(name, value)); + } + } + + public static void addStringArrayValueIfNotEmpty(Xpp3Dom config, String arrayName, String name, String[] values) { + if (values != null && values.length > 0) { + config.addChild(getDomArrayObject(arrayName, name, values)); + } + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/IPluginConfiguration.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/IPluginConfiguration.java new file mode 100644 index 00000000..708afa64 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/IPluginConfiguration.java @@ -0,0 +1,7 @@ +package com.github.gilesi.illicocoverage.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public interface IPluginConfiguration { + Xpp3Dom serialize(); +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/PomHelper.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/PomHelper.java new file mode 100644 index 00000000..67f852fc --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/PomHelper.java @@ -0,0 +1,154 @@ +package com.github.gilesi.illicocoverage.buildsystem.configuration.maven; + +import com.github.gilesi.illicocoverage.Constants; +import org.apache.maven.model.Build; +import org.apache.maven.model.Dependency; +import org.apache.maven.model.Model; +import org.apache.maven.model.Plugin; +import org.apache.maven.model.io.xpp3.MavenXpp3Reader; +import org.apache.maven.model.io.xpp3.MavenXpp3Writer; +import org.codehaus.plexus.util.xml.Xpp3Dom; +import org.codehaus.plexus.util.xml.pull.XmlPullParserException; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; + +public class PomHelper { + + public static Model readPomFile(String pomFilePath) throws IOException, XmlPullParserException { + MavenXpp3Reader pomReader = new MavenXpp3Reader(); + Path pomPath = Path.of(pomFilePath); + InputStream pomStream = Files.newInputStream(pomPath); + Model pomModel = pomReader.read(pomStream); + pomModel.setPomFile(new File(pomFilePath)); + pomStream.close(); + return pomModel; + } + + private static void writePomFile(Model pomModel, String pomFilePath) throws IOException { + MavenXpp3Writer pomWriter = new MavenXpp3Writer(); + FileWriter pomWriteStream = new FileWriter(pomFilePath); + pomWriter.write(pomWriteStream, pomModel); + pomWriteStream.close(); + } + + private static boolean doesBuildContainPluginGroupId(Build bld, String groupId) { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static boolean doesModelContainDependencyGroupId(Model pomModel, String groupId) { + for (Dependency plg : pomModel.getDependencies()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return true; + } + } + return false; + } + + private static Plugin getPluginByGroupId(Build bld, String groupId) throws FileNotFoundException { + for (Plugin plg : bld.getPlugins()) { + if (plg.getGroupId().equalsIgnoreCase(groupId)) { + return plg; + } + } + throw new FileNotFoundException(); + } + + private static Xpp3Dom buildSureFireConfiguration() { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + return sureFireConfiguration.serialize(); + } + + private static Xpp3Dom buildSureFireConfiguration(String argLine) { + SureFirePluginConfiguration sureFireConfiguration = new SureFirePluginConfiguration(); + sureFireConfiguration.setArgLine(argLine); + return sureFireConfiguration.serialize(); + } + + private static Plugin getSureFirePlugin() { + return buildPlugin(Constants.SUREFIRE_GROUPID, Constants.SUREFIRE_ARTIFACTID, Constants.SUREFIRE_VERSION); + } + + private static Dependency buildDependency(String groupId, String artifactId, String version) { + Dependency dependency = new Dependency(); + dependency.setGroupId(groupId); + dependency.setArtifactId(artifactId); + dependency.setVersion(version); + return dependency; + } + + private static Plugin buildPlugin(String groupId, String artifactId, String version) { + Plugin plugin = new Plugin(); + plugin.setGroupId(groupId); + plugin.setArtifactId(artifactId); + plugin.setVersion(version); + return plugin; + } + + private static Plugin buildSureFirePlugin() { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static Plugin buildSureFirePlugin(String argLine) { + Plugin surePlugin = getSureFirePlugin(); + Xpp3Dom config = buildSureFireConfiguration(argLine); + surePlugin.setConfiguration(config); + return surePlugin; + } + + private static void removeExistingPlugin(Build bld, String groupId) throws FileNotFoundException { + // Get rid of all previous instances of the plugin in case one already exists + while (doesBuildContainPluginGroupId(bld, groupId)) { + bld.removePlugin(getPluginByGroupId(bld, groupId)); + } + } + + private static void removeExistingSureFirePlugins(Build bld) throws FileNotFoundException { + removeExistingPlugin(bld, Constants.SUREFIRE_GROUPID); + } + + public static void addSureFire(String pomFilePath) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } + + public static void addSureFire(String pomFilePath, String argLine) throws XmlPullParserException, IOException { + Model pomModel = readPomFile(pomFilePath); + Build bld = pomModel.getBuild(); + + if (bld == null) { + bld = new Build(); + } + + removeExistingSureFirePlugins(bld); + + Plugin surePlugin = buildSureFirePlugin(argLine); + + bld.addPlugin(surePlugin); + + pomModel.setBuild(bld); + writePomFile(pomModel, pomFilePath); + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/SureFirePluginConfiguration.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/SureFirePluginConfiguration.java new file mode 100644 index 00000000..339b33b4 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/buildsystem/configuration/maven/SureFirePluginConfiguration.java @@ -0,0 +1,103 @@ +package com.github.gilesi.illicocoverage.buildsystem.configuration.maven; + +import org.codehaus.plexus.util.xml.Xpp3Dom; + +public class SureFirePluginConfiguration implements IPluginConfiguration { + private int forkCount = 1; + private boolean reuseForks = false; + private String argLine = "-Xmx2G -XX:MaxMetaspaceSize=2G"; + private String parallel = "methods"; + private int threadCount = 1; + private String forkedProcessTimeoutInSeconds = "40"; + private String forkedProcessExitTimeoutInSeconds = "40"; + private String parallelTestsTimeoutInSeconds = "30"; + private String parallelTestsTimeoutForcedInSeconds = "30"; + + public int getForkCount() { + return forkCount; + } + + public void setForkCount(int forkCount) { + this.forkCount = forkCount; + } + + public int getThreadCount() { + return threadCount; + } + + public void setThreadCount(int threadCount) { + this.threadCount = threadCount; + } + + public String getArgLine() { + return argLine; + } + + public void setArgLine(String argLine) { + this.argLine = argLine; + } + + public String getForkedProcessExitTimeoutInSeconds() { + return forkedProcessExitTimeoutInSeconds; + } + + public void setForkedProcessExitTimeoutInSeconds(String forkedProcessExitTimeoutInSeconds) { + this.forkedProcessExitTimeoutInSeconds = forkedProcessExitTimeoutInSeconds; + } + + public String getForkedProcessTimeoutInSeconds() { + return forkedProcessTimeoutInSeconds; + } + + public void setForkedProcessTimeoutInSeconds(String forkedProcessTimeoutInSeconds) { + this.forkedProcessTimeoutInSeconds = forkedProcessTimeoutInSeconds; + } + + public String getParallelTestsTimeoutForcedInSeconds() { + return parallelTestsTimeoutForcedInSeconds; + } + + public void setParallelTestsTimeoutForcedInSeconds(String parallelTestsTimeoutForcedInSeconds) { + this.parallelTestsTimeoutForcedInSeconds = parallelTestsTimeoutForcedInSeconds; + } + + public String getParallelTestsTimeoutInSeconds() { + return parallelTestsTimeoutInSeconds; + } + + public void setParallelTestsTimeoutInSeconds(String parallelTestsTimeoutInSeconds) { + this.parallelTestsTimeoutInSeconds = parallelTestsTimeoutInSeconds; + } + + public String getParallel() { + return parallel; + } + + public void setParallel(String parallel) { + this.parallel = parallel; + } + + public boolean getReuseForks() { + return reuseForks; + } + + public void setReuseForks(boolean reuseForks) { + this.reuseForks = reuseForks; + } + + public Xpp3Dom serialize() { + Xpp3Dom config = new Xpp3Dom("configuration"); + + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkCount", Integer.toString(forkCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "reuseForks", Boolean.toString(reuseForks)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "argLine", argLine); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallel", parallel); + ConfigurationUtils.addStringValueIfNotEmpty(config, "threadCount", Integer.toString(threadCount)); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessTimeoutInSeconds", forkedProcessTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "forkedProcessExitTimeoutInSeconds", forkedProcessExitTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutInSeconds", parallelTestsTimeoutInSeconds); + ConfigurationUtils.addStringValueIfNotEmpty(config, "parallelTestsTimeoutForcedInSeconds", parallelTestsTimeoutForcedInSeconds); + + return config; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ConsoleLogger.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ConsoleLogger.java new file mode 100644 index 00000000..0b4775df --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ConsoleLogger.java @@ -0,0 +1,248 @@ +package com.github.gilesi.illicocoverage.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; +import java.util.Date; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class ConsoleLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The threshold used to filter messages. + */ + private int threshold; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public ConsoleLogger() { + this(INFO); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param threshold The threshold for the logger. + */ + public ConsoleLogger(int threshold) { + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + String logLevel = "INFO"; + + switch (level) { + case (DEBUG) -> logLevel = "DEBUG"; + case (INFO) -> logLevel = "INFO"; + case (WARN) -> logLevel = "WARN"; + case (ERROR) -> logLevel = "ERROR"; + case (FATAL) -> logLevel = "FATAL"; + default -> { + } + } + + buffer.append("[Maven] "); + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + System.out.printf("[%s] [%s] %s%n", new Date(), logLevel, buffer); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/Log4JLogger.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/Log4JLogger.java new file mode 100644 index 00000000..72c2fb13 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/Log4JLogger.java @@ -0,0 +1,271 @@ +package com.github.gilesi.illicocoverage.runners.maven; + +/* + * Licensed to the Apache Software Foundation (ASF) under one + * or more contributor license agreements. See the NOTICE file + * distributed with this work for additional information + * regarding copyright ownership. The ASF licenses this file + * to you under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance + * with the License. You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, + * software distributed under the License is distributed on an + * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the + * specific language governing permissions and limitations + * under the License. + */ + +import org.apache.logging.log4j.Level; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.PrintWriter; +import java.io.StringWriter; + +/** + * Offers a logger that writes to a print stream like {@link java.lang.System#out}. + * + * @since 2.0.9 + */ +public class Log4JLogger implements InvokerLogger, InvocationOutputHandler { + + /** + * The print stream to write to, never null. + */ + private final Logger out; + + /** + * The threshold used to filter messages. + */ + private int threshold; + + private String prefix; + + /** + * Creates a new logger that writes to {@link java.lang.System#out} and has a threshold of {@link #INFO}. + */ + public Log4JLogger() { + this(LogManager.getLogger(), INFO, ""); + } + + public Log4JLogger(String prefix) { + this(LogManager.getLogger(), INFO, prefix); + } + + /** + * Creates a new logger that writes to the specified print stream. + * + * @param out The print stream to write to, must not be null. + * @param threshold The threshold for the logger. + */ + public Log4JLogger(Logger out, int threshold, String prefix) { + if (out == null) { + throw new NullPointerException("missing output stream"); + } + this.prefix = prefix; + this.out = out; + setThreshold(threshold); + } + + /** + * Writes the specified message and exception to the print stream. + * + * @param level The priority level of the message. + * @param message The message to log, may be null. + * @param error The exception to log, may be null. + */ + private void log(int level, String message, Throwable error) { + if (level > threshold) { + // don't log when it doesn't match your threshold. + return; + } + + if (message == null && error == null) { + // don't log when there's nothing to log. + return; + } + + StringBuilder buffer = new StringBuilder(); + Level logLevel = Level.INFO; + + switch (level) { + case (DEBUG) -> logLevel = Level.DEBUG; + case (INFO) -> logLevel = Level.INFO; + case (WARN) -> logLevel = Level.WARN; + case (ERROR) -> logLevel = Level.ERROR; + case (FATAL) -> logLevel = Level.FATAL; + default -> { + } + } + + if (prefix != null && !prefix.isEmpty()) { + buffer.append("[%s-Maven] ".formatted(prefix)); + } else { + buffer.append("[Maven] "); + } + + if (message != null) { + buffer.append(message); + } + + if (error != null) { + StringWriter writer = new StringWriter(); + PrintWriter pWriter = new PrintWriter(writer); + + error.printStackTrace(pWriter); + + if (message != null) { + buffer.append('\n'); + } + + buffer.append("Error:\n"); + buffer.append(writer); + } + + out.log(logLevel, buffer.toString()); + } + + /** + * {@inheritDoc} + */ + public void debug(String message) { + log(DEBUG, message, null); + } + + /** + * {@inheritDoc} + */ + public void debug(String message, Throwable throwable) { + log(DEBUG, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void info(String message) { + log(INFO, message, null); + } + + /** + * {@inheritDoc} + */ + public void info(String message, Throwable throwable) { + log(INFO, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void warn(String message) { + log(WARN, message, null); + } + + /** + * {@inheritDoc} + */ + public void warn(String message, Throwable throwable) { + log(WARN, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void error(String message) { + log(ERROR, message, null); + } + + /** + * {@inheritDoc} + */ + public void error(String message, Throwable throwable) { + log(ERROR, message, throwable); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message) { + log(FATAL, message, null); + } + + /** + * {@inheritDoc} + */ + public void fatalError(String message, Throwable throwable) { + log(FATAL, message, throwable); + } + + /** + *

isDebugEnabled.

+ * + * @return a boolean. + */ + public boolean isDebugEnabled() { + return threshold >= DEBUG; + } + + /** + *

isErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isErrorEnabled() { + return threshold >= ERROR; + } + + /** + *

isFatalErrorEnabled.

+ * + * @return a boolean. + */ + public boolean isFatalErrorEnabled() { + return threshold >= FATAL; + } + + /** + *

isInfoEnabled.

+ * + * @return a boolean. + */ + public boolean isInfoEnabled() { + return threshold >= INFO; + } + + /** + *

isWarnEnabled.

+ * + * @return a boolean. + */ + public boolean isWarnEnabled() { + return threshold >= WARN; + } + + /** + *

Getter for the field threshold.

+ * + * @return an int. + */ + public int getThreshold() { + return threshold; + } + + /** + * {@inheritDoc} + */ + public void setThreshold(int threshold) { + this.threshold = threshold; + } + + /** + * {@inheritDoc} + */ + public void consumeLine(String line) { + log(INFO, line, null); + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ProjectRunner.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ProjectRunner.java new file mode 100644 index 00000000..7a6eacbd --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/ProjectRunner.java @@ -0,0 +1,181 @@ +package com.github.gilesi.illicocoverage.runners.maven; + +import com.github.gilesi.illicocoverage.Constants; +import com.github.gilesi.illicocoverage.Main; +import org.apache.maven.model.*; +import org.apache.maven.shared.invoker.*; + +import java.io.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import static com.github.gilesi.illicocoverage.buildsystem.configuration.maven.PomHelper.readPomFile; + +public class ProjectRunner { + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, Object logger, String javaToolOptions) + throws MavenInvocationException { + + String javaVersion = "8"; + + try { + Model pomModel = readPomFile(pomFilePath); + Properties props = pomModel.getProperties(); + if (props.stringPropertyNames().contains("java.compiler.version")) { + javaVersion = props.getProperty("java.compiler.version"); + Main.logger.info("Debug: Using java.compiler.version=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.source")) { + javaVersion = props.getProperty("maven.compiler.source"); + Main.logger.info("Debug: Using maven.compiler.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compiler.target")) { + javaVersion = props.getProperty("maven.compiler.target"); + Main.logger.info("Debug: Using maven.compiler.target=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.source")) { + javaVersion = props.getProperty("maven.compile.source"); + Main.logger.info("Debug: Using maven.compile.source=" + javaVersion); + } else if (props.stringPropertyNames().contains("maven.compile.target")) { + javaVersion = props.getProperty("maven.compile.target"); + Main.logger.info("Debug: Using maven.compile.target=" + javaVersion); + } + } catch (Exception ignored) { + Main.logger.info("Debug: Getting java specific version unfortunately failed."); + } + + return runPomGoals(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaVersion, logger, + javaToolOptions); + } + + public static int runPomGoals(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String javaVersion, Object logger, String javaToolOptions) + throws MavenInvocationException { + String javaHome = Constants.JAVA_VERSIONS.getOrDefault(javaVersion, System.getenv("JAVA_HOME")); + return runPomGoalsInternal(pomFilePath, pomGoals, pomProperties, batchMode, userSettingsFilePath, javaHome, + javaVersion, logger, javaToolOptions); + } + + public static int runPomGoalsInternal(String pomFilePath, List pomGoals, List pomProperties, + boolean batchMode, String userSettingsFilePath, String JavaHome, String JavaVersion, Object logger, + String javaToolOptions) throws MavenInvocationException { + File pomFile = new File(pomFilePath); + + InvokerLogger invokerLogger = null; + InvocationOutputHandler invocationOutputHandler = null; + + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + + File projectDirectory = new File(Path.of(pomFilePath).getParent().toString()); + + Properties properties = new Properties(); + pomProperties.forEach(p -> properties.setProperty(p, "true")); + + properties.setProperty("maven.compiler.source", JavaVersion); + properties.setProperty("maven.compiler.target", JavaVersion); + properties.setProperty("maven.compile.source", JavaVersion); + properties.setProperty("maven.compile.target", JavaVersion); + + properties.setProperty("maven.source.skip", "true"); + properties.setProperty("assembly.skipAssembly", "true"); + properties.setProperty("shade.skip", "true"); + properties.setProperty("maven.war.skip", "true"); + properties.setProperty("maven.rar.skip", "true"); + properties.setProperty("changelog.skip", "true"); + properties.setProperty("checkstyle.skip", "true"); + properties.setProperty("maven.doap.skip", "true"); + properties.setProperty("maven.javadoc.skip", "true"); + properties.setProperty("maven.jxr.skip", "true"); + properties.setProperty("linkcheck.skip", "true"); + properties.setProperty("pmd.skip", "true"); + properties.setProperty("mpir.skip", "true"); + properties.setProperty("gpg.skip", "true"); + properties.setProperty("jdepend.skip", "true"); + + String javacLocation = "%s%sbin%sjavac".formatted(JavaHome, File.separator, File.separator); + pomGoals.add("-Dmaven.compiler.fork=true"); + if (Files.exists(Path.of(javacLocation))) { + pomGoals.add("-Dmaven.compiler.executable=%s".formatted(javacLocation)); + } + + InvocationRequest request = new DefaultInvocationRequest(); + + Integer timeout = 30 * 60; // 30 minutes in seconds + + request.setShellEnvironmentInherited(false); + request.setPomFile(pomFile); + request.setGoals(pomGoals); + request.setProperties(properties); + request.setAlsoMake(true); + request.setBatchMode(true); + request.setTimeoutInSeconds(timeout); + + request.setJavaHome(new File(JavaHome)); + request.setBaseDirectory(projectDirectory); + request.setInputStream(InputStream.nullInputStream()); + if (invocationOutputHandler != null) { + request.setOutputHandler(invocationOutputHandler); + request.setErrorHandler(invocationOutputHandler); + } + + if (userSettingsFilePath != null && !userSettingsFilePath.isEmpty() && !userSettingsFilePath.isBlank()) { + Path pa = Path.of(userSettingsFilePath); + if (Files.exists(pa) && Files.isRegularFile(pa)) { + request.setUserSettingsFile(new File(userSettingsFilePath)); + } + } + + if (javaToolOptions != null && !javaToolOptions.isEmpty()) { + request.addShellEnvironment("JAVA_TOOL_OPTIONS", javaToolOptions); + } + + Main.logger.info("Building with pom=%s goals=%s properties=%s%n" + .formatted(pomFilePath, + pomGoals, + properties)); + + try { + Invoker invoker = new DefaultInvoker(); + if (invokerLogger != null) { + invoker.setLogger(invokerLogger); + } + + invoker.setMavenHome(new File(System.getenv("MAVEN_HOME"))); + + InvocationResult result = invoker.execute(request); + + Main.logger.info("Building with pom={} goals={} properties={} returned {}", + pomFile, + pomGoals, + properties, + result.getExitCode()); + + return result.getExitCode(); + } catch (MavenInvocationException e) { + throw e; + } + } + + public static boolean runMavenGoalOnRepository(String repositoryDirectory, String goal, String userSettingsFilePath, + String javaVersion, Object logger, String javaToolOptions) throws MavenInvocationException { + Main.logger.info("ExecuteMavenGoalOnDuetsRepository Entry"); + String pomFilePath = "%s%spom.xml".formatted(repositoryDirectory, File.separator); + ArrayList goals = new ArrayList<>(); + goals.add(goal); + + if (javaVersion != null && !javaVersion.isBlank()) { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, javaVersion, logger, + javaToolOptions) == 0; + } else { + return runPomGoals(pomFilePath, goals, new ArrayList<>(), false, userSettingsFilePath, logger, + javaToolOptions) == 0; + } + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/TestAssertedLogger.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/TestAssertedLogger.java new file mode 100644 index 00000000..fc5921a6 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/runners/maven/TestAssertedLogger.java @@ -0,0 +1,192 @@ +package com.github.gilesi.illicocoverage.runners.maven; + +import org.apache.maven.shared.invoker.InvocationOutputHandler; +import org.apache.maven.shared.invoker.InvokerLogger; + +import java.io.IOException; + +public class TestAssertedLogger implements InvokerLogger, InvocationOutputHandler { + + private InvokerLogger invokerLogger = null; + private InvocationOutputHandler invocationOutputHandler = null; + private boolean testFailed = false; + + public TestAssertedLogger(Object logger) { + if (logger instanceof InvokerLogger tmp) { + invokerLogger = tmp; + } + + if (logger instanceof InvocationOutputHandler tmp) { + invocationOutputHandler = tmp; + } + } + + + public void debug(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message); + } + } + + public void debug(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.debug(message, throwable); + } + } + + public boolean isDebugEnabled() { + if (invokerLogger != null) { + return invokerLogger.isDebugEnabled(); + } + + return false; + } + + public void info(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message); + } + } + + public void info(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.info(message, throwable); + } + } + + public boolean isInfoEnabled() { + if (invokerLogger != null) { + return invokerLogger.isInfoEnabled(); + } + + return false; + } + + public void warn(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message); + } + } + + public void warn(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.warn(message, throwable); + } + } + + public boolean isWarnEnabled() { + if (invokerLogger != null) { + return invokerLogger.isWarnEnabled(); + } + + return false; + } + + public void error(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message); + } + } + + public void error(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.error(message, throwable); + } + } + + public boolean isErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isErrorEnabled(); + } + + return false; + } + + public void fatalError(String message) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message); + } + } + + public void fatalError(String message, Throwable throwable) { + if (message.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invokerLogger != null) { + invokerLogger.fatalError(message, throwable); + } + } + + public boolean isFatalErrorEnabled() { + if (invokerLogger != null) { + return invokerLogger.isFatalErrorEnabled(); + } + + return false; + } + + public int getThreshold() { + if (invokerLogger != null) { + return invokerLogger.getThreshold(); + } + + return 0; + } + + public void setThreshold(int threshold) { + if (invokerLogger != null) { + invokerLogger.setThreshold(threshold); + } + } + + public void consumeLine(String line) throws IOException { + if (line.contains("<<< FAILURE!")) { + testFailed = true; + } + + if (invocationOutputHandler != null) { + invocationOutputHandler.consumeLine(line); + } + } + + public boolean HasTestFailed() { + return testFailed; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/ReportItem.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/ReportItem.java new file mode 100644 index 00000000..4479ddaf --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/ReportItem.java @@ -0,0 +1,65 @@ +package com.github.gilesi.illicocoverage.testing; + +import com.github.gilesi.illicocoverage.Constants; +import com.github.gilesi.illicocoverage.testing.models.Testcase; + +public class ReportItem { + public String Name; + public String Version; + private String TestName; + private String TestResult; + private String ErrorDetails; + + public ReportItem(String projectName, String projectCommit, Testcase testcase) { + this.TestName = "%s.%s".formatted(testcase.ClassName, testcase.Name); + this.TestResult = ((testcase.Error != null) || (testcase.Failure != null)) ? Constants.RED_TEST : Constants.GREEN_TEST; + this.ErrorDetails = (testcase.Error != null) ? testcase.Error.Message : ""; + this.Name = projectName; + this.Version = projectCommit; + } + + public String getName() { + return Name; + } + + public void setName(String name) { + Name = name; + } + + public String getVersion() { + return Version; + } + + public void setVersion(String version) { + Version = version; + } + + public String getTestName() { + return TestName; + } + + public void setTestName(String testName) { + TestName = testName; + } + + public String getTestResult() { + return TestResult; + } + + public void setTestResult(String testResult) { + TestResult = testResult; + } + + public String getErrorDetails() { + return ErrorDetails; + } + + public void setErrorDetails(String errorDetails) { + ErrorDetails = errorDetails; + } + + @Override + public String toString() { + return "\"%s\",\"%s\",\"%s\",\"%s\",\"%s\"".formatted(Name, Version, TestName, TestResult, ErrorDetails); + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/XmlParser.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/XmlParser.java new file mode 100644 index 00000000..c1bbc838 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/XmlParser.java @@ -0,0 +1,33 @@ +package com.github.gilesi.illicocoverage.testing; + +import com.fasterxml.jackson.databind.DeserializationFeature; +import com.fasterxml.jackson.dataformat.xml.XmlMapper; +import com.github.gilesi.illicocoverage.testing.models.Testsuite; +import com.github.gilesi.illicocoverage.testing.models.Testsuites; + +import java.io.File; +import java.io.IOException; + +public class XmlParser { + + private static final XmlMapper mapper = XmlMapper + .builder() + .defaultUseWrapper(false) + .configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false) + .build(); + + public static Testsuite deserializeTestsuite(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuite.class); + } + + public static Testsuites deserializeTestsuites(String XmlPath) throws IOException { + File fi = new File(XmlPath); + return mapper.readValue(fi, Testsuites.class); + } + + public static void serialize(String XmlPath, Object obj) throws IOException { + File fi = new File(XmlPath); + mapper.writeValue(fi, obj); + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/gradle/GradleHarness.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/gradle/GradleHarness.java new file mode 100644 index 00000000..ef1f16cb --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/gradle/GradleHarness.java @@ -0,0 +1,52 @@ +package com.github.gilesi.illicocoverage.testing.gradle; + +import com.github.gilesi.illicocoverage.FileUtils; +import com.github.gilesi.illicocoverage.Main; +import com.github.gilesi.illicocoverage.testing.ReportItem; +import com.github.gilesi.illicocoverage.testing.XmlParser; +import com.github.gilesi.illicocoverage.testing.models.Testcase; +import com.github.gilesi.illicocoverage.testing.models.Testsuite; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class GradleHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, + ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%stest-results%stest".formatted(targetLocation, File.separator, + File.separator); + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, + String buildGradleFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path buildGradleFilePath = Path.of(buildGradleFileLocation); + String targetLocation = "%s%sbuild".formatted(buildGradleFilePath.getParent().toAbsolutePath(), File.separator); + + if (Files.isDirectory(Path.of(targetLocation))) { + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + Main.logger.info(e); + } + } + + return reportItems; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Error.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Error.java new file mode 100644 index 00000000..acb8674f --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Error.java @@ -0,0 +1,17 @@ +package com.github.gilesi.illicocoverage.testing.models; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlCData; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlProperty; +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlText; + +public class Error { + @JacksonXmlProperty(isAttribute = true, localName = "message") + public String Message; + + @JacksonXmlProperty(isAttribute = true, localName = "type") + public String Type; + + @JacksonXmlText + @JacksonXmlCData + private String Data; +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Properties.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Properties.java new file mode 100644 index 00000000..e4aba116 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Properties.java @@ -0,0 +1,13 @@ +package com.github.gilesi.illicocoverage.testing.models; + +public class Properties { + private Property[] property; + + public Property[] getProperty() { + return property; + } + + public void setProperty(Property[] value) { + this.property = value; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Property.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Property.java new file mode 100644 index 00000000..ea9e1d4d --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Property.java @@ -0,0 +1,22 @@ +package com.github.gilesi.illicocoverage.testing.models; + +public class Property { + private String name; + private String value; + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getValue() { + return value; + } + + public void setValue(String value) { + this.value = value; + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testcase.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testcase.java new file mode 100644 index 00000000..f2128522 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testcase.java @@ -0,0 +1,23 @@ +package com.github.gilesi.illicocoverage.testing.models; + +import com.fasterxml.jackson.dataformat.xml.annotation.JacksonXmlElementWrapper; + +public class Testcase { + @JacksonXmlElementWrapper(localName = "error") + public com.github.gilesi.illicocoverage.testing.models.Error Error; + + @JacksonXmlElementWrapper(localName = "failure") + public Error Failure; + + @JacksonXmlElementWrapper(localName = "name") + public String Name; + + @JacksonXmlElementWrapper(localName = "classname") + public String ClassName; + + @JacksonXmlElementWrapper(localName = "time") + public String Time; + + @JacksonXmlElementWrapper(localName = "system-out") + public String SystemOut; +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuite.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuite.java new file mode 100644 index 00000000..d0c827de --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuite.java @@ -0,0 +1,103 @@ +package com.github.gilesi.illicocoverage.testing.models; + +public class Testsuite { + private Properties properties; + private Testcase[] testcase; + private String xmlnsXsi; + private String xsiNoNamespaceSchemaLocation; + private String version; + private String name; + private String time; + private String tests; + private String errors; + private String skipped; + private String failures; + + public Properties getProperties() { + return properties; + } + + public void setProperties(Properties value) { + this.properties = value; + } + + public Testcase[] getTestcase() { + return testcase; + } + + public void setTestcase(Testcase[] value) { + this.testcase = value; + } + + public String getXmlnsXsi() { + return xmlnsXsi; + } + + public void setXmlnsXsi(String value) { + this.xmlnsXsi = value; + } + + public String getXsiNoNamespaceSchemaLocation() { + return xsiNoNamespaceSchemaLocation; + } + + public void setXsiNoNamespaceSchemaLocation(String value) { + this.xsiNoNamespaceSchemaLocation = value; + } + + public String getVersion() { + return version; + } + + public void setVersion(String value) { + this.version = value; + } + + public String getName() { + return name; + } + + public void setName(String value) { + this.name = value; + } + + public String getTime() { + return time; + } + + public void setTime(String value) { + this.time = value; + } + + public String getTests() { + return tests; + } + + public void setTests(String value) { + this.tests = value; + } + + public String getErrors() { + return errors; + } + + public void setErrors(String value) { + this.errors = value; + } + + public String getSkipped() { + return skipped; + } + + public void setSkipped(String value) { + this.skipped = value; + } + + public String getFailures() { + return failures; + } + + public void setFailures(String value) { + this.failures = value; + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuites.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuites.java new file mode 100644 index 00000000..5ea98a69 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/models/Testsuites.java @@ -0,0 +1,13 @@ +package com.github.gilesi.illicocoverage.testing.models; + +public class Testsuites { + private Testsuite[] testsuites; + + public Testsuite[] getTestsuites() { + return testsuites; + } + + public void setTestsuites(Testsuite[] value) { + this.testsuites = value; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/surefire/SurefireHarness.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/surefire/SurefireHarness.java new file mode 100644 index 00000000..75572f86 --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/testing/surefire/SurefireHarness.java @@ -0,0 +1,49 @@ +package com.github.gilesi.illicocoverage.testing.surefire; + +import com.github.gilesi.illicocoverage.FileUtils; +import com.github.gilesi.illicocoverage.Main; +import com.github.gilesi.illicocoverage.testing.ReportItem; +import com.github.gilesi.illicocoverage.testing.models.Testcase; +import com.github.gilesi.illicocoverage.testing.models.Testsuite; +import com.github.gilesi.illicocoverage.testing.XmlParser; + +import java.io.File; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.util.ArrayList; + +public class SurefireHarness { + private static void buildReportXml(String projectName, String projectCommit, String targetLocation, ArrayList reportItems) throws IOException { + String sureFireReportsLocation = "%s%ssurefire-reports".formatted(targetLocation, File.separator); + ArrayList reportXmls = FileUtils.enumerateFiles(sureFireReportsLocation, ".*\\.xml", false); + + for (String xml : reportXmls) { + Testsuite testsuite = XmlParser.deserializeTestsuite(xml); + Testcase[] list = testsuite.getTestcase(); + if (list == null) { + continue; + } + for (Testcase testcase : list) { + reportItems.add(new ReportItem(projectName, projectCommit, testcase)); + } + } + } + + public static ArrayList getProjectTestReports(String projectPathFriendlyName, String commit, String pomFileLocation) { + ArrayList reportItems = new ArrayList<>(); + + Path pomFilePath = Path.of(pomFileLocation); + String targetLocation = "%s%starget".formatted(pomFilePath.getParent().toAbsolutePath(), File.separator); + + if (Files.isDirectory(Path.of(targetLocation))) { + try { + buildReportXml(projectPathFriendlyName, commit, targetLocation, reportItems); + } catch (Exception e) { + Main.logger.info(e); + } + } + + return reportItems; + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/ConfGenCoverage.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/ConfGenCoverage.java new file mode 100644 index 00000000..3d5172ef --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/ConfGenCoverage.java @@ -0,0 +1,23 @@ +package com.github.gilesi.illicocoverage.tools; + +import com.github.gilesi.illicocoverage.Constants; +import com.github.gilesi.illicocoverage.Main; +import com.github.gilesi.illicocoverage.ProcessUtils; + +import java.io.IOException; +import java.nio.file.Path; + +public class ConfGenCoverage { + public static void runConfGenCoverage(String GilesiRepositoryLocation, String libraryConfig, String outputTestProject, String libraryLocation) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx8g", + "-Xms8g", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.CONF_GEN_COVERAGE_LOCATION).toString(), + libraryConfig, + outputTestProject, + libraryLocation + }, null, Main.loggerConfGenCoverage); + } +} diff --git a/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/TestGen.java b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/TestGen.java new file mode 100644 index 00000000..4a544ecd --- /dev/null +++ b/IllicoCoverage/src/main/java/com/github/gilesi/illicocoverage/tools/TestGen.java @@ -0,0 +1,44 @@ +package com.github.gilesi.illicocoverage.tools; + +import com.github.gilesi.illicocoverage.Constants; +import com.github.gilesi.illicocoverage.Main; +import com.github.gilesi.illicocoverage.ProcessUtils; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +import java.io.IOException; +import java.nio.file.Path; + +public class TestGen { + public static final Logger logger = LogManager.getLogger(); + + public static void runTestGen(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory, String libraryConfig) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx8g", + "-Xms8g", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.TEST_GEN_LOCATION).toString(), + traceFile, + outputCodeDirectory, + libraryConfig + }, null, Main.loggerTraceGen); + } + + public static void runTraceDiff(String GilesiRepositoryLocation, String traceFile, String outputCodeDirectory, String libraryConfig) throws IOException, InterruptedException { + ProcessUtils.runExternalCommand(new String[]{ + Path.of(Constants.JAVA_21_BINARY_LOCATION, "bin", "java").toString(), + "-Xmx32768m", + "-Xms16384m", + "-Xss1024m", + "-XX:ParallelGCThreads=8", + "-XX:InitiatingHeapOccupancyPercent=70", + "-XX:+UnlockDiagnosticVMOptions", + "-jar", + Path.of(GilesiRepositoryLocation).resolve(Constants.TRACE_DIFF_LOCATION).toString(), + traceFile, + outputCodeDirectory, + libraryConfig + }, null, Main.loggerTraceDiff); + } +} \ No newline at end of file diff --git a/IllicoCoverage/src/main/resources/log4j2.xml b/IllicoCoverage/src/main/resources/log4j2.xml new file mode 100644 index 00000000..6ef0deaf --- /dev/null +++ b/IllicoCoverage/src/main/resources/log4j2.xml @@ -0,0 +1,82 @@ + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + %d{HH:mm:ss.SSS} %-5level %logger{36} - %msg%n + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/IllicoCoverageRun.sh b/IllicoCoverageRun.sh new file mode 100755 index 00000000..89f5a5ff --- /dev/null +++ b/IllicoCoverageRun.sh @@ -0,0 +1,16 @@ +#!/bin/bash + +# illicocoverage requires the use of other subprojects that must be precompiled before running, and pointed to it via the gilesi repo arg. +# first compile everything +sh ./compile.sh + +export MAVEN_HOME="/snap/intellij-idea-ultimate/current/plugins/maven/lib/maven3" + +# then run illicocoverage for sample usage +# this commands starts the experience on the compsuite dataset copied at "/home/gus/Datasets/compsuite3", and limits it to just the project id "i-3" +# note that the compsuite dataset folder layout is our own format, and omitting "i-3" will run the entire experience on every project. +java -Xms8g -Xmx8g -jar ./IllicoCoverage/build/libs/com.github.gilesi.illicocoverage.jar "/home/gus/Datasets/compsuite3/i-7/old" "org.slf4j:slf4j-api:1.7.9" "./illicocoverage-sample-results" "$PWD" "test -fn -Drat.ignoreErrors=true -DtrimStackTrace=false -DfailIfNoTests=false -Dtest=Slf4jLogFilterTest#test_slf4j" + +# list of configurable hardocded options scattered throughout the entire project: +# illicocoverage/src/main/java/com/github/gilesi/illicocoverage/Constants.java +# TestGenerator/src/main/java/com/github/gilesi/testgenerator/StaticConfiguration.java diff --git a/compile.sh b/compile.sh index cf02e391..6e3ee66b 100755 --- a/compile.sh +++ b/compile.sh @@ -67,3 +67,36 @@ echo cd Illico sh ./gradlew shadowJar --warning-mode all cd .. + +echo +echo =========================================================== +echo Building ConfGenCoverage +echo =========================================================== +echo + +# build confgencoverage +cd ConfGenCoverage +sh ./gradlew shadowJar --warning-mode all +cd .. + +echo +echo =========================================================== +echo Building Coverage +echo =========================================================== +echo + +# build coverage +cd Coverage +sh ./gradlew shadowJar --warning-mode all +cd .. + +echo +echo =========================================================== +echo Building IllicoCoverage +echo =========================================================== +echo + +# build illicocoverage +cd IllicoCoverage +sh ./gradlew shadowJar --warning-mode all +cd .. From 535c1f9922f883aa2d2eed46c332c178832d410e Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Thu, 28 Nov 2024 18:36:20 +0000 Subject: [PATCH 244/244] Bump com.fasterxml.jackson:jackson-base in /CompSuiteHarness Bumps [com.fasterxml.jackson:jackson-base](https://github.com/FasterXML/jackson-bom) from 2.18.1 to 2.18.2. - [Commits](https://github.com/FasterXML/jackson-bom/compare/jackson-bom-2.18.1...jackson-bom-2.18.2) --- updated-dependencies: - dependency-name: com.fasterxml.jackson:jackson-base dependency-type: direct:production update-type: version-update:semver-patch ... Signed-off-by: dependabot[bot] --- CompSuiteHarness/build.gradle | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/CompSuiteHarness/build.gradle b/CompSuiteHarness/build.gradle index 6c2c8439..d6a196bb 100644 --- a/CompSuiteHarness/build.gradle +++ b/CompSuiteHarness/build.gradle @@ -28,7 +28,7 @@ dependencies { implementation 'com.fasterxml.jackson.dataformat:jackson-dataformat-xml:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-databind:2.18.1' implementation 'com.fasterxml.jackson.core:jackson-annotations:2.18.1' - implementation 'com.fasterxml.jackson:jackson-base:2.18.1' + implementation 'com.fasterxml.jackson:jackson-base:2.18.2' implementation 'org.apache.maven:maven-core:3.9.9' implementation 'org.apache.maven.shared:maven-invoker:3.3.0' testImplementation platform('org.junit:junit-bom:5.11.3')