Skip to content

Commit

Permalink
wip virutal thread tests
Browse files Browse the repository at this point in the history
  • Loading branch information
KyleAure committed Feb 5, 2024
1 parent 454d466 commit f4bcb3c
Show file tree
Hide file tree
Showing 6 changed files with 386 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package ee.jakarta.tck.concurrent.framework.junit.anno;

import java.lang.annotation.ElementType;
import java.lang.annotation.RetentionPolicy;

import java.lang.annotation.Retention;
import java.lang.annotation.Target;

import org.junit.jupiter.api.condition.EnabledForJreRange;
import org.junit.jupiter.api.condition.JRE;

/**
* These are test classes or methods that test virtual threads.
* These tests will be enabled only when running on Java 21 or higher.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.TYPE, ElementType.METHOD })
@EnabledForJreRange(
min = JRE.JAVA_21,
max = JRE.OTHER, //Unlimited upper bound
disabledReason = "Cannot test virtual threads unless running on Java 21 or higher")
public @interface UsingVirtualThreads {
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,73 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package ee.jakarta.tck.concurrent.spec.Platform.virtual;

import java.net.URL;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.EnterpriseArchive;
import org.jboss.shrinkwrap.api.spec.WebArchive;

import ee.jakarta.tck.concurrent.framework.TestClient;
import ee.jakarta.tck.concurrent.framework.junit.anno.Assertion;
import ee.jakarta.tck.concurrent.framework.junit.anno.Debug;
import ee.jakarta.tck.concurrent.framework.junit.anno.Full;
import ee.jakarta.tck.concurrent.framework.junit.anno.TestName;
import ee.jakarta.tck.concurrent.framework.junit.anno.UsingVirtualThreads;

@Full
@Debug
@RunAsClient // Requires client testing due to annotation configuration
@UsingVirtualThreads
public class VirtualFullTests extends TestClient {

@ArquillianResource(VirtualThreadServlet.class)
private URL baseURL;

@Deployment(name = "VirtualThreadTests")
public static EnterpriseArchive createDeployment() {
WebArchive war = ShrinkWrap.create(WebArchive.class, "VirtualTests_web.war")
.addClasses(VirtualThreadServlet.class);

EnterpriseArchive ear = ShrinkWrap.create(EnterpriseArchive.class, "VirtualTests.ear")
.addAsManifestResource(VirtualFullTests.class.getPackage(), "application.xml", "application.xml")
.addAsModules(war);

return ear;
}

@TestName
private String testname;

@Override
protected String getServletPath() {
return "VirtualThreadServlet";
}

@Assertion(id = "GIT:414", strategy = "Tests that a thread factory with virtual = false never returns a virtual thread.")
public void testPlatformThreadFactory() {
runTest(baseURL, testname);
}

@Assertion(id = "GIT:414", strategy = "Tests that a thread factory with virtual = true can return and use a virtual thread,"
+ " or returns a platform thread if it is not capable of providing virtual threads.")
public void testVirtualThreadFactory() {
runTest(baseURL, testname);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package ee.jakarta.tck.concurrent.spec.Platform.virtual;

import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assumptions.assumeTrue;

import java.lang.reflect.Method;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;

import javax.naming.InitialContext;

import ee.jakarta.tck.concurrent.framework.TestConstants;
import ee.jakarta.tck.concurrent.framework.TestServlet;
import jakarta.enterprise.concurrent.ManagedThreadFactory;
import jakarta.enterprise.concurrent.ManagedThreadFactoryDefinition;
import jakarta.servlet.annotation.WebServlet;

@ManagedThreadFactoryDefinition(name = "java:app/concurrent/ThreadFactoryAnnoPlatform", virtual = false)
@ManagedThreadFactoryDefinition(name = "java:app/concurrent/ThreadFactoryAnnoVirtual", virtual = true)
@WebServlet("/VirtualThreadServlet")
public class VirtualThreadServlet extends TestServlet {

private static final long serialVersionUID = 1L;

private static final Runnable NOOP_RUNNABLE = () -> {
};

// TODO add virtual tests for ManagedExecutor and ManagedScheduledExcecutor

public void testPlatformThreadFactory() throws Exception {
ManagedThreadFactory platfromThreadFactoryAnno = InitialContext
.doLookup("java:app/concurrent/ThreadFactoryAnnoPlatform");
ManagedThreadFactory platfromThreadFactoryDD = InitialContext
.doLookup("java:app/concurrent/ThreadFactoryDDPlatform");

assertFalse(isVirtual(platfromThreadFactoryAnno.newThread(NOOP_RUNNABLE)),
"Thread Factory should not have returned a virtual thread when defined with virtual=false");
assertFalse(isVirtual(platfromThreadFactoryDD.newThread(NOOP_RUNNABLE)),
"Thread Factory should not have returned a virtual thread when defined with virtual=false");
}

public void testVirtualThreadFactory() throws Exception {
ManagedThreadFactory virtualThreadFactoryAnno = InitialContext
.doLookup("java:app/concurrent/ThreadFactoryAnnoVirtual");
ManagedThreadFactory virtualThreadFactoryDD = InitialContext
.doLookup("java:app/concurrent/ThreadFactoryDDVirtual");

// If assumeTrue checks pass it means the platform supports virtual threads and
// we can continue testing,
// otherwise the test will return successfully at this point and not continue.
assumeTrue(isVirtual(virtualThreadFactoryAnno.newThread(NOOP_RUNNABLE)));
assumeTrue(isVirtual(virtualThreadFactoryDD.newThread(NOOP_RUNNABLE)));

LinkedBlockingQueue<Object> results;
Object result;

// Test virtual thread from Annotation
results = new LinkedBlockingQueue<Object>();
Thread annoThread = virtualThreadFactoryAnno
.newThread(new LookupAction(results, "java:app/concurrent/ThreadFactoryAnnoVirtual"));
annoThread.start();
result = results.poll(TestConstants.waitTimeout.toMillis(), TimeUnit.MILLISECONDS);
assertNotNull(result);
if (result instanceof Throwable)
throw new AssertionError("An error occured on thread.", (Throwable) result);

// Test virtual thread from Deployment Descriptor
results = new LinkedBlockingQueue<Object>();
Thread ddThread = virtualThreadFactoryDD
.newThread(new LookupAction(results, "java:app/concurrent/ThreadFactoryDDVirtual"));
ddThread.start();
result = results.poll(TestConstants.waitTimeout.toMillis(), TimeUnit.MILLISECONDS);
assertNotNull(result);
if (result instanceof Throwable)
throw new AssertionError("An error occured on thread.", (Throwable) result);
}

/**
* Uses reflection to call method isVirtual on on the supplied thread.
*
* @param thread - the thread being tested
* @return true, if the thread is virtual; false, if the thread is not virtual
*
* @throws Exception when unable to call the isVirtual method
*/
private boolean isVirtual(final Thread thread) throws Exception {
Method isVirtual = Thread.class.getMethod("isVirtual");
return (boolean) isVirtual.invoke(thread);
}

/**
* A simple lookup action that can pass/fail on a virtual thread
*/
class LookupAction implements Runnable {

private BlockingQueue<Object> results;
private String resource;

public LookupAction(final BlockingQueue<Object> results, final String resource) {
this.results = results;
this.resource = resource;
}

@Override
public void run() {
try {
results.add(InitialContext.doLookup(resource));
} catch (Throwable x) {
results.add(x);
}
}

}

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
/*
* Copyright (c) 2024 Contributors to the Eclipse Foundation
*
* This program and the accompanying materials are made available under the
* terms of the Eclipse Public License v. 2.0, which is available at
* http://www.eclipse.org/legal/epl-2.0.
*
* This Source Code may also be made available under the following Secondary
* Licenses when the conditions for such availability set forth in the
* Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
* version 2 with the GNU Classpath Exception, which is available at
* https://www.gnu.org/software/classpath/license.html.
*
* SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
*/
package ee.jakarta.tck.concurrent.spec.Platform.virtual;

import java.net.URL;

import org.jboss.arquillian.container.test.api.Deployment;
import org.jboss.arquillian.container.test.api.RunAsClient;
import org.jboss.arquillian.test.api.ArquillianResource;
import org.jboss.shrinkwrap.api.ShrinkWrap;
import org.jboss.shrinkwrap.api.spec.WebArchive;

import ee.jakarta.tck.concurrent.framework.TestClient;
import ee.jakarta.tck.concurrent.framework.junit.anno.Assertion;
import ee.jakarta.tck.concurrent.framework.junit.anno.Debug;
import ee.jakarta.tck.concurrent.framework.junit.anno.TestName;
import ee.jakarta.tck.concurrent.framework.junit.anno.UsingVirtualThreads;
import ee.jakarta.tck.concurrent.framework.junit.anno.Web;

@Web
@Debug
@RunAsClient // Requires client testing due to annotation configuration
@UsingVirtualThreads
public class VirtualWebTests extends TestClient {

@ArquillianResource(VirtualThreadServlet.class)
private URL baseURL;

@Deployment(name = "VirtualThreadTests")
public static WebArchive createDeployment() {
return ShrinkWrap.create(WebArchive.class, "VirtualTests_web.war")
.addPackages(false, VirtualWebTests.class.getPackage())
.addAsWebInfResource(VirtualWebTests.class.getPackage(), "web.xml", "web.xml");
}

@TestName
private String testname;

@Override
protected String getServletPath() {
return "VirtualThreadServlet";
}

@Assertion(id = "GIT:414", strategy = "Tests that a thread factory with virtual = false never returns a virtual thread.")
public void testPlatformThreadFactory() {
runTest(baseURL, testname);
}

@Assertion(id = "GIT:414", strategy = "Tests that a thread factory with virtual = true can return and use a virtual thread,"
+ " or returns a platform thread if it is not capable of providing virtual threads..")
public void testVirtualThreadFactory() {
runTest(baseURL, testname);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Contributors to the Eclipse Foundation
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->
<application version="11"
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/application_11.xsd">

<module>
<web>
<web-uri>VirtualTests_web.war</web-uri>
<context-root>/</context-root>
</web>
</module>

<managed-thread-factory>
<name>java:app/concurrent/ThreadFactoryDDPlatform</name>
<virtual>false</virtual>
</managed-thread-factory>

<managed-thread-factory>
<name>java:app/concurrent/ThreadFactoryDDVirtual</name>
<virtual>true</virtual>
</managed-thread-factory>

</application>
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--
Copyright (c) 2024 Contributors to the Eclipse Foundation
This program and the accompanying materials are made available under the
terms of the Eclipse Public License v. 2.0, which is available at
http://www.eclipse.org/legal/epl-2.0.
This Source Code may also be made available under the following Secondary
Licenses when the conditions for such availability set forth in the
Eclipse Public License v. 2.0 are satisfied: GNU General Public License,
version 2 with the GNU Classpath Exception, which is available at
https://www.gnu.org/software/classpath/license.html.
SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
-->
<web-app
version="6.1"
xmlns="https://jakarta.ee/xml/ns/jakartaee"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="https://jakarta.ee/xml/ns/jakartaee https://jakarta.ee/xml/ns/jakartaee/web-app_6_1.xsd">

<managed-thread-factory>
<name>java:app/concurrent/ThreadFactoryDDPlatform</name>
<virtual>false</virtual>
</managed-thread-factory>

<managed-thread-factory>
<name>java:app/concurrent/ThreadFactoryDDVirtual</name>
<virtual>true</virtual>
</managed-thread-factory>

</web-app>

0 comments on commit f4bcb3c

Please sign in to comment.