-
Notifications
You must be signed in to change notification settings - Fork 11
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
IT file changes- TestFramework.scala, Runner.scala, RunnerFactory.java #41
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,6 +13,7 @@ import java.util.List; | |
import scala.collection.JavaConverters._ | ||
import scala.collection.mutable.ListBuffer | ||
import scala.util.Try | ||
import java.util.logging.{Level, Logger} | ||
|
||
object TestFramework { | ||
def testFramework(project: ProjectWrapper): Option[TestFramework] = { | ||
|
@@ -106,98 +107,145 @@ trait TestFramework { | |
} | ||
|
||
object JUnit extends TestFramework { | ||
val methodAnnotationStr: String = "org.junit.Test" | ||
val methodAnnotationStr: String = "org.junit.Test" | ||
|
||
override def tryGenerateTestClass(loader: ClassLoader, clzName: String): Option[GeneralTestClass] = { | ||
|
||
override def tryGenerateTestClass(loader: ClassLoader, clzName: String) | ||
: Option[GeneralTestClass] = { | ||
val annotation: Class[_ <: Annotation] = | ||
val annotation: Class[_ <: Annotation] = | ||
loader.loadClass(methodAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
|
||
try { | ||
|
||
val clz = loader.loadClass(clzName) | ||
|
||
Logger.getGlobal().log(Level.INFO, s"Loaded class: $clzName") | ||
|
||
if (!Modifier.isAbstract(clz.getModifiers)) { | ||
|
||
val methods = clz.getMethods.toStream | ||
|
||
Try(if (methods.exists(_.getAnnotation(annotation) != null)) { | ||
// Check if it is an integration test by name or directory | ||
|
||
val isIntegrationTestByName = clzName.endsWith("IT") | ||
val classFilePath = clz.getProtectionDomain.getCodeSource.getLocation.getPath | ||
val isIntegrationTestByDirectory = classFilePath.contains("/target/test-classes/") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Are there other places in testrunner that hard codes paths? Looking specifically in /target/test-classes/ may be best to be hard coded with other paths in testrunner |
||
|
||
Logger.getGlobal().log(Level.INFO, s"Class $clzName integration test by name: $isIntegrationTestByName") | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Instead of adding debug messages to INFO logging, please change the level to DEBUG or something equivalent. |
||
Logger.getGlobal().log(Level.INFO, s"Class $clzName integration test by directory: $isIntegrationTestByDirectory") | ||
|
||
Try(if (methods.exists(_.getAnnotation(annotation) != null) || | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Should Try be try? |
||
(isIntegrationTestByName && isIntegrationTestByDirectory)) { | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName recognized as a test class.") | ||
Option(new JUnitTestClass(loader, clz)) | ||
} else if (loader.loadClass("junit.framework.TestCase").isAssignableFrom(clz)) { | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName recognized as a TestCase class.") | ||
Option(new JUnitTestCaseClass(loader, clz)) | ||
} else { | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName is not a test class, skipping.") | ||
Option.empty | ||
}).toOption.flatten | ||
|
||
} else { | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName is abstract, skipping.") | ||
Option.empty | ||
|
||
} | ||
|
||
} catch { | ||
case e: NoClassDefFoundError => Option.empty | ||
|
||
case e: NoClassDefFoundError => | ||
Logger.getGlobal().log(Level.WARNING, s"Class $clzName could not be loaded due to NoClassDefFoundError.") | ||
Option.empty | ||
|
||
} | ||
|
||
} | ||
|
||
override def toString(): String = "JUnit" | ||
|
||
// the splitor to split the class name and method name | ||
// for the full qualified name of JUnit 4 test | ||
// the delimiter to split the class name and method name | ||
// for the fully qualified name of JUnit 4 test | ||
// like com.package.JUnit4TestClass.TestA | ||
override def getDelimiter(): String = "." | ||
|
||
} | ||
|
||
object JUnit5 extends TestFramework { | ||
|
||
val methodAnnotationStr: String = "org.junit.jupiter.api.Test" | ||
val nestedAnnotationStr: String = "org.junit.jupiter.api.Nested" | ||
val disabledAnnotationStr: String = "org.junit.jupiter.api.Disabled" | ||
|
||
override def tryGenerateTestClass(loader: ClassLoader, clzName: String) | ||
: Option[GeneralTestClass] = { | ||
val testAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(methodAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
|
||
val disabledAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(disabledAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
override def tryGenerateTestClass(loader: ClassLoader, clzName: String): Option[GeneralTestClass] = { | ||
|
||
try { | ||
val clz = loader.loadClass(clzName) | ||
val testAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(methodAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
|
||
val disabledAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(disabledAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
|
||
|
||
try { | ||
|
||
val clz = loader.loadClass(clzName) | ||
Logger.getGlobal().log(Level.INFO, s"Loaded class: $clzName") | ||
|
||
if (clz.getAnnotation(disabledAnnotation) != null) { | ||
// Skip disabled class | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName is disabled, skipping.") | ||
return Option.empty | ||
|
||
} | ||
|
||
if (clz.getAnnotation(disabledAnnotation) != null) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. should this be removed? |
||
// skip disabled class | ||
if (clz.isMemberClass) { | ||
val nestedAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(nestedAnnotationStr).asInstanceOf[Class[_ <: Annotation]] | ||
|
||
if (Modifier.isStatic(clz.getModifiers) || | ||
clz.getAnnotation(nestedAnnotation) == null) { | ||
// Skip unqualified nested test class | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName is an unqualified nested test class, skipping.") | ||
return Option.empty | ||
} | ||
|
||
if (clz.isMemberClass) { | ||
val nestedAnnotation: Class[_ <: Annotation] = | ||
loader.loadClass(nestedAnnotationStr) | ||
.asInstanceOf[Class[_ <: Annotation]] | ||
if (Modifier.isStatic(clz.getModifiers) || | ||
clz.getAnnotation(nestedAnnotation) == null) { | ||
// a nested test class should | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. We should keep these comments |
||
// (1) be non-static | ||
// (2) have @Nested annotation | ||
// | ||
// Skip unqualified test class | ||
return Option.empty | ||
} | ||
} | ||
} | ||
|
||
if (!Modifier.isAbstract(clz.getModifiers)) { | ||
val methods = Utility.getAllMethods(clz) | ||
// Check if it is an integration test by name or directory | ||
|
||
val isIntegrationTestByName = clzName.endsWith("IT") | ||
val classFilePath = clz.getProtectionDomain.getCodeSource.getLocation.getPath | ||
val isIntegrationTestByDirectory = classFilePath.contains("/target/test-classes/") | ||
|
||
Logger.getGlobal().log(Level.INFO, s"Class $clzName integration test by name: $isIntegrationTestByName") | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName integration test by directory: $isIntegrationTestByDirectory") | ||
|
||
|
||
if (!Modifier.isAbstract(clz.getModifiers) && | ||
|
||
(clz.getDeclaredMethods.exists(_.getAnnotation(testAnnotation) != null) || (isIntegrationTestByName && isIntegrationTestByDirectory))) { | ||
Logger.getGlobal().log(Level.INFO, s"Class $clzName recognized as a test class.") | ||
Option(new JUnit5TestClass(loader, clz)) | ||
|
||
} else { | ||
|
||
Logger.getGlobal().log(Level.INFO, s"Class $clzName is not a test class, skipping.") | ||
Option.empty | ||
|
||
Try(if (methods.exists(_.getAnnotation(testAnnotation) != null)) { | ||
Option(new JUnit5TestClass(loader, clz)) | ||
} else { | ||
Option.empty | ||
}).toOption.flatten | ||
} else { | ||
Option.empty | ||
} | ||
} catch { | ||
case e: NoClassDefFoundError => Option.empty | ||
} | ||
} | ||
|
||
override def toString(): String = "JUnit5" | ||
} catch { | ||
|
||
case e: NoClassDefFoundError => | ||
Logger.getGlobal().log(Level.WARNING, s"Class $clzName could not be loaded due to NoClassDefFoundError.") | ||
Option.empty | ||
|
||
} | ||
|
||
} | ||
override def toString(): String = "JUnit5" | ||
|
||
// the splitor to split the class name and method name | ||
// for the full qualified name of JUnit 5 test | ||
// like com.package.JUnit5TestClass#TestA | ||
override def getDelimiter(): String = "#" | ||
} | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -16,6 +16,8 @@ import scala.collection.mutable.ListBuffer | |
import scala.io.Source | ||
import scala.util.{Failure, Try} | ||
|
||
import java.util.logging.{Level, Logger} | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Wrong line. put inbetween line 4-5 |
||
|
||
trait Runner { | ||
def outputPath(): Path | ||
def classpath(): String | ||
|
@@ -56,36 +58,56 @@ trait Runner { | |
|
||
def generateTestRunId(): String = System.currentTimeMillis() + "-" + UUID.randomUUID.toString | ||
|
||
def runWithCp(cp: String, testOrder: Stream[String]): Try[TestRunResult] = | ||
TempFiles.withSeq(testOrder)(path => | ||
TempFiles.withTempFile(outputPath => | ||
TempFiles.withProperties(Configuration.config().properties())(propertiesPath => { | ||
val builder = makeBuilder(cp + File.pathSeparator + Configuration.config().getProperty("testplugin.classpath")) | ||
|
||
val info = execution(testOrder, builder) | ||
|
||
val testRunId = generateTestRunId() | ||
|
||
val exitCode = info.run( | ||
testRunId, | ||
framework().toString, | ||
path.toAbsolutePath.toString, | ||
propertiesPath.toAbsolutePath.toString, | ||
outputPath.toAbsolutePath.toString).exitValue() | ||
|
||
if (exitCode == 0) { | ||
autoClose(Source.fromFile(outputPath.toAbsolutePath.toString).bufferedReader())(reader => | ||
Try(new Gson().fromJson(reader, classOf[TestRunResult]))) | ||
} else { | ||
// Try to copy the output log so that it can be inspected | ||
val failureLog = Paths.get("failing-test-output-" + testRunId) | ||
Files.copy(info.outputPath, failureLog, StandardCopyOption.REPLACE_EXISTING) | ||
Failure(new Exception("Non-zero exit code (output in " + failureLog.toAbsolutePath + "): " ++ exitCode.toString)) | ||
} | ||
}))).flatten.flatten.flatten.flatten | ||
val logger = Logger.getLogger(getClass.getName) | ||
|
||
def runWithCp(cp: String, testOrder: Stream[String]): Try[TestRunResult] = { | ||
logger.log(Level.INFO, "runWithCp method is being executed") | ||
|
||
|
||
TempFiles.withSeq(testOrder)(path => { | ||
println(s"Temporary path created: $path") // Print after creating the sequence of test paths | ||
|
||
TempFiles.withTempFile(outputPath => { | ||
println(s"Temporary output path created: $outputPath") // Print after creating the temporary output file | ||
|
||
TempFiles.withProperties(Configuration.config().properties())(propertiesPath => { | ||
println(s"Properties path created: $propertiesPath") // Print after creating the properties path | ||
|
||
val builder = makeBuilder(cp + File.pathSeparator + Configuration.config().getProperty("testplugin.classpath")) | ||
|
||
val info = execution(testOrder, builder) | ||
|
||
val testRunId = generateTestRunId() | ||
println(s"Generated testRunId: $testRunId") // Print the generated testRunId | ||
|
||
val exitCode = info.run( | ||
testRunId, | ||
framework().toString, | ||
path.toAbsolutePath.toString, | ||
propertiesPath.toAbsolutePath.toString, | ||
outputPath.toAbsolutePath.toString).exitValue() | ||
|
||
println(s"Execution finished with exit code: $exitCode") // Print the exit code | ||
|
||
if (exitCode == 0) { | ||
autoClose(Source.fromFile(outputPath.toAbsolutePath.toString).bufferedReader())(reader => | ||
Try(new Gson().fromJson(reader, classOf[TestRunResult]))) | ||
} else { | ||
// Try to copy the output log so that it can be inspected | ||
val failureLog = Paths.get("failing-test-output-" + testRunId) | ||
Files.copy(info.outputPath, failureLog, StandardCopyOption.REPLACE_EXISTING) | ||
println(s"Non-zero exit code. Output copied to: $failureLog") // Print the failure log location | ||
Failure(new Exception("Non-zero exit code (output in " + failureLog.toAbsolutePath + "): " ++ exitCode.toString)) | ||
} | ||
}) | ||
}) | ||
}).flatten.flatten.flatten.flatten | ||
} | ||
} | ||
|
||
|
||
trait RunnerProvider[A <: Runner] { | ||
def withFramework(framework: TestFramework, classpath: String, | ||
environment: java.util.Map[String, String], outputPath: Path): A | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Remove most empty lines please