Giter Club home page Giter Club logo

moduletestingenvironment's Introduction

ModuleTestingEnvironment

A test helper to instantiate a full headless TerasologyEngine instance in JUnit tests.

Usage

For more examples see the test suite.

Here's an example taken from the test suite:

@ExtendWith(MTEExtension.class)
@Dependencies("MyModule")
@UseWorldGenerator("CoreWorlds:flat")
public class ExampleTest {

    @In
    private WorldProvider worldProvider;
    @In
    private BlockManager blockManager;
    @In
    private EntityManager entityManager;
    @In
    private ModuleTestingHelper helper;

    @Test
    public void testExample() {
        // create some clients (the library connects them automatically)
        Context clientContext1 = helper.createClient();
        Context clientContext2 = helper.createClient();

        // wait for both clients to be known to the server
        helper.runUntil(()-> Lists.newArrayList(entityManager.getEntitiesWith(ClientComponent.class)).size() == 2);
        assertEquals(2, Lists.newArrayList(entityManager.getEntitiesWith(ClientComponent.class)).size());

        // run while a condition is true or until a timeout passes
        boolean timedOut = helper.runWhile(1000, ()-> true);
        assertTrue(timedOut);

        // send an event to a client's local player just for fun
        clientContext1.get(LocalPlayer.class).getClientEntity().send(new ResetCameraEvent());

        // wait for a chunk to be generated
        helper.forceAndWaitForGeneration(new Vector3i());

        // set a block's type and immediately read it back
        worldProvider.setBlock(Vector3i.zero(), blockManager.getBlock("engine:air"));
        assertEquals("engine:air", worldProvider.getBlock(Vector3f.zero()).getURI().toString());
    }
}

Receiving events

You can use a TestEventReceiver to inspect events fired against the engine context.

TestEventReceiver receiver = new TestEventReceiver<>(context, DropItemEvent.class, (event, entity) -> {
  // do something with the event or entity
});

Delay code

Conventionally, we use while (condition) to wait for delaying action. This can be done in MTE test by using runWhile() method. This runs the test engine while the condition is true.

runWhile(() -> true);

Conversely, for running the enging until some condition is true, use runUntil()

runUntil(() -> false);

Check the JavaDoc and test suite for more usage examples.

Isolating test cases

By default MTEExtension will reuse the same engine instance for all test cases. If you want to create a new engine instance for every test (and wait much longer) try IsolatedMTEExtension.

moduletestingenvironment's People

Contributors

4denthusiast avatar aaron-harris avatar bkconrad avatar cervator avatar darkweird avatar e-aakash avatar eviltak avatar iaronaraujo avatar jdrueckert avatar kaen avatar keturn avatar pollend avatar skaldarnar avatar soloturn avatar

Stargazers

 avatar  avatar  avatar

Watchers

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

moduletestingenvironment's Issues

World-building environment

In writing my first test using this module, I find myself spending a lot of time writing the code that sets up the environment appropriately (e.g., "ensure enough of the world is loaded, then put dirt here, here, and here"). It's not especially complicated for my particular use-case (yet), but I'm guessing that this sort of thing is a common enough need across enough different modules that I think it may be worth building an extension of ModuleTestingEnvironment that handles some of this for you.

I've been using this code as an example; @kaen has set up a DSL for concisely encoding the world template for the test. The extension I'm envisioning would be similar.

Annotation-based dependency definition seems quirky

Two issues noted on Discord just recently in #architecture relating to something like @Dependencies({"FlexibleMovement", "CoreAssets"})

  1. Apparently this is currently needed in child classes if you use a common utility class for some basic setup (see for instance FlexibleMovementTestingEnvironment in https://github.com/Terasology/FlexibleMovement) - the annotation doesn't get inherited by default
  2. Transitive dependencies may be honored, but possibly not for assets. This is odd, but in a FlexibleMovement test with the above @Dependencies statement, despite the FM module itself having a dependency tree including CoreAssets the dirt and water block families were not found if CoreAssets wasn't explicitly included in the list

I also sort of wonder why we have to explicitly call out the parent module as a dependency? 🤔 And for that sake - if the parent module's dependencies were to be respected and just loaded normally out of module.txt why would @Dependencies even exist? Is there a case where you'd have a test in a module depend on a different module the test-owning module itself doesn't depend on? Or is it more that we'd want the ability to only activate a subset of the dependency tree? That seems like it would lead to tests differing more than needed from the mainline code.

Terasology-Archived/FlexibleMovement#3 was used for some of the testing

MTE's own test suite is very slow

This issue is not "Tests which use @ExtendWith(MTEExtension.class) are slow,"
it is "Running :modules:ModuleTestingEnvironment:test is slow."

On my workstation it takes about eight minutes, which is about as much as everything else (including engine!) put together. And it's not because MTE has a zillion tests!

Maybe in the process of fixing this, we discover what's been making MTE-using tests so slow to boot up in general.

engine lifecycle / test case isolation

TestInstance.Lifecycle vs MTE Engine lifespan

Currently the Extension does its own management of when to create new Engine instances vs re-using an existing one. (Users choose between MTEExtension or IsolatedMTEExtension.)

JUnit5 introduced its own way to manage test instance lifecycle. A test class may set TestInstance.Lifecycle.PER_CLASS to share state on the instance across invocation of all its test methods.

Is it worthwhile for us to keep our own way to specify whether an engine is shared between tests, or should we drop that part and say the engine's lifespan is the same as the test instance's?

Related Work: There may be other work in progress for managing resources across JUnit tests: junit-pioneer/junit-pioneer#348 started out being about TempDirectory, but may be generalized to support arbitrary types of resources.

Relation of Engine & Game lifecycle to JUnit Before/After hooks

JUnit will call methods annotated with BeforeAll, BeforeEach, AfterAll, AfterEach, as it enters and exits your Test methods.

A clearer way to describe some MTE setup code is according to the game engine's lifecycle: run before or after Engine initialization, or on transition to StateLoading or StateIngame.

GameEngine does provide an interface to subscribe to its state changes, but the interface we have with the most detailed lifecycle methods is the EngineSubsystem.

Should we provide a convenient way to define methods on the test class that are run at these points in the subsystem lifecycle?

What about the ComponentSystem lifecycle methods?

Neither gestalt's Modules nor ModuleEnvironment look to have lifecycle methods, but some things that handle Terasology's ModuleEnvironments call methods on whatever EnvironmentSwitchHandler is in the Context.

CrashReporter should not be enabled

As amusing as it is to see Crash Reporter's dialog pop up for a moment when a test case crashes, it's not an appropriate thing for an MTE test to do by default and it makes things extra noisy when it tries to do it in the headless CI environment.

Package as a library instead of a module

ModuleTestingEnvironment isn't a module in the sense that it's something you load during your play session, even for test purposes.

It's a library you can use with your test framework to provide a test harness for automated headless testing of events running in a Terasology engine.

I'd like to reclassify this from "terasology module" to a library we use as a testImplementation dependency.

The fixtures (DummyWorldGenerator and such) do contain some things that probably do need to be registered with the engine, so maybe that means this does still need to provide a module in some sense. There are some details to figure out there.

RFC: Make run* helper timeouts more humane.

runWhile and friends have a real-time timeout parameter to avoid tests accidentally running forever. Users (including myself some times) expect that runWhile(5000, callback) will timeout after 5000 game-time milliseconds have passsed, but in reality it's real time seconds. Tests written like this will flake as different machines simulate different amounts of game time (and therefore different game states) in a fixed amount of real time.

Currently my idea is to change the semantics of runWhile(timeout, callback) to make timeout in game time ms. The safety timeout will be moved to the helper itself and configured with a setter (helper.setSafetyTimeout()). The return type for runWhile and friends will be an enum like MTETimeout.GameTime, MTETimeout.Safety, and MTETimeout.None. I think these should be implicitly castable to boolean if possible, which would allow preserving the old interface except for the argument semantics.

reducing the number of annotations

Setting up a test class currently looks like this:

@Tag("MteTest")
@ExtendWith(MTEExtension.class)
@Dependencies("Pathfinding")
@UseWorldGenerator("Pathfinding:pathfinder")
public class PathfinderTest { /*…*/ }

Maybe we should make it look more like this:

@ModuleEnvironmentTest(modules="Pathfinding", worldGenerator="Pathfinding:pathfinder")
public class PathfinderTest { /*…*/ }
  • Tag: not required for MTE itself, but we do have a convention for adding it to all MTE-using tests for the benefit of separating the unitTest and integrationTest suites, so we might as well have something that applies it anywhere we're using MTE.
  • ExtendWith: we do need one of these, but we can wrap it up in a composed annotation.
  • Dependencies and UseWorldGenerator: MTE tests effectively always need to provide a value for Dependencies. An interface that says “use ExtendWith” can't express that sort of required parameter, but if we have a composed annotation for setting up the test, we can put the parameters in the same place.
    UseWorldGenerator has a useful default, so we don't need to make it required, but we can help discoverability by putting it in the same place.
    Neither of these annotations is at all useful on classes that aren't MTEExtension-enabled test classes, so we don't lose anything by taking them out of the interface.

add ability to use a WorldGenerator defined in src/test (not src/main)

MTE has a way to specify which world generator should be used: The @UseWorldGenerator annotation.

That works fine for WorldGenerators defined in the module or dependencies of the module, but it does not currently allow you to define a WorldGenerator in your classes under the src/test sources.

It would be nice to be able to do so. With the current limitation, any world generators defined for testing (i.e. to make worlds that have very specific properties in predicable places, unlike the random worlds for game modes) will show up mixed in with the other world types that are provided for gameplay.

[original discussion]

"Connection refused" errors when attempting parallel test execution

During MovingBlocks/Terasology#4576 I noticed that running tests with --parallel sometimes resulted in an error Connection refused: localhost/127.0.0.1:25777, which I haven't seen in other test runs.

I didn't dig in to the details, but I'm guessing multiple processes were probably trying to use the same ports at once. If that's the case, either

a. they shouldn't be trying to use network ports at all, or
b. they need some smarter port-allocation logic that's muchmuch less likely to have collisions with other instances.

createClient fails while initializing engine state

createClient fails with an NPE from somewhere beneath TerasologyEngine.changeState (currently in TerasologyCanvasImpl).

Looking at the code for createClient, I see it jumps right in to things without going through anything like TestingStateHeadlessSetup. As a client, it's true that it doesn't need to do most of the setup that the host does (because it will get that configuration from the host when it connects), but there might be some stuff along the lines of EntitySystemSetup that needs to happen?

Guard against infinite loops - add timeout somehow if a test gets stuck?

Specific example: Terasology/SimpleFarming#97

One theory is something goes weird and the MTE test just keeps generating chunks forever, which prints one of those log snippets about compacting the chunk cache every tick, which might be the only indication that something is still happening, otherwise it would just appear to hang.

I've seen similar cases elsewhere. For instance http://jenkins.terasology.io/teraorg/job/Terasology/job/engine/view/change-requests/job/PR-4036/ related to MovingBlocks/Terasology#4036 for some reason got stuck several times for hours on end. One example printed this a bunch (although not nearly as much as the SimpleFarming PR):

11:50:39.535 [Test worker] ERROR o.t.w.b.internal.BlockManagerImpl - Attempt to fetch block with unknown uri 'engine:air'

It may not be an issue specific to the MTE, could be some underlying issue with environment-based tests. Not sure which actual test stalls for SimpleFarming, although the engine one is StorageManagerTest extends TerasologyTestingEnvironment so yeah not MTE, but maybe both hit that environment class?

ReuseEngineTest failure

CI says:

java.util.NoSuchElementException: No value present
	at java.util.Optional.get(Optional.java:135)
	at org.terasology.engine.rendering.nui.internal.TerasologyCanvasImpl.<init>(TerasologyCanvasImpl.java:45)
	at org.terasology.engine.rendering.nui.internal.NUIManagerInternal.<init>(NUIManagerInternal.java:116)
	at org.terasology.engine.core.modes.StateMainMenu.init(StateMainMenu.java:82)

in ReuseEngineTest.

That TerasologyCanvasImpl is: https://github.com/MovingBlocks/Terasology/blob/3b8c37df89fc0839cc84bda1e325310e1f12ed86/engine/src/main/java/org/terasology/rendering/nui/internal/TerasologyCanvasImpl.java#L43-L45

[and I'm not sure when GitHub will and won't inline the source listing. Is it only when the issue is in the same repository as the source? or the same organization?]

so Assets.getTexture("engine:white") ... the engine module isn't loaded, or some asset file is not in the right place?

provide in-memory world implementation (MapWorldProvider)

While converting some tests from WorldProvidingHeadlessEnvironment to ModuleTestingEnvironment, I discovered that WPHE uses MapWorldProvider, which generates chunks on demand.

There might be a handful of modules providing large-scale features that need to deal with the intricacies of chunk loading, and they should be able to use the default WorldProvider so they don't get a false sense of security. But I think most tests for most modules are only interested a small area, and this on-demand behavior would make things much easier for them. It would eliminate the need for them to use things like forceAndWaitForGeneration.

Mystery `APIScanner` NPE on MTE tests in some cases

The really mysterious part being how you can bypass it: by removing a specific package-info.java file: org/terasology/input/binds/inventory/package-info.java inside the Inventory module (assuming naturally that you actually have that module locally, but being that it is a dependency of Core now it'll likely be present)

Why that one specific file? No idea! May not always be the case, may involve a different instance of that file based on workspace state? So far in a mega-workspace it is always that one for me.

23:13:32.292 [main] ERROR o.terasology.engine.TerasologyEngine - Failed to initialise Terasology
java.lang.NullPointerException: null
	at org.terasology.module.sandbox.APIScanner.scan(APIScanner.java:56)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.accept(ForEachOps.java:184)
	at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:175)
	at java.util.Iterator.forEachRemaining(Iterator.java:116)
	at java.util.Spliterators$IteratorSpliterator.forEachRemaining(Spliterators.java:1801)
	at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:481)
	at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:471)
	at java.util.stream.ForEachOps$ForEachOp.evaluateSequential(ForEachOps.java:151)
	at java.util.stream.ForEachOps$ForEachOp$OfRef.evaluateSequential(ForEachOps.java:174)
	at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234)
	at java.util.stream.ReferencePipeline.forEach(ReferencePipeline.java:418)
	at org.terasology.engine.module.ModuleManagerImpl.setupSandbox(ModuleManagerImpl.java:191)
	at org.terasology.engine.module.ModuleManagerImpl.<init>(ModuleManagerImpl.java:117)
	at org.terasology.engine.module.ModuleManagerImpl.<init>(ModuleManagerImpl.java:127)
	at org.terasology.engine.TerasologyEngine.initManagers(TerasologyEngine.java:309)
	at org.terasology.engine.TerasologyEngine.initialize(TerasologyEngine.java:210)
	at org.terasology.moduletestingenvironment.ModuleTestingEnvironment.createEngine(ModuleTestingEnvironment.java:245)
	at org.terasology.moduletestingenvironment.ModuleTestingEnvironment.createHeadlessEngine(ModuleTestingEnvironment.java:217)
	at org.terasology.moduletestingenvironment.ModuleTestingEnvironment.createHost(ModuleTestingEnvironment.java:252)
	at org.terasology.moduletestingenvironment.ModuleTestingEnvironment.setup(ModuleTestingEnvironment.java:115)
	at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
	at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
	at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
	at java.lang.reflect.Method.invoke(Method.java:498)
	at org.junit.runners.model.FrameworkMethod$1.runReflectiveCall(FrameworkMethod.java:50)
	at org.junit.internal.runners.model.ReflectiveCallable.run(ReflectiveCallable.java:12)
	at org.junit.runners.model.FrameworkMethod.invokeExplosively(FrameworkMethod.java:47)
	at org.junit.internal.runners.statements.RunBefores.evaluate(RunBefores.java:24)
	at org.junit.internal.runners.statements.RunAfters.evaluate(RunAfters.java:27)
	at org.junit.runners.ParentRunner.runLeaf(ParentRunner.java:325)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:78)
	at org.junit.runners.BlockJUnit4ClassRunner.runChild(BlockJUnit4ClassRunner.java:57)
	at org.junit.runners.ParentRunner$3.run(ParentRunner.java:290)
	at org.junit.runners.ParentRunner$1.schedule(ParentRunner.java:71)
	at org.junit.runners.ParentRunner.runChildren(ParentRunner.java:288)
	at org.junit.runners.ParentRunner.access$000(ParentRunner.java:58)
	at org.junit.runners.ParentRunner$2.evaluate(ParentRunner.java:268)
	at org.junit.runners.ParentRunner.run(ParentRunner.java:363)
	at org.junit.runner.JUnitCore.run(JUnitCore.java:137)
	at com.intellij.junit4.JUnit4IdeaTestRunner.startRunnerWithArgs(JUnit4IdeaTestRunner.java:68)
	at com.intellij.rt.execution.junit.IdeaTestRunner$Repeater.startRunnerWithArgs(IdeaTestRunner.java:47)
	at com.intellij.rt.execution.junit.JUnitStarter.prepareStreamsAndStart(JUnitStarter.java:242)
	at com.intellij.rt.execution.junit.JUnitStarter.main(JUnitStarter.java:70)
23:13:32.293 [main] INFO  o.terasology.engine.TerasologyEngine - Shutting down Terasology...

Tests can be overly resource hungry or otherwise get out of control - add hardening somehow?

Maybe mildly similar to #25 but distinct - in this case testExample literally went out of memory:

http://jenkins.terasology.io/teraorg/job/Terasology/job/Modules/job/M/job/ModuleTestingEnvironment/job/PR-29/1/console

I'm not sure what the best way to address this is. It doesn't look like the build agent itself ran out of memory, it had a little more space allocated, although maybe if Java requested a large enough chunk of memory (more than 300MB in one reqest?) that could be related

image

Maybe it is something more specific? The build log talks about "GC overhead limit exceeded"

DeprecationTest > testExample() STANDARD_ERROR
    Exception in thread "Chunk-Processing-Reactor" java.lang.OutOfMemoryError: GC overhead limit exceeded
    Exception in thread "Thread-148" java.lang.OutOfMemoryError: GC overhead limit exceeded

Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "Chunk-Processing-6"

Cannot run MTE tests in a standalone module build environment (like Jenkins)

I figured out a way to get past some unrelated quirky natives issues but only uncovered what's probably a fair limitation at present: if running in a standalone workspace (just one module, fetching engine etc all as binaries) then MTE tests at least in some cases will fail, even if just trying to prepare a module environment with the test-bearing module itself available.

Take the Health module as an example. When it attempts to run its MTE tests it runs into the following problem, triggered in TestingStateHeadlessSetup:

[Test worker] WARN org.terasology.moduletestingenvironment.TestingStateHeadlessSetup - Adding dependencies for Health
[Test worker] WARN org.terasology.moduletestingenvironment.TestingStateHeadlessSetup - Unable to resolve modules: [Health]
[Test worker] INFO org.terasology.engine.TerasologyEngine - Shutting down Terasology...

I am not sure if this is just a simple quirk or something bigger to fix. In this context the engine will start out of a jar file in the Gradle cache and the Health module is the project root. I've been able to confirm it in a local module-only workspace taking Jenkins out of the equation.

Steps to reproduce:

  • Take a copy of the Health module from a regular workspace, put it somewhere on its own
  • Copy in gradlew or gradlew.bat (depending on your OS) from the engine workspace into the Health directory
  • Likewise copy in the config, natives, and gradle directories from there
  • Optionally copy in a gradle.properties if needing to set the alternativeResolutionRepo=http://artifactory.terasology.org/artifactory/virtual-nanoware-and-remote flag that'll let Gradle build against the Nanoware-specific code line (until an associated engine PR is merged into MovingBlocks/Terasology)
  • Run gradlew clean check

Let users specify component types in TestEventReceiver

Currently, the TestEventReceiver allows to specify the event class to be caught, but it lacks the abilitiy to restrict event handling to a specific set of components to be present. This, however, is crucial for events such as OnAddedComponent which themselves don't carry any information. Without the indication of component classes it is impossible to react to these kind of "informative events" that rely on the component check.

Note that this event will only be received by @ReceiveEvent methods where all components in its list are present and at least one is involved in the action causing the event.

As the components are just specified as list of component class it may be possible to extend the existing interface with another parameter taking this list:

TestEventReceiver receiver = new TestEventReceiver<>(context, OnComponentAdded.class, (event, entity) -> {
  // do something with the event or entity
}, List.of(StunEffect.class));

This receiver signature should be equivalent to the following event handler:

@ReceiveEvent(components = {StunEffect.class})
public void onStunAdded(OnComponentAdded event, EntityRef entity) {
  // do something with the event or entity
}

Blocked by MovingBlocks/Terasology#3147

add ability to use assets defined in src/test

I was looking at writing tests for DynamicCities. It has systems that depend heavily on prefab assets for configuration. Sure, we can change those things to add programmatic interfaces for configuration as well, but it's a reasonable design: Configuration of these things should be data-driven, and the way modules load data is through the asset manager.

But I don't want the assets I define for specific test scenarios mixed in with all the other assets meant for gameplay.

[original discussion]

SimpleFarming transitive dependencies irregularities

testRuntimeClasspath dependency report
  • org.terasology.modules:CoreAssets:[2.0.1,3.0.0) ➡ 2.3.0-SNAPSHOT
  • org.terasology.modules:Inventory:[1.1.0,2.0.0) ➡ 1.5.0-SNAPSHOT
  • org.terasology.modules:ModuleTestingEnvironment:[0.3.0,0.4.0) ➡ 0.3.2-SNAPSHOT
  • org.terasology.modules:Genome:[1.0.0,2.0.0) ➡ 1.0.1-SNAPSHOT
    • org.terasology.modules:Inventory:[1.1.0,2.0.0) ➡ 1.5.0-SNAPSHOT
  • org.terasology.modules:BasicCrafting:[1.0.0,2.0.0) ➡ 1.1.0-SNAPSHOT
    • org.terasology.modules:Inventory:[1.1.0,2.0.0) ➡ 1.5.0-SNAPSHOT
  • org.terasology.modules:SubstanceMatters:[2.0.0,3.0.0) ➡ 2.1.0-SNAPSHOT
    • org.terasology.modules:CoreAssets:[2.0.1-SNAPSHOT,3.0.0) ➡ 2.3.0-SNAPSHOT
    • org.terasology.modules:Fluid:[2.0.0-SNAPSHOT,2.0.0) ➡ 2.0.0-SNAPSHOT
      • org.terasology.modules:Inventory:+ ➡ 1.5.0-SNAPSHOT
      • org.terasology.modules:FlowingLiquids:+ ➡ 1.4.0-SNAPSHOT
    • org.terasology.modules:Inventory:[1.1.0-SNAPSHOT,2.0.0) ➡ 1.5.0-SNAPSHOT
    • org.terasology.modules:ItemRendering:[1.1.0-SNAPSHOT,2.0.0) ➡ 1.2.0-SNAPSHOT
      • org.terasology.modules:Inventory:[1.1.0-SNAPSHOT,2.0.0) ➡ 1.5.0-SNAPSHOT
    • org.terasology.modules:Workstation:[1.1.0-SNAPSHOT,2.0.0) ➡ 1.2.0-SNAPSHOT
      • org.terasology.modules:Fluid:[2.0.0-SNAPSHOT,) ➡ 2.0.0-SNAPSHOT
      • org.terasology.modules:Inventory:[1.1.0-SNAPSHOT,) ➡ 1.5.0-SNAPSHOT
loading classpath modules
22:47:28.245 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded SimpleFarming from /home/jenkins/agent/workspace/_Modules_S_SimpleFarming_develop
22:47:28.250 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded SubstanceMatters from /home/jenkins/.gradle/caches/modules-2/files-2.1/org.terasology.modules/SubstanceMatters/2.1.0-SNAPSHOT/9f35192aa8af83452c8e76a8ac001d2dec871d3b/SubstanceMatters-2.1.0-SNAPSHOT.jar
22:47:28.253 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded CoreAssets from /home/jenkins/.gradle/caches/modules-2/files-2.1/org.terasology.modules/CoreAssets/2.3.0-SNAPSHOT/2d3268349e1e678827ba8a4ae67b301f0c598363/CoreAssets-2.3.0-SNAPSHOT.jar
22:47:28.257 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded Genome from /home/jenkins/.gradle/caches/modules-2/files-2.1/org.terasology.modules/Genome/1.0.1-SNAPSHOT/11fc4fb72553da2563c1864245e4a5b1692cb3ed/Genome-1.0.1-SNAPSHOT.jar
22:47:28.261 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded BasicCrafting from /home/jenkins/.gradle/caches/modules-2/files-2.1/org.terasology.modules/BasicCrafting/1.1.0-SNAPSHOT/37fa36bb0ab2d79dab18628e0476240b39d5f81e/BasicCrafting-1.1.0-SNAPSHOT.jar
22:47:28.268 [Test worker] INFO  o.t.engine.core.module.ModuleManager - Loaded Workstation from /home/jenkins/.gradle/caches/modules-2/files-2.1/org.terasology.modules/Workstation/1.2.0-SNAPSHOT/c1de4f87c39e014960528af396c64ae1297c81df/Workstation-1.2.0-SNAPSHOT.jar

22:47:28.273 [Test worker] WARN  org.reflections.Reflections - could not get type for name org.terasology.logic.inventory.ItemDifferentiating from any class loader
org.reflections.ReflectionsException: could not get type for name org.terasology.logic.inventory.ItemDifferentiating
	at org.reflections.ReflectionUtils.forName(ReflectionUtils.java:387)
	at org.reflections.Reflections.expandSuperTypes(Reflections.java:387)
	at org.reflections.Reflections.<init>(Reflections.java:126)
	at org.terasology.gestalt.module.ModuleFactory.scanContents(ModuleFactory.java:237)
	at org.terasology.gestalt.module.ModuleFactory.scanOrLoadArchiveManifest(ModuleFactory.java:260)
	at org.terasology.gestalt.module.ModuleFactory.createArchiveModule(ModuleFactory.java:406)
	at org.terasology.engine.core.module.ClasspathCompromisingModuleFactory.createArchiveModule(ClasspathCompromisingModuleFactory.java:59)
	at org.terasology.gestalt.module.ModuleFactory.createArchiveModule(ModuleFactory.java:383)
	at org.terasology.gestalt.module.ModuleFactory.createModule(ModuleFactory.java:441)
	at org.terasology.engine.core.module.ModuleManager.loadModulesFromClassPath(ModuleManager.java:164)
	at org.terasology.engine.core.module.ModuleManager.<init>(ModuleManager.java:80)
later, in loadProcesses.RegisterMods
22:47:31.346 [Test worker] INFO  o.t.e.c.m.loadProcesses.RegisterMods - Activating module: engine:5.2.0-SNAPSHOT
22:47:31.347 [Test worker] INFO  o.t.e.c.m.loadProcesses.RegisterMods - Activating module: CoreAssets:2.3.0-SNAPSHOT
22:47:31.347 [Test worker] INFO  o.t.e.c.m.loadProcesses.RegisterMods - Activating module: ModuleTestingEnvironment:0.3.2-SNAPSHOT
22:47:31.347 [Test worker] INFO  o.t.e.c.m.loadProcesses.RegisterMods - Activating module: Inventory:1.5.0-SNAPSHOT
22:47:31.347 [Test worker] INFO  o.t.e.c.m.loadProcesses.RegisterMods - Activating module: SimpleFarming:2.2.0-SNAPSHOT
22:47:31.355 [Thread-17] WARN  org.reflections.Reflections - could not create Vfs.Dir from url. ignoring the exception and continuing
org.reflections.ReflectionsException: could not create Vfs.Dir from url, no matching UrlType was found [file:/home/jenkins/agent/workspace/_Modules_S_SimpleFarming_develop/build/resources/main]
either use fromURL(final URL url, final List<UrlType> urlTypes) or use the static setDefaultURLTypes(final List<UrlType> urlTypes) or addDefaultURLTypes(UrlType urlType) with your specialized UrlType.
	at org.reflections.vfs.Vfs.fromURL(Vfs.java:111)
	at org.reflections.vfs.Vfs.fromURL(Vfs.java:93)
	at org.reflections.Reflections.scan(Reflections.java:244)
	at org.reflections.Reflections.scan(Reflections.java:204)
	at org.reflections.Reflections.<init>(Reflections.java:123)
	at org.terasology.reflection.TypeRegistry.initializeReflections(TypeRegistry.java:104)
	at org.terasology.reflection.ModuleTypeRegistry.initializeReflections(ModuleTypeRegistry.java:24)
	at org.terasology.reflection.ModuleTypeRegistry.reload(ModuleTypeRegistry.java:20)
	at org.terasology.engine.core.bootstrap.EnvironmentSwitchHandler.handleSwitchToGameEnvironment(EnvironmentSwitchHandler.java:76)
	at org.terasology.engine.core.modes.loadProcesses.RegisterMods.lambda$step$0(RegisterMods.java:75)

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.