GithubHelp home page GithubHelp logo

sourcegrade / jagr Goto Github PK

View Code? Open in Web Editor NEW
26.0 0.0 3.0 19.41 MB

Java AutoGrader, Implemented in Kotlin

Home Page: https://docs.sourcegrade.org/jagr/

License: GNU Affero General Public License v3.0

Kotlin 85.35% Java 14.65%
grading java kotlin

jagr's People

Contributors

alexstaeding avatar dst97 avatar hapstyx avatar jan1na avatar janbormet avatar juliushardt avatar lukasklenner avatar rdeisenroth avatar renovate[bot] avatar w-lfchen avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

jagr's Issues

Fix hardcoded assignment prefix "h..."

The current MoodleUnpack file has a hardcoded format for the assignment id that begins with "h":

// TODO: Fix this hack
val assignmentId = assignmentIdRegex.matchEntire(candidate.name)
?.run { groups["assignmentId"]?.value }
?.padStart(length = 2, padChar = '0')
?.let { "h$it" }

Fix this so that other assignment id formats may be used (and may not necessarily be numbers)

Re-add compatibility with < v0.6 graders during migration

Jagr v0.6 will break compatibility for graders. Specifically, the grader-info.json file format is different: the list property assignmentIds is now just a single assignmentId.

This change was introduced in #101 because graders only apply to a single assignment in practice. Unfortunately, this means all previously created graders will not work with Jagr v0.6 onwards.

Deliverables

  • Add some way of using old graders with Jagr >= v0.6

Use JavaExec instead of DefaultTask for Gradle Task grader{Private,Public}Run

Currently, class GraderRunTask is using DefaultTask as basic class.

In IntelliJ, when a DefaultTask is started, gradle uses resources from the IDE. Especially, gradle does not create a new process. It is very likely that this behavior results in the following issues:

  • On the one side, the process running the gradle task terminates only when the IDE is terminates. This might be the reason for overflowing heap space which is an known issue.
  • On the other side, the process of the IDE does not allow to create java agents at runtime. This can be explicitly allowed for JavaExec gradle tasks.

Using JavaExec instead of DefaultTask might solve these issues.

Rework CLI

Most settings are currently provided via the jagr.conf file, which is fine in some simple usecases. However, in preparation for the move to containerization, this system needs to be reworked. Specifically:

  • All settings should be configurable via command-line flag/parameter
  • All (non-aesthetic) settings should be configurable via environment variable
  • Optional: Find a user-friendly way to optionally use a user-specific config

Additionally, Jagr currently always creates all directories as soon as it is run. This is sometimes unwanted (e.g. accidental execution) or unnecessary (e.g. no export - no export directory needed).

Add setting for java version used in process mode

Currently, when a child process is created, the child process is using the default java environemt (called by java). When tests require java agents, the use of the default java environment might not provide java agent support.

.command("java", "-Dlog4j.configurationFile=log4j2-child.xml", "-jar", jagrLocation, "--child")

Provide an option in the configuration file to set the java version or, if possible, use the java environment the program was called with.

Fix failed evaluation of tests with value source

It seems that a parameterized test always results in a failed evaluation ("Failed to evaluate test" in rubric). For example, the following test is valid and works with the IntelliJ JUnit test runner, but not with jagr.

@ParameterizedTest
@ValueSource(strings = {"BRASS", "COPPER", "SILVER"})
@DisplayName("2 | Existenz Enum CoinType")
public void test02(String name) {
    // no body required for failing test
}

Incorrect handling of duplicated files in related graders

If you have two graders where one grader depends on the other (e.q. private and public grader) in a setup like this:

graders {
        val graderPublic by creating {
            graderName.set("Public")
            rubricProviderName.set("RubricProvider-Public")
        }
        val graderPrivate by creating {
            parent(graderPublic)
            graderName.set("Private")
            rubricProviderName.set("RubricProvider-Private")
        }
    }

and two identically named files in both graders it seems to continue the grading process with the file in the child grader when executing the parent grader. If the public grader consists of the class

@TestForSubmission
public class ExampleTest {
    @Test
    public void test() {
        fail();
    }
}

the private grader of the class

@TestForSubmission
public class ExampleTest {
    @Test
    public void test() {
    }
}

and both Rubrics being

Rubric.builder()
        .title("Example")
        .addChildCriteria(Criterion.builder()
            .shortDescription("test")
            .grader(Grader.testAwareBuilder()
                .requirePass(JUnitTestRef.ofMethod(() -> ExampleTest.class.getDeclaredMethod("test")))
                .pointsPassedMax()
                .build())
            .build())
        .build()

You would expect the public grader to fail and the private grader to pass because the private grader, being the parent of the public grader, should overwrite the failing ExampleTest class of the public grader with its version of the class (which doesn't fail). But the actual behavior is that both graders fail. Renaming the ExampleTest class of the private grader leads to the expected behavior.

It seems like this bug was introduced with version 0.9.0.

Come up with a better grader inheritance concept

The primary use case for multiple graders in a project is the split between public/private graders. Because inherited graders are combined with duplicate resolution always favoring the "base" grader (i.e. private grader), combining existing test classes or rubrics in the public grader with ones in the private grader is cumbersome.

The current options are:

  1. Copy the entire class into the base grader with modifications. Rely on duplicate file exclusion to favor the class in the private grader.
  2. Extract the the logic of the class and reference it. Similar to 1. but the duplicate code is just method calls to the actual logic which is extracted.

Find a better solution to this problem.

Show unexpected exceptions (other than AssertionError etc.) in console

Currently, any exception in a unit test results in the test failing and the exercise marked as wrong for the student.

However, there could also be an error in the test itself, rather than the student being wrong. This is currently hidden from the console, the exception is only visible when manually reviewing the rubrics. Errors in the tests might never be detected this way.

Therefore, when a test throws something different from an AssertionError, AssertionFailedException etc., this should be clearly visible when executing the grader.
Failed tests caused by AssertionErrors etc. can be ignored, but any other Exception (e.g. NullPointerException) that occurs in a test should be visible in red in the console, so the tutor can review the tests and correct the error.

jagr-gradle grading output

Currently, the only feedback available from the grading process via jagr-gradle is the total points for a submission. Provide a nice way of showing the results of individual tests and/or criteria.

Fix submission info failure condition with gradle >= 7.6

Gradle 7.6 introduced a change that affects the way the errors are presented for SubmissionWriteInfoTask. The names of the missing properties are no longer shown:

Old:

Could not evaluate onlyIf predicate for task ':mainWriteSubmissionInfo'.
> 
  There were some errors preparing your submission, please check your Gradle buildscript (e.g. build.gradle.kts).
  The following required properties were not set:
  studentId
  firstName
  lastName

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

Now:

Could not evaluate onlyIf predicate for task ':mainWriteSubmissionInfo'.
> Could not evaluate spec for 'Task satisfies onlyIf spec'.

* Try:
> Run with --stacktrace option to get the stack trace.
> Run with --info or --debug option to get more log output.
> Run with --scan to get full insights.

graderPrivateRun won't execute the code from graderPrivate

Running graderPrivateRun will execute the code of RubricProvider class from graderPublic instead of graderPrivate if a RubricProvider exists in graderPrivate and graderPublic.

Expected behavior:

Run the RubricProvider code from graderPrivate.

Actual behavior:

The RubricProvider code from graderPublic will be executed instead.

writeUTF for Strings exceeding length 65535 doesn't work

A class with a length greater than 65535 (2^16) triggers the following exception:

Exception in thread "pool-3-thread-1" java.lang.AssertionError: java.io.UTFDataFormatException: encoded string (package ...    }
}
) too long: 66717 bytes
	at com.google.common.io.ByteStreams$ByteArrayDataOutputStream.writeUTF(ByteStreams.java:630)
	at org.sourcegrade.jagr.core.compiler.java.JavaSourceFile$Factory.write(JavaSourceFile.kt:46)
	at org.sourcegrade.jagr.core.compiler.java.JavaSourceFile$Factory.write(JavaSourceFile.kt:39)
	at org.sourcegrade.jagr.launcher.io.MapSerializerFactory.write(SerializerFactory.kt:207)
...

This is because the writeUTF method of java.io.DataOutputStream writes 2 bytes length information, which limits the length of serialized strings to 2^16 bytes.

Dependency Dashboard

This issue lists Renovate updates and detected dependencies. Read the Dependency Dashboard docs to learn more.


Warning

Renovate failed to look up the following dependencies: Failed to look up maven package org.jetbrains.teamcity:configs-dsl-kotlin-parent, Failed to look up maven package org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest.

Files affected: .teamcity/pom.xml


Open

These updates have all been created already. Click a checkbox below to force a retry/rebase of any.

Detected dependencies

github-actions
.github/workflows/publish-docs.yml
  • actions/checkout v4
  • mhausenblas/mkdocs-deploy-gh-pages 1.26
gradle
buildSrc/src/main/kotlin/org/sourcegrade/jagr/script/DependencyConfigurationExtensions.kt
settings.gradle.kts
build.gradle.kts
build-logic/settings.gradle.kts
build-logic/build.gradle.kts
build-logic/src/main/kotlin/jagr-publish.gradle.kts
build-logic/src/main/kotlin/jagr-sign.gradle.kts
buildSrc/build.gradle.kts
core/build.gradle.kts
grader-api/build.gradle.kts
gradle/libs.versions.toml
  • org.jetbrains:annotations 24.1.0
  • org.apiguardian:apiguardian-api 1.1.2
  • org.ow2.asm:asm 9.7
  • org.ow2.asm:asm-util 9.7
  • com.github.ajalt.clikt:clikt 4.4.0
  • org.spongepowered:configurate-extra-kotlin 4.1.2
  • org.spongepowered:configurate-hocon 4.1.2
  • org.jetbrains.kotlinx:kotlinx-coroutines-core 1.8.1
  • org.apache.commons:commons-csv 1.11.0
  • com.google.inject:guice 5.1.0
  • org.fusesource.jansi:jansi 2.4.1
  • org.junit.jupiter:junit-jupiter 5.10.2
  • org.junit.jupiter:junit-jupiter-engine 5.10.2
  • org.junit.platform:junit-platform-launcher 1.10.2
  • com.github.albfernandez:juniversalchardet 2.4.0
  • org.apache.logging.log4j:log4j-api 2.23.1
  • org.apache.logging.log4j:log4j-core 2.23.1
  • org.jetbrains.kotlinx:kotlinx-serialization-json 1.6.3
  • de.undercouch.download 5.6.0
  • com.gradle.plugin-publish 1.2.1
  • org.jetbrains.kotlin.jvm 2.0.0
  • org.jetbrains.kotlin.kapt 2.0.0
  • org.jetbrains.kotlin.plugin.serialization 2.0.0
  • com.github.johnrengelman.shadow 8.1.1
  • org.sourcegrade.style 3.0.0
launcher/build.gradle.kts
launcher/gradle-plugin/build.gradle.kts
gradle-wrapper
gradle/wrapper/gradle-wrapper.properties
  • gradle 8.7
maven
.teamcity/pom.xml
  • org.jetbrains.teamcity:configs-dsl-kotlin-parent 1.0-SNAPSHOT
  • org.jetbrains.teamcity:configs-dsl-kotlin-plugins-latest 1.0-SNAPSHOT

  • Check this box to trigger a request for Renovate to run again on this repository

Debugging in gradle-Task no longer working

This issue aims to document the reasons for why debugging does no longer work and does not expect a fix soon

Since v0.8.0 or more precisely since #201, debugging using the graderPublicRun or graderPrivateRun tasks is no longer possible.

why?

In order to address #83 and some other issues such as memory leaks and only partial Mockito-Support, jagr decided to replace the gradle-specific executor mode with the process-mode which downloads the fat-jar and uses this to run all the tests. While this archieves the goal of fully supporting mockito (and especially mockStatic), it renders the gradle debugger useless for now.

how to fix?

In order to fix this issue, a whole new execution mode using java-exec would be necessary, which is currently not planned.

what to do instead?

Since popular mocking frameworks are now fully supported, the test-creators can and should ensure regular Junit-compatibility as much as possible which will enable granular per-test debugging and should now work mostly the same within jagr. If tests are only compatible with full jagr runs, they should be marked as such.

TL;DR

Test development is now easier than ever, but debugging should be done in Junit for now.

Match graders with regex

Currently graders can only match a single Submission. It should be possible for a grader to match multiple submissions with a regex.

Support ignored files for BuildSubmission

It should be possible to mark certain large files (e.g. images) to not be exported when building a submission with jagr-gradle.

This is to prevent unnecessary load on platforms such as moodle.

Containerization support

Provide a containerized release (potentially with docker compose for more complicated configurations)

Libraries not correctly resolving when working with multi-module projects

When working with multi-module projects and one module declares the java-library plugin the grader will fail with the attached stack trace.
This is caused by the GraderRunTask trying to add the module as a library when the module is declared as a dependencies by another module. Because the module is build as a directory containing .class files the creation of the resource Container, which expects .jar files, fails.

Caused by: java.lang.IllegalArgumentException: Could not an appropriate resource container for C:\Users\klenn\Documents\git\FOP-2223-Projekt-Student\domain\build\classes\java\main
	at org.sourcegrade.jagr.launcher.io.ResourceContainerKt.createResourceContainer(ResourceContainer.kt:80)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask$grade$batch$1.invoke(GraderRunTask.kt:152)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask$grade$batch$1.invoke(GraderRunTask.kt:93)
	at org.sourcegrade.jagr.launcher.io.GradingBatchKt.buildGradingBatch(GradingBatch.kt:55)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask.grade(GraderRunTask.kt:93)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask.access$grade(GraderRunTask.kt:48)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask$runTask$1.invokeSuspend(GraderRunTask.kt:82)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
	at kotlinx.coroutines.EventLoopImplBase.processNextEvent(EventLoop.common.kt:284)
	at kotlinx.coroutines.BlockingCoroutine.joinBlocking(Builders.kt:85)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking(Builders.kt:59)
	at kotlinx.coroutines.BuildersKt.runBlocking(Unknown Source)
	at kotlinx.coroutines.BuildersKt__BuildersKt.runBlocking$default(Builders.kt:38)
	at kotlinx.coroutines.BuildersKt.runBlocking$default(Unknown Source)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask.runTask(GraderRunTask.kt:81)
	at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    ...

This behavior can be reproduced in the repo https://github.com/FOP-2223/FOP-2223-Projekt-Student by adding

plugins {
    `java-library`
}

to the build.gradle.kts file of the domain subproject.

Do not assume new TU-IDs in moodle regex

Currently, if a student has a TU-ID that does not fit the "[a-z]{2}[0-9]{2}[a-z]{4}" regex (defined in the config), and that student does not supply a studentId, no rubric for that student is created.
If the student supplies an incorrect studentId, a rubric is created, but it will be impossible to upload the student's moodle-json export.

Change this behavior, so that the student's id is automatically inferred either by extending the regex to handle all possible ids or by changing this alltogether.

Provide graders with access to solution code

It is currently impossible to directly access solution code in a grader. This may be sensible in a situation where a comparison between a submission and the solution is necessary.

A workaround is to duplicate solution code into the grader section of the grader jar, but this is not a good solution.

Deliverables:

  • Come up with a clean way of accessing solution classes, possibly via the RuntimeClassLoader

Child process logging not present in log files

The logging output from child processes is currently only visible in the console running the program. It is visible because each child process sends its standard out directly to the main process which in turn pipes it directly into the console.

Unfortunately, log4j does not intercept logging from the child process because it is sent directly via InputStream and not via logging method invocation in the main process. This means that the log files created by the main processes' appenders do not include the output from child processes.

Parameterized tests not evaluated correctly in grader

When using parameterized tests, the grader will give points when the test passes for the first parameter set. It is expected that the tests fails overall if any of the parameter sets makes the test fail. How to reproduce:

Test:

@ParameterizedTest
@CsvFileSource(resources = "/Test.csv", numLinesToSkip = 1)
public void test(boolean value) {
    assertEquals(true, value);
}

With CSV:

foo
true
false

The test will fail in IntelliJ
image

but it will pass in the grader:
image

The issue can be reproduced on this branch: https://github.com/FOP-2223/FOP-2223-H03-Root/tree/parameterizedBug

Task :jagrDownload Logger errors

When executing the new :jagrDownload task, the following errors appear in the log:

> Task :jagrDownload
Download https://github.com/sourcegrade/jagr/releases/download/v0.8.0/Jagr-0.8.0.jar
SLF4J: No SLF4J providers were found.
SLF4J: Defaulting to no-operation (NOP) logger implementation
SLF4J: See https://www.slf4j.org/codes.html#noProviders for further details.

[23-Jan.-31 13:41:16] [ERROR] - OpenJDK 64-Bit Server VM warning: Sharing is only supported for boot loader classes because bootstrap classpath has been appended

The intended functionality is still archieved but it is confusing some of the students even though it finishes the job.

Add support for additional languages

Jagr currently only supports Java submissions. To support additional languages, both support for the compiler and the runtime interface between JUnit and the language must be implemented.

Compiler

Jagr's Java compiler interface is located in the compiler.java package, with some language-independent functionality located in the base compiler package. Supporting a language like Kotlin shouldn't require too many changes other than adding support for it in a compiler.kotlin package.

However, support for languages like Racket or Python will most likely be more challenging. If a language does not have a java-based compiler, it will probably need to be bundled as a native executable in the jar. This poses additional problems for multi-platform execution. For this reason, it is likely that some additional language support has to be provided external to Jagr; through a plugin for example. A compiler abstraction in the launcher or a new plugin module would be necessary.

Testing-Language interop

Currently, all testing is done through JUnit. To support other languages, a form of interoperability is required to call the foreign code from Java. The two options here are

  1. To continue using JUnit as the primary testing environment, using methods in JUnit tests that invoke the foreign code
  2. Add a Grader that runs a foreign testing environment and sets points based on the results.

Deliverables

  • [] Add compiler abstraction (in API)
  • [] Add support for Kotlin compilation
  • [] Consider possible interoperability for JVM-foreign languages such as Racket and Python

Hide submission stdout and stderr

Hiding the standard out and err from submission code used to be handled by the ThreadAwarePrintStream.

This broke after the launcher module (#12) was introduced because of the new multi-process structure. It is no longer as simple as hiding output from specific threads, as child processes do not create extra threads specific for grading. The output from the main thread of the child process is important in sending the results back to the main process.

There needs to be a new way of differentiating the legitimate output (from the main thread) from the submission output that does not rely on the current thread.

Gradle plugin

Add a jagr-gradle plugin with the ability to grade easily via Gradle task.

Custom export buildscript support

The Gradle projects exported by the GradleSubmissionExporter currently use a hardcoded Gradle configuration defined by the following build.gradle.kts_.

This hardcoded configuration works most of the time. However, there are cases (such as custom dependencies), where it is necessary to modify the exported Gradle configuration. This should be supported by the API.

The missing functionality would most likely be appropriate in RubricConfiguration.

Improve submission exporter

Currently the export submission only copies the dependencies of the grader, but if using custom jagr settings (like disabling timeouts, or JVM Arguments) or gradle Plugins like JavaFX it does apply to the exported submissions.

Timeout while loading submissions

Example:

[22-May-14 20:36:34] [ERROR] - Timeout after 1000ms @ DefaultDispatcher-worker-2
java.lang.Exception
        at org.sourcegrade.jagr.core.executor.TimeoutHandler.getTimeoutLocation(TimeoutHandler.kt:91)
        at org.sourcegrade.jagr.core.executor.TimeoutHandler.checkTimeout(TimeoutHandler.kt:74)
        at h01.utils.BytecodeTransformations.getWriterFlags(BytecodeTransformations.java)
        at org.sourcegrade.jagr.core.transformer.TransformerApplierKt.transform(TransformerApplier.kt:91)
        at org.sourcegrade.jagr.core.transformer.TransformerApplierKt.transform(TransformerApplier.kt:85)
        at org.sourcegrade.jagr.core.transformer.MultiTransformerApplierImpl.transform(TransformerApplier.kt:59)
        at org.sourcegrade.jagr.core.transformer.TransformerApplierKt.createApplier$lambda-1(TransformerApplier.kt:79)
        at org.sourcegrade.jagr.core.transformer.TransformerApplierKt.plus$lambda-0(TransformerApplier.kt:40)
        at org.sourcegrade.jagr.core.executor.CompiledBatchFactoryImpl$compile$2.invokeSuspend(BatchCompilation.kt:155)
        at org.sourcegrade.jagr.core.executor.CompiledBatchFactoryImpl$compile$2.invoke(BatchCompilation.kt)
        at org.sourcegrade.jagr.core.executor.CompiledBatchFactoryImpl$compile$2.invoke(BatchCompilation.kt)
        at org.sourcegrade.jagr.core.ParallelKt$parallel$deferreds$1$1.invokeSuspend(Parallel.kt:73)
        at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
        at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:106)
        at kotlinx.coroutines.scheduling.CoroutineScheduler.runSafely(CoroutineScheduler.kt:570)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.executeTask(CoroutineScheduler.kt:749)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.runWorker(CoroutineScheduler.kt:677)
        at kotlinx.coroutines.scheduling.CoroutineScheduler$Worker.run(CoroutineScheduler.kt:664)
[22-May-14 20:36:34] [ERROR] - submission null-h01-XXX-XXX-submission.jar has 0 warnings and 1 errors!
[22-May-14 20:36:34] [ERROR] - Transformation failed :: Timeout after 1000ms

Transformations during grading phase

Transformations are currently only easily applied very early - during the compilation phase. These transformations are applied globally and permanently.

Additionally, it is very difficult to transmit any state from this early transformation phase to the grading phase. This is due to the fact that the classes are completely redefined (from the original bytecode) for every submission. Any state saved traditionally (e.g. via static field) is lost.

Deliverables

  • Come up with a clean way of transforming classes during the grading phase

Optimize buffering for ResourceContainers

Currently, standard implementations of ResourceContainer such as ZipResourceContainer buffer the backing stream. This was a necessary safety precaution in the initial implementation of the launcher module (#12), as it is not initially clear how callers may use the stream. In the interest of time, this was the best solution.

As an example, this is the current state of ZipResourceContainer as of v0.2.1:
https://github.com/SourceGrade/Jagr/blob/30c517952cdcc53ce4f2c54ee6d6cc87a3d3a69e/launcher/src/main/kotlin/org/sourcegrade/jagr/launcher/io/ZipResourceContainer.kt#L57-L63

The result from the underlying ZipInputStream is buffered using ByteArrayResource:
https://github.com/SourceGrade/Jagr/blob/30c517952cdcc53ce4f2c54ee6d6cc87a3d3a69e/launcher/src/main/kotlin/org/sourcegrade/jagr/launcher/io/Resource.kt#L70-L73

Further compounding the issue, is the fact that zip.readBytes() creates its own buffer and then copies the array again to cut it to the correct size (IOStreams.kt in the Kotlin stdlib):

/**
 * Reads this stream completely into a byte array.
 *
 * **Note**: It is the caller's responsibility to close this stream.
 */
@SinceKotlin("1.3")
public fun InputStream.readBytes(): ByteArray {
    val buffer = ByteArrayOutputStream(maxOf(DEFAULT_BUFFER_SIZE, this.available()))
    copyTo(buffer)
    return buffer.toByteArray()
}

Why turn off buffering by default?

In cases where the original resource is directly transformed, it is not necessary to save the original state of the stream. While some buffering may be required for the transformation, that should be up to the transformer to implement. A "general" buffering strategy is not useful here and may significantly harm performance.,

A possible solution to this is to not buffer the standard implementations of ResourceContainer at all. Instead, for cases where a "general" buffer is required, provide a method similar to InputStream.buffered from the Kotlin stdlib (which returns a wrapped, buffered InpustStream) but applied to either ResourceContainer and/or Resource.

Deliverables

  • Remove all redundant array copies and stop buffering standard implementations of ResourceContainer by default
  • Provide an alternative method when buffering is needed
  • Document the effects of non-buffered resources

Logging in graders not working since v0.6.1

Since Jagr v0.6.1, logging in graders using the gradle plugin is not possible and fails with the following message:

[23-Jun-20 15:11:31] [INFO] - Starting Jagr v0.9.0
[23-Jun-20 15:11:35] [ERROR] - Grader grader has 0 warnings and 2 errors
[23-Jun-20 15:11:35] [ERROR] - /p3/graph/BasicGraphTests.java:3 ERROR :: cannot access org.apache.logging.log4j.Logger
  bad class file: org.apache.logging.log4j.core.Logger
    class file contains wrong class: org.apache.logging.log4j.core.Logger
    Please remove or make sure it appears in the correct subdirectory of the classpath.
[23-Jun-20 15:11:35] [ERROR] - /p3/graph/BasicGraphTests.java:43 ERROR :: cannot find symbol
  symbol:   class Logger
  location: class p3.graph.BasicGraphTests
[23-Jun-20 15:11:35] [ERROR] - Grader container grader failed to load
[23-Jun-20 15:11:35] [INFO] - Submission container submission loaded
[23-Jun-20 15:11:35] [INFO] - Executor mode 'gradle' :: expected submission: 1
[23-Jun-20 15:11:41] [WARN] - No rubrics!

An example statement to reproduce the bug would be Jagr.Default.getInjector().getInstance(Logger.class).warn("Hello world!");

graderPrivateRun is broken since 0.10.1

As the title suggests, the graderPrivateRun gradle-Task is broken since version 0.10.1. The job runs correctly but fails to create the rubric. Here is a full log of a graderPrivateRun of H01 FOP-2324:

7:49:49 PM: Executing 'graderPrivateRun'...

> Task :compileJava UP-TO-DATE
> Task :processResources UP-TO-DATE
> Task :classes UP-TO-DATE
> Task :compileTestJava UP-TO-DATE
> Task :processTestResources NO-SOURCE
> Task :testClasses UP-TO-DATE
> Task :compileGraderPrivateJava UP-TO-DATE
> Task :graderPrivateWriteGraderInfo
> Task :mainWriteSubmissionInfo

> Task :jagrDownload UP-TO-DATE
Download https://github.com/sourcegrade/jagr/releases/download/v0.10.1/Jagr-0.10.1.jar
[23-Nov-05 19:49:51] [INFO] - Grader H01-Private discovered rubric provider h01.H01_RubricProvider and 3 test classes
[23-Nov-05 19:49:51] [INFO] - Grader container grader loaded
[23-Nov-05 19:49:51] [INFO] - Submission container submission loaded

> Task :graderPrivateRun
[23-Nov-05 19:49:49] [INFO] - Starting Jagr v0.10.1
[23-Nov-05 19:49:51] [INFO] - Executor mode 'gradle' :: expected submission: 1

[23-Nov-05 19:49:51] [ERROR] - Picked up _JAVA_OPTIONS: -Dswing.aatext=TRUE -Dawt.useSystemAAFontSettings=on
[23-Nov-05 19:49:51] [ERROR] - WARNING: Runtime environment or build system does not support multi-release JARs. This will impact location-based features.
[23-Nov-05 19:49:53] [INFO] - Grader H01-Private discovered rubric provider h01.H01_RubricProvider and 3 test classes
[23-Nov-05 19:49:53] [INFO] - Running JUnit @ h01_ab12cdef_sol_last_sol_first :: [h01.CleaningRobotTest, h01.Contaminant2Test, h01.Contaminant1Test]
[23-Nov-05 19:51:01] [INFO] - h01_ab12cdef_sol_last_sol_first(submission) ::  (81/81 tests) minPoints=12/16 maxPoints=12/16 from 'H01 | Foreign Contaminants'
[23-Nov-05 19:51:01] [ERROR] - An error occurred receiving result for grading job
java.lang.IllegalStateException: Unable to create directory /home/ruben/git/FOP-2324/FOP-2324-H01-Root/build.gradle.kts/resources/jagr/graderPrivate/rubrics
	at org.sourcegrade.jagr.launcher.io.ResourceKt.writeIn(Resource.kt:45)
	at org.sourcegrade.jagr.launcher.io.ResourceKt.writeIn$default(Resource.kt:42)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask$grade$2.invoke(GraderRunTask.kt:109)
	at org.sourcegrade.jagr.gradle.task.grader.GraderRunTask$grade$2.invoke(GraderRunTask.kt:105)
	at org.sourcegrade.jagr.launcher.executor.RubricCollectorImpl$startDirect$1.invokeSuspend(RubricCollectorImpl.kt:100)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTaskKt.resume(DispatchedTask.kt:235)
	at kotlinx.coroutines.DispatchedTaskKt.resumeUnconfined(DispatchedTask.kt:191)
	at kotlinx.coroutines.DispatchedTaskKt.dispatch(DispatchedTask.kt:163)
	at kotlinx.coroutines.CancellableContinuationImpl.dispatchResume(CancellableContinuationImpl.kt:474)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl(CancellableContinuationImpl.kt:508)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeImpl$default(CancellableContinuationImpl.kt:497)
	at kotlinx.coroutines.CancellableContinuationImpl.resumeWith(CancellableContinuationImpl.kt:368)
	at kotlinx.coroutines.ResumeAwaitOnCompletion.invoke(JobSupport.kt:1406)
	at kotlinx.coroutines.JobSupport.notifyCompletion(JobSupport.kt:1497)
	at kotlinx.coroutines.JobSupport.completeStateFinalization(JobSupport.kt:325)
	at kotlinx.coroutines.JobSupport.finalizeFinishingState(JobSupport.kt:242)
	at kotlinx.coroutines.JobSupport.tryMakeCompletingSlowPath(JobSupport.kt:910)
	at kotlinx.coroutines.JobSupport.tryMakeCompleting(JobSupport.kt:867)
	at kotlinx.coroutines.JobSupport.makeCompleting$kotlinx_coroutines_core(JobSupport.kt:810)
	at kotlinx.coroutines.CompletableDeferredImpl.complete(CompletableDeferred.kt:90)
	at org.sourcegrade.jagr.launcher.executor.RuntimeGraderKt.gradeCatching(RuntimeGrader.kt:69)
	at org.sourcegrade.jagr.launcher.executor.ProcessWorker$assignJob$2.invokeSuspend(ProcessWorker.kt:72)
	at kotlin.coroutines.jvm.internal.BaseContinuationImpl.resumeWith(ContinuationImpl.kt:33)
	at kotlinx.coroutines.DispatchedTask.run(DispatchedTask.kt:108)
	at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1136)
	at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:635)
	at java.base/java.lang.Thread.run(Thread.java:833)

> Task :graderPrivateRun
[23-Nov-05 19:51:01] [INFO] - Result: Min: 12, Max: 16, Average: 12.0, Rubrics: 1
[23-Nov-05 19:51:01] [INFO] - Points:  12 Nr:   1 |-
[23-Nov-05 19:51:01] [WARN] - No rubrics!

Deprecated Gradle features were used in this build, making it incompatible with Gradle 9.0.

You can use '--warning-mode all' to show the individual deprecation warnings and determine if they come from your own scripts or plugins.

For more on this, please refer to https://docs.gradle.org/8.4/userguide/command_line_interface.html#sec:command_line_warnings in the Gradle documentation.

BUILD SUCCESSFUL in 1m 12s
8 actionable tasks: 3 executed, 5 up-to-date
7:51:01 PM: Execution finished 'graderPrivateRun'.

JUnitTestRef.ofClass not working as intended

JUnitTestRef.ofClass should extract all test methods of a class and apply an AND-function to them, so that the test ref evaluates to true, if and only if all tests in this class are successful.
At the moment it appears to do nothing.

Rename output from HTML rubric exporter

The HTML rubric exporter currently always exports with the filename result.html which makes it difficult to export normally during the standard grading process as every export will override the export from the previous submission.

Fix logging error in jagr-gradle startup

The following error occurs every time the jagr-plugin plugin is loaded. Logging to file must be disabled when executing from Gradle.

(Optionally add a nice way of choosing this via the launcher api)

2022-10-03 20:59:55,097 Daemon worker ERROR Cannot access RandomAccessFile java.io.FileNotFoundException: logs/latest.log (No such file or directory) java.io.FileNotFoundException: logs/latest.log (No such file or directory)
	at java.base/java.io.RandomAccessFile.open0(Native Method)
	at java.base/java.io.RandomAccessFile.open(RandomAccessFile.java:344)
	at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:259)
	at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:213)
	at java.base/java.io.RandomAccessFile.<init>(RandomAccessFile.java:127)
	at org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager$RollingRandomAccessFileManagerFactory.createManager(RollingRandomAccessFileManager.java:232)
	at org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager$RollingRandomAccessFileManagerFactory.createManager(RollingRandomAccessFileManager.java:204)
	at org.apache.logging.log4j.core.appender.AbstractManager.getManager(AbstractManager.java:144)
	at org.apache.logging.log4j.core.appender.OutputStreamManager.getManager(OutputStreamManager.java:100)
	at org.apache.logging.log4j.core.appender.rolling.RollingRandomAccessFileManager.getRollingRandomAccessFileManager(RollingRandomAccessFileManager.java:107)
	at org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender$Builder.build(RollingRandomAccessFileAppender.java:132)
	at org.apache.logging.log4j.core.appender.RollingRandomAccessFileAppender$Builder.build(RollingRandomAccessFileAppender.java:53)
	at org.apache.logging.log4j.core.config.plugins.util.PluginBuilder.build(PluginBuilder.java:124)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.createPluginObject(AbstractConfiguration.java:1138)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1063)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.createConfiguration(AbstractConfiguration.java:1055)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.doConfigure(AbstractConfiguration.java:664)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.initialize(AbstractConfiguration.java:258)
	at org.apache.logging.log4j.core.config.AbstractConfiguration.start(AbstractConfiguration.java:304)
	at org.apache.logging.log4j.core.LoggerContext.setConfiguration(LoggerContext.java:621)
	at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:694)
	at org.apache.logging.log4j.core.LoggerContext.reconfigure(LoggerContext.java:711)
	at org.apache.logging.log4j.core.LoggerContext.start(LoggerContext.java:253)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:245)
	at org.apache.logging.log4j.core.impl.Log4jContextFactory.getContext(Log4jContextFactory.java:47)
	at org.apache.logging.log4j.LogManager.getContext(LogManager.java:176)
	at org.apache.logging.log4j.LogManager.getLogger(LogManager.java:666)
	at org.sourcegrade.jagr.launcher.env.LaunchConfiguration$Standard.<clinit>(LaunchConfiguration.kt:36)
	at org.sourcegrade.jagr.launcher.env.Jagr$Factory$DefaultImpls.create$default(Jagr.kt:43)
	at org.sourcegrade.jagr.launcher.env.Jagr$Default.<init>(Jagr.kt:34)
	at org.sourcegrade.jagr.launcher.env.Jagr$Default.<clinit>(Jagr.kt)
	at org.sourcegrade.jagr.launcher.env.Jagr.<clinit>(Jagr.kt)
	at org.sourcegrade.jagr.gradle.extension.GraderConfiguration$1$1.invoke(GraderConfiguration.kt:77)
	at org.sourcegrade.jagr.gradle.extension.GraderConfiguration$1$1.invoke(GraderConfiguration.kt:75)
	at org.gradle.kotlin.dsl.ProjectExtensionsKt.dependencies(ProjectExtensions.kt:178)
	at org.sourcegrade.jagr.gradle.extension.GraderConfiguration$1.invoke(GraderConfiguration.kt:75)
	at org.sourcegrade.jagr.gradle.extension.GraderConfiguration$1.invoke(GraderConfiguration.kt:59)
	at org.sourcegrade.jagr.gradle.extension.GraderConfiguration._init_$lambda$2(GraderConfiguration.kt:59)
	at org.gradle.configuration.internal.DefaultUserCodeApplicationContext$CurrentApplication$1.execute(DefaultUserCodeApplicationContext.java:123)
...
	```

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.