getInferredEncodings() {
+ return inferredEncodings;
+ }
+
+ public boolean isSsl() {
+ return ssl;
+ }
+
+ public void setSsl(boolean ssl) {
+ this.ssl = ssl;
+ }
+
+ public String getKeystorePath() {
+ return keystorePath;
+ }
+
+ public void setKeystorePath(String keystorePath) {
+ this.keystorePath = keystorePath;
+ }
+
+ public String getKeystorePassword() {
+ return keystorePassword;
+ }
+
+ public void setKeystorePassword(String keystorePassword) {
+ this.keystorePassword = keystorePassword;
+ }
+
+ public String getTrustStorePath() {
+ return trustStorePath;
+ }
+
+ public void setTrustStorePath(String trustStorePath) {
+ this.trustStorePath = trustStorePath;
+ }
+
+ public String getTrustStorePassword() {
+ return trustStorePassword;
+ }
+
+ public void setTrustStorePassword(String trustStorePassword) {
+ this.trustStorePassword = trustStorePassword;
+ }
+
+ public boolean isSniRequired() {
+ return sniRequired;
+ }
+
+ public void setSniRequired(boolean sniRequired) {
+ this.sniRequired = sniRequired;
+ }
+
+ public boolean isSniHostCheck() {
+ return sniHostCheck;
+ }
+
+ public void setSniHostCheck(boolean sniHostCheck) {
+ this.sniHostCheck = sniHostCheck;
+ }
+
+ public boolean isNeedClientAuth() {
+ return needClientAuth;
+ }
+
+ public void setNeedClientAuth(boolean needClientAuth) {
+ this.needClientAuth = needClientAuth;
+ }
+
+ public boolean isH2cEnabled() {
+ return h2cEnabled;
+ }
+
+ public void setH2cEnabled(boolean h2cEnabled) {
+ this.h2cEnabled = h2cEnabled;
+ }
+}
+
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/ArquillianAppProvider.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/ArquillianAppProvider.java
new file mode 100644
index 0000000000000000000000000000000000000000..ba7f64bc43022bed015b22599183c33878d15fd4
--- /dev/null
+++ b/testsuite/src/main/java/org/smartboot/servlet/testsuite/ArquillianAppProvider.java
@@ -0,0 +1,128 @@
+/*
+ * Copyright (C) [2022] smartboot [zhengjunweimail@163.com]
+ *
+ * 企业用户未经smartboot组织特别许可,需遵循AGPL-3.0开源协议合理合法使用本项目。
+ *
+ * Enterprise users are required to use this project reasonably
+ * and legally in accordance with the AGPL-3.0 open source agreement
+ * without special permission from the smartboot organization.
+ */
+
+package org.smartboot.servlet.testsuite;
+
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.api.exporter.ZipExporter;
+import org.smartboot.servlet.ContainerRuntime;
+import org.smartboot.servlet.ServletContextRuntime;
+import org.smartboot.servlet.util.WarUtil;
+
+import java.io.File;
+import java.io.IOException;
+import java.net.URI;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.logging.Logger;
+
+public class ArquillianAppProvider {
+ private static final Logger LOG = Logger.getLogger(ArquillianAppProvider.class.getName());
+
+ /**
+ * The prefix assigned to the temporary file where the archive is exported
+ */
+ private static final String EXPORT_FILE_PREFIX = "export";
+
+ /**
+ * Directory into which we'll extract export the war files
+ */
+ private static final File EXPORT_DIR;
+
+ static {
+ /*
+ * Use of java.io.tmpdir Should be a last-resort fallback for temp directory.
+ *
+ * Use of java.io.tmpdir on CI systems is dangerous (overwrite possibility is extremely high)
+ *
+ * Use of java.io.tmpdir on Unix systems is unreliable (due to common /tmp dir cleanup processes)
+ */
+ File systemDefaultTmpDir = new File(System.getProperty("java.io.tmpdir"));
+
+ // If running under maven + surefire, use information provided by surefire.
+ String baseDirVal = System.getProperty("basedir");
+
+ File mavenTmpDir = null;
+ if (baseDirVal != null) {
+ File baseDir = new File(baseDirVal);
+ if (baseDir.exists() && baseDir.isDirectory()) {
+ File targetDir = new File(baseDir, "target");
+ if (targetDir.exists() && targetDir.isDirectory()) {
+ mavenTmpDir = new File(targetDir, "arquillian-jetty-temp");
+ mavenTmpDir.mkdirs();
+ }
+ }
+ }
+
+ if ((mavenTmpDir != null) && mavenTmpDir.exists() && mavenTmpDir.isDirectory()) {
+ EXPORT_DIR = mavenTmpDir;
+ } else {
+ EXPORT_DIR = systemDefaultTmpDir;
+ }
+
+ // If the temp location doesn't exist or isn't a directory
+ if (!EXPORT_DIR.exists() || !EXPORT_DIR.isDirectory()) {
+ throw new IllegalStateException("Could not obtain export directory \"" + EXPORT_DIR.getAbsolutePath() + "\"");
+ }
+ }
+
+ private final JettyEmbeddedConfiguration config;
+ private ContainerRuntime deploymentManager;
+
+ public ArquillianAppProvider(JettyEmbeddedConfiguration config) {
+ this.config = config;
+ }
+
+ protected ServletContextRuntime createApp(ContainerRuntime containerRuntime, final Archive> archive) throws Exception {
+ String name = archive.getName();
+ int extOff = name.lastIndexOf('.');
+ if (extOff <= 0) {
+ throw new RuntimeException("Not a valid Web Archive filename: " + name);
+ }
+ String ext = name.substring(extOff).toLowerCase();
+ if (!ext.equals(".war")) {
+ throw new RuntimeException("Not a recognized Web Archive: " + name);
+ }
+ name = name.substring(0, extOff);
+
+ final File exported;
+ try {
+ if (this.config.isUseArchiveNameAsContext()) {
+ Path tmpDirectory = Files.createTempDirectory("arquillian-jetty");
+ Path archivePath = tmpDirectory.resolveSibling(archive.getName());
+ Files.deleteIfExists(archivePath);
+ exported = Files.createFile(archivePath).toFile();
+ exported.deleteOnExit();
+ } else {
+ // If this method returns successfully then it is guaranteed that:
+ // 1. The file denoted by the returned abstract pathname did not exist before this method was invoked, and
+ // 2. Neither this method nor any of its variants will return the same abstract pathname again in the current invocation of the virtual machine.
+ exported = File.createTempFile(EXPORT_FILE_PREFIX, archive.getName(), EXPORT_DIR);
+ }
+ } catch (IOException e) {
+ throw new RuntimeException("Could not create temporary File in " + EXPORT_DIR + " to write exported archive",
+ e);
+ }
+ // We are overwriting the temporary file placeholder reserved by File#createTemplateFile()
+ archive.as(ZipExporter.class).exportTo(exported, true);
+
+ // Mark to delete when we come down
+ // exported.deleteOnExit();
+
+ // Add the context
+ URI uri = exported.toURI();
+ LOG.info("Webapp archive location: " + uri.toASCIIString());
+ File dirFile = new File(exported.getParentFile(), name);
+ System.out.println("开始解压[" + name + "]...");
+ WarUtil.unZip(exported, dirFile);
+ return containerRuntime.addRuntime(dirFile.getAbsolutePath(), "/" + name);
+ }
+
+}
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/DemoServlet.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/DemoServlet.java
deleted file mode 100644
index 06a9d62d399249ad5e06bc6abc2c805852b3df66..0000000000000000000000000000000000000000
--- a/testsuite/src/main/java/org/smartboot/servlet/testsuite/DemoServlet.java
+++ /dev/null
@@ -1,40 +0,0 @@
-/*
- * Copyright (c) 2017-2021, org.smartboot. All rights reserved.
- * project name: smart-servlet
- * file name: DemoServlet.java
- * Date: 2021-05-14
- * Author: sandao (zhengjunweimail@163.com)
- *
- */
-package org.smartboot.servlet.testsuite;
-
-import com.alibaba.fastjson.JSONObject;
-
-import javax.servlet.ServletException;
-import javax.servlet.http.HttpServlet;
-import javax.servlet.http.HttpServletRequest;
-import javax.servlet.http.HttpServletResponse;
-import java.io.IOException;
-import java.nio.charset.StandardCharsets;
-import java.util.Enumeration;
-
-/**
- * @author 三刀(zhengjunweimail@163.com)
- * @version V1.0 , 2021/5/14
- */
-public class DemoServlet extends HttpServlet {
- @Override
- protected void doGet(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
- JSONObject jsonObject = new JSONObject();
- jsonObject.put("contextPath", req.getContextPath());
- jsonObject.put("servletPath", req.getServletPath());
- jsonObject.put("pathInfo", req.getPathInfo());
- jsonObject.put("queryString", req.getQueryString());
- Enumeration enumeration = req.getParameterNames();
- while ((enumeration.hasMoreElements())) {
- String param = String.valueOf(enumeration.nextElement());
- jsonObject.put("param_" + param, req.getParameter(param));
- }
- resp.getOutputStream().write((jsonObject.toJSONString()).getBytes(StandardCharsets.UTF_8));
- }
-}
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedConfiguration.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedConfiguration.java
new file mode 100644
index 0000000000000000000000000000000000000000..09aa9ab368dc565860f51514d9b937151fa8cbf3
--- /dev/null
+++ b/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedConfiguration.java
@@ -0,0 +1,124 @@
+/*
+ * Copyright (C) [2022] smartboot [zhengjunweimail@163.com]
+ *
+ * 企业用户未经smartboot组织特别许可,需遵循AGPL-3.0开源协议合理合法使用本项目。
+ *
+ * Enterprise users are required to use this project reasonably
+ * and legally in accordance with the AGPL-3.0 open source agreement
+ * without special permission from the smartboot organization.
+ */
+package org.smartboot.servlet.testsuite;
+
+
+import org.smartboot.http.server.HttpServerConfiguration;
+
+import java.io.File;
+import java.net.URI;
+
+/**
+ * A {@link org.jboss.arquillian.container.spi.client.container.ContainerConfiguration} implementation for the Jetty Embedded
+ * containers.
+ *
+ * @author Dan Allen
+ * @author Ales Justin
+ */
+public class JettyEmbeddedConfiguration extends AbstractJettyEmbeddedConfiguration {
+ public enum ClassLoaderBehavior {
+ /**
+ * Default behavior for Java Spec (server classloader, then webapp).
+ *
+ * Also the default for Arquillian.
+ */
+ JAVA_SPEC,
+ /**
+ * Default behavior for Servlet Spec (webapp classloader, then server)
+ */
+ SERVLET_SPEC
+ }
+
+ /**
+ * Classloader Search Order behavior.
+ *
+ */
+ private ClassLoaderBehavior classloaderBehavior = ClassLoaderBehavior.JAVA_SPEC;
+
+ /**
+ * Optional override for the default servlet spec descriptor
+ */
+ private URI defaultsDescriptor;
+
+ /**
+ * Dump, to System.err, the server state tree after the server has successfully started up.
+ */
+ private boolean dumpServerAfterStart = false;
+
+ /**
+ * Optional HttpConfiguration for the ServerConnector that Arquillian
+ * creates.
+ */
+ private HttpServerConfiguration httpConfiguration;
+
+ /**
+ * Idle Timeout (in milliseconds) for active connections.
+ *
+ * Default: 30,000ms
+ */
+ private long idleTimeoutMillis = 30000;
+
+ /**
+ * Base directory for all temp files that Jetty will manage.
+ */
+ private File tempDirectory;
+
+ public ClassLoaderBehavior getClassloaderBehavior() {
+ return classloaderBehavior;
+ }
+
+ public URI getDefaultsDescriptor() {
+ return defaultsDescriptor;
+ }
+
+ public HttpServerConfiguration getHttpConfiguration() {
+ return httpConfiguration;
+ }
+
+ public long getIdleTimeoutMillis() {
+ return idleTimeoutMillis;
+ }
+
+ public File getTempDirectory() {
+ return tempDirectory;
+ }
+
+ public boolean hasDefaultsDescriptor() {
+ return (defaultsDescriptor != null);
+ }
+
+ public boolean isDumpServerAfterStart() {
+ return dumpServerAfterStart;
+ }
+
+ public void setClassloaderBehavior(ClassLoaderBehavior classloaderBehavior) {
+ this.classloaderBehavior = classloaderBehavior;
+ }
+
+ public void setDefaultsDescriptor(URI defaultsDescriptor) {
+ this.defaultsDescriptor = defaultsDescriptor;
+ }
+
+ public void setDumpServerAfterStart(boolean serverDumpAfterStart) {
+ this.dumpServerAfterStart = serverDumpAfterStart;
+ }
+
+ public void setHttpConfiguration(HttpServerConfiguration httpConfiguration) {
+ this.httpConfiguration = httpConfiguration;
+ }
+
+ public void setIdleTimeoutMillis(long milliseconds) {
+ this.idleTimeoutMillis = milliseconds;
+ }
+
+ public void setTempDirectory(File tempDirectory) {
+ this.tempDirectory = tempDirectory;
+ }
+}
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedContainer.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedContainer.java
new file mode 100644
index 0000000000000000000000000000000000000000..204ad637cf7018af5af42617989a0aa6f7acea1b
--- /dev/null
+++ b/testsuite/src/main/java/org/smartboot/servlet/testsuite/JettyEmbeddedContainer.java
@@ -0,0 +1,186 @@
+/*
+ * Copyright (C) [2022] smartboot [zhengjunweimail@163.com]
+ *
+ * 企业用户未经smartboot组织特别许可,需遵循AGPL-3.0开源协议合理合法使用本项目。
+ *
+ * Enterprise users are required to use this project reasonably
+ * and legally in accordance with the AGPL-3.0 open source agreement
+ * without special permission from the smartboot organization.
+ */
+package org.smartboot.servlet.testsuite;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.container.spi.client.container.DeploymentException;
+import org.jboss.arquillian.container.spi.client.container.LifecycleException;
+import org.jboss.arquillian.container.spi.client.protocol.ProtocolDescription;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.HTTPContext;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.ProtocolMetaData;
+import org.jboss.arquillian.container.spi.client.protocol.metadata.Servlet;
+import org.jboss.arquillian.container.spi.context.annotation.DeploymentScoped;
+import org.jboss.arquillian.core.api.InstanceProducer;
+import org.jboss.arquillian.core.api.annotation.ApplicationScoped;
+import org.jboss.arquillian.core.api.annotation.Inject;
+import org.jboss.shrinkwrap.api.Archive;
+import org.jboss.shrinkwrap.descriptor.api.Descriptor;
+import org.smartboot.http.common.utils.Mimetypes;
+import org.smartboot.http.server.*;
+import org.smartboot.http.server.impl.WebSocketRequestImpl;
+import org.smartboot.http.server.impl.WebSocketResponseImpl;
+import org.smartboot.servlet.ContainerRuntime;
+import org.smartboot.servlet.ServletContextRuntime;
+import org.smartboot.servlet.conf.ServletInfo;
+
+import javax.servlet.ServletContext;
+import java.io.File;
+import java.util.Map;
+import java.util.Set;
+import java.util.logging.Logger;
+
+public class JettyEmbeddedContainer implements DeployableContainer {
+ private static final Logger log = Logger.getLogger(JettyEmbeddedContainer.class.getName());
+
+ private HttpBootstrap bootstrap;
+ private ContainerRuntime containerRuntime;
+ private ArquillianAppProvider appProvider;
+
+ private JettyEmbeddedConfiguration containerConfig;
+
+ private String listeningHost;
+ private int listeningPort;
+
+ @Inject
+ @DeploymentScoped
+ private InstanceProducer webAppContextProducer;
+
+ @Inject
+ @ApplicationScoped
+ private InstanceProducer servletContextInstanceProducer;
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jboss.arquillian.spi.client.container.DeployableContainer#getConfigurationClass()
+ */
+ public Class getConfigurationClass() {
+ return JettyEmbeddedConfiguration.class;
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jboss.arquillian.spi.client.container.DeployableContainer#getDefaultProtocol()
+ */
+ public ProtocolDescription getDefaultProtocol() {
+ // Jetty 9 is a Servlet 3.1 container.
+ // However, Arquillian "Protocol" actuall means "Packaging"
+ // TODO: Fix to servlet 3.1 (when available in arquillian)
+ return new ProtocolDescription("Servlet 3.0");
+ }
+
+ public void setup(JettyEmbeddedConfiguration containerConfig) {
+ this.containerConfig = containerConfig;
+ }
+
+ public void start() throws LifecycleException {
+ appProvider = new ArquillianAppProvider(containerConfig);
+ this.bootstrap = new HttpBootstrap();
+ containerRuntime = new ContainerRuntime();
+ bootstrap.httpHandler(new HttpServerHandler() {
+ @Override
+ public void handle(HttpRequest request, HttpResponse response) {
+ containerRuntime.doHandle(request, response);
+ }
+ }).webSocketHandler(new WebSocketHandler() {
+ @Override
+ public void whenHeaderComplete(WebSocketRequestImpl request, WebSocketResponseImpl response) {
+ containerRuntime.onHeaderComplete(request.getRequest());
+ }
+
+ @Override
+ public void handle(WebSocketRequest request, WebSocketResponse response) {
+ containerRuntime.doHandle(request, response);
+ }
+ });
+ bootstrap.configuration().bannerEnabled(false).readBufferSize(1024 * 1024).debug(true);
+
+ containerRuntime.start(this.bootstrap.configuration());
+ bootstrap.setPort(containerConfig.getBindHttpPort()).start();
+ listeningHost = "127.0.0.1";
+// listeningHost = containerConfig.getBindAddress();
+ listeningPort = containerConfig.getBindHttpPort();
+ System.out.println("host: " + listeningHost + " port:" + listeningPort);
+ }
+
+ private String getRealmName() {
+ File realmProperties = containerConfig.getRealmProperties();
+ String fileName = realmProperties.getName();
+ int index;
+ if ((index = fileName.indexOf('.')) > -1) {
+ fileName = fileName.substring(0, index);
+ }
+ return fileName;
+ }
+
+ public void stop() throws LifecycleException {
+ try {
+ System.out.println("stop.....");
+ containerRuntime.stop();
+ bootstrap.shutdown();
+ } catch (Exception e) {
+ throw new LifecycleException("Could not stop container", e);
+ }
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jboss.arquillian.spi.client.container.DeployableContainer#deploy(org.jboss.shrinkwrap.descriptor.api.Descriptor)
+ */
+ public void deploy(Descriptor descriptor) throws DeploymentException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ /*
+ * (non-Javadoc)
+ *
+ * @see org.jboss.arquillian.spi.client.container.DeployableContainer#undeploy(org.jboss.shrinkwrap.descriptor.api.Descriptor)
+ */
+ public void undeploy(Descriptor descriptor) throws DeploymentException {
+ throw new UnsupportedOperationException("Not implemented");
+ }
+
+ public ProtocolMetaData deploy(final Archive> archive) throws DeploymentException {
+ try {
+ ServletContextRuntime app = appProvider.createApp(containerRuntime,archive);
+
+ app.start();
+
+ webAppContextProducer.set(app);
+ servletContextInstanceProducer.set(app.getServletContext());
+
+ HTTPContext httpContext = new HTTPContext(listeningHost, listeningPort);
+ for (ServletInfo servlet : app.getDeploymentInfo().getServlets().values()) {
+ httpContext.add(new Servlet(servlet.getServletName(), app.getContextPath()));
+ }
+ return new ProtocolMetaData().addContext(httpContext);
+ } catch (Exception e) {
+ throw new DeploymentException("Could not deploy " + archive.getName(), e);
+ }
+ }
+
+ private Mimetypes getMimeTypes() {
+ Map configuredMimeTypes = containerConfig.getMimeTypes();
+ Set> entries = configuredMimeTypes.entrySet();
+// MimeTypes mimeTypes = new MimeTypes();
+// entries.forEach(stringStringEntry ->
+// mimeTypes.addMimeMapping(stringStringEntry.getKey(), stringStringEntry.getValue()));
+ return Mimetypes.getInstance();
+ }
+
+ public void undeploy(Archive> archive) throws DeploymentException {
+ ServletContextRuntime app = webAppContextProducer.get();
+ if (app != null) {
+ app.stop();
+ }
+ }
+}
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/SmartServletExtension.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/SmartServletExtension.java
new file mode 100644
index 0000000000000000000000000000000000000000..dcb1896faa2e1e7e208ecc10d3d3052424988408
--- /dev/null
+++ b/testsuite/src/main/java/org/smartboot/servlet/testsuite/SmartServletExtension.java
@@ -0,0 +1,25 @@
+/*
+ * Copyright (C) [2022] smartboot [zhengjunweimail@163.com]
+ *
+ * 企业用户未经smartboot组织特别许可,需遵循AGPL-3.0开源协议合理合法使用本项目。
+ *
+ * Enterprise users are required to use this project reasonably
+ * and legally in accordance with the AGPL-3.0 open source agreement
+ * without special permission from the smartboot organization.
+ */
+package org.smartboot.servlet.testsuite;
+
+import org.jboss.arquillian.container.spi.client.container.DeployableContainer;
+import org.jboss.arquillian.core.spi.LoadableExtension;
+
+/**
+ * Jetty Embedded 10.x extension.
+ *
+ * @author Aslak Knutsen
+ */
+public class SmartServletExtension implements LoadableExtension {
+ @Override
+ public void register(ExtensionBuilder builder) {
+ builder.service(DeployableContainer.class, JettyEmbeddedContainer.class);
+ }
+}
diff --git a/testsuite/src/main/java/org/smartboot/servlet/testsuite/VersionUtil.java b/testsuite/src/main/java/org/smartboot/servlet/testsuite/VersionUtil.java
new file mode 100644
index 0000000000000000000000000000000000000000..d8419711cb50a2b3f58cdd70c9104a5a83d52d0f
--- /dev/null
+++ b/testsuite/src/main/java/org/smartboot/servlet/testsuite/VersionUtil.java
@@ -0,0 +1,93 @@
+/*
+ * JBoss, Home of Professional Open Source
+ * Copyright 2011 Red Hat Inc. and/or its affiliates and other contributors
+ * as indicated by the @authors tag. All rights reserved.
+ * See the copyright.txt in the distribution for a
+ * full listing of individual contributors.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ * http://www.apache.org/licenses/LICENSE-2.0
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+package org.smartboot.servlet.testsuite;
+
+/**
+ * VersionUtil
+ *
+ * @author Aslak Knutsen
+
+ */
+public class VersionUtil {
+ private VersionUtil() {
+ }
+
+ public static class Version implements Comparable {
+ private final Integer major;
+ private final Integer minor;
+
+ public Version(int major, int minor) {
+ this.major = major;
+ this.minor = minor;
+ }
+
+ /**
+ * @return the major
+ */
+ public int getMajor() {
+ return major;
+ }
+
+ /**
+ * @return the minor
+ */
+ public int getMinor() {
+ return minor;
+ }
+
+ /* (non-Javadoc)
+ * @see java.lang.Comparable#compareTo(java.lang.Object)
+ */
+ @Override
+ public int compareTo(Version o) {
+ int majorCompare = major.compareTo(o.major);
+ if (majorCompare == 0) {
+ return minor.compareTo(o.minor);
+ }
+ return majorCompare;
+ }
+ }
+
+ private static final String expression = "([0-9]{1,5})\\.([0-9]{1,5}).*";
+
+ public static Version extract(String version) {
+ if (version == null || !version.matches(expression)) {
+ return new Version(0, 0);
+ }
+
+ return new Version(
+ Integer.parseInt(version.replaceAll(expression, "$1")),
+ Integer.parseInt(version.replaceAll(expression, "$2")));
+ }
+
+ public static boolean isGreaterThenOrEqual(String greater, String then) {
+ return isGreaterThenOrEqual(extract(greater), extract(then));
+ }
+
+ public static boolean isGreaterThenOrEqual(Version greater, Version then) {
+ return greater.compareTo(then) >= 0;
+ }
+
+ public static boolean isLessThenOrEqual(String less, String then) {
+ return isLessThenOrEqual(extract(less), extract(then));
+ }
+
+ public static boolean isLessThenOrEqual(Version less, Version then) {
+ return less.compareTo(then) <= 0;
+ }
+}
diff --git a/testsuite/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension b/testsuite/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
new file mode 100644
index 0000000000000000000000000000000000000000..1b3da30ebbfda68bcf3c33c670c368b58594ca79
--- /dev/null
+++ b/testsuite/src/main/resources/META-INF/services/org.jboss.arquillian.core.spi.LoadableExtension
@@ -0,0 +1 @@
+org.smartboot.servlet.testsuite.SmartServletExtension
\ No newline at end of file
diff --git a/testsuite/src/main/webapp/WEB-INF/web.xml b/testsuite/src/main/webapp/WEB-INF/web.xml
deleted file mode 100644
index afba978e10df27e4a100dd58befb5d17b8238fa1..0000000000000000000000000000000000000000
--- a/testsuite/src/main/webapp/WEB-INF/web.xml
+++ /dev/null
@@ -1,34 +0,0 @@
-
-
-
-
- demoServlet
- org.smartboot.servlet.testsuite.DemoServlet
-
-
- demoServlet
- /demo
-
-
- demoServlet
- /pathMatch/*
-
-
- demoServlet
- *.do
-
-
-
- 30
-
-
- /index.jsp
- /index.htm
-
-
-
diff --git a/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/AppTest.java b/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/AppTest.java
new file mode 100644
index 0000000000000000000000000000000000000000..d59e2aebca2a5afc7bc558997b3ebbaf9b72823e
--- /dev/null
+++ b/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/AppTest.java
@@ -0,0 +1,32 @@
+/*
+ * Copyright (C) [2022] smartboot [zhengjunweimail@163.com]
+ *
+ * 企业用户未经smartboot组织特别许可,需遵循AGPL-3.0开源协议合理合法使用本项目。
+ *
+ * Enterprise users are required to use this project reasonably
+ * and legally in accordance with the AGPL-3.0 open source agreement
+ * without special permission from the smartboot organization.
+ */
+
+package org.smartboot.servlet.testsuite.test;
+
+import org.junit.jupiter.api.Test;
+import org.slf4j.LoggerFactory;
+
+/**
+ * Unit test for simple App.
+ */
+public class AppTest extends com.sun.ts.tests.servlet.api.jakarta_servlet_http.sessioncookieconfig.URLClient // com.sun.ts.tests.servlet.api.jakarta_servlet_http.sessioncookieconfig.URLClient // com.sun.ts.tests.servlet.spec.security.annotations.Client
+{
+
+ @Test
+ public void foo() throws Exception {
+ //
+ }
+
+ @Test
+ public void bar() throws Exception {
+ LoggerFactory loggerFactory;
+ }
+
+}
diff --git a/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/BastTest.java b/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/BastTest.java
deleted file mode 100644
index fd3c53c7945f34bf1f4289855031a51c516aaa9f..0000000000000000000000000000000000000000
--- a/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/BastTest.java
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- * Copyright (c) 2017-2021, org.smartboot. All rights reserved.
- * project name: smart-servlet
- * file name: BastTest.java
- * Date: 2021-05-14
- * Author: sandao (zhengjunweimail@163.com)
- *
- */
-package org.smartboot.servlet.testsuite.test;
-
-import com.alibaba.fastjson.JSONObject;
-import org.junit.Assert;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.smartboot.http.client.HttpClient;
-import org.smartboot.http.client.HttpResponse;
-
-import java.util.concurrent.ExecutionException;
-import java.util.concurrent.Future;
-
-/**
- * @author 三刀(zhengjunweimail@163.com)
- * @version V1.0 , 2021/5/14
- */
-public class BastTest {
- private static final Logger LOGGER = LoggerFactory.getLogger(ServletTest.class);
- private static final String CONTENT_PATH = "/demo";
-
- protected HttpClient getSmartClient() {
- HttpClient httpClient = new HttpClient("127.0.0.1", 8081);
- httpClient.connect();
- return httpClient;
- }
-
- protected HttpClient getTomcatClient() {
- HttpClient httpClient = new HttpClient("127.0.0.1", 8082);
- httpClient.connect();
- return httpClient;
- }
-
- protected void checkPath(String path, HttpClient smartClient, HttpClient tomcatClient) {
- Future smartFuture = smartClient.get(CONTENT_PATH + path).onSuccess(resp -> {
- LOGGER.info("smart-servlet response: {}", resp.body());
- }).send();
- Future tomcatFuture = tomcatClient.get(CONTENT_PATH + path).onSuccess(resp -> {
- LOGGER.info("tomcat response: {}", resp.body());
- }).send();
- try {
- checkResponse(smartFuture.get(), tomcatFuture.get());
- } catch (InterruptedException | ExecutionException e) {
- throw new RuntimeException(e);
- }
- }
-
- protected void checkResponse(HttpResponse smartResponse, HttpResponse tomcatResponse) {
- JSONObject smartJson = JSONObject.parseObject(smartResponse.body());
- JSONObject tomcatJson = JSONObject.parseObject(tomcatResponse.body());
- Assert.assertEquals("key 数量不一致", smartJson.size(), tomcatJson.size());
- for (String key : smartJson.keySet()) {
- Assert.assertEquals("key: " + key + " 匹配失败", smartJson.getString(key), tomcatJson.getString(key));
- }
- }
-}
diff --git a/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/ServletTest.java b/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/ServletTest.java
deleted file mode 100644
index 98023ddb6a709eec56ece12ac08d0b9f6b355d14..0000000000000000000000000000000000000000
--- a/testsuite/src/test/java/org/smartboot/servlet/testsuite/test/ServletTest.java
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * Copyright (c) 2017-2021, org.smartboot. All rights reserved.
- * project name: smart-servlet
- * file name: ServletTest.java
- * Date: 2021-05-14
- * Author: sandao (zhengjunweimail@163.com)
- *
- */
-
-package org.smartboot.servlet.testsuite.test;
-
-import org.junit.After;
-import org.junit.Before;
-import org.junit.Test;
-import org.slf4j.Logger;
-import org.slf4j.LoggerFactory;
-import org.smartboot.http.client.HttpClient;
-
-/**
- * @author 三刀(zhengjunweimail@163.com)
- * @version V1.0 , 2021/5/14
- */
-public class ServletTest extends BastTest {
- private static final Logger LOGGER = LoggerFactory.getLogger(ServletTest.class);
- private HttpClient smartClient;
- private HttpClient tomcatClient;
-
- @Before
- public void init() {
- smartClient = getSmartClient();
- tomcatClient = getTomcatClient();
- }
-
- /**
- * 精确匹配
- */
- @Test
- public void test1() {
- checkPath("/demo", smartClient, tomcatClient);
- }
-
- /**
- * 前缀匹配
- */
- @Test
- public void test2() {
- checkPath("/pathMatch", smartClient, tomcatClient);
- }
-
- /**
- * 前缀匹配
- */
- @Test
- public void test3() {
- checkPath("/pathMatch/1", smartClient, tomcatClient);
- }
-
- /**
- * 前缀匹配,包含query
- */
- @Test
- public void test4() {
- checkPath("/pathMatch/1?abc=c&bdc=4", smartClient, tomcatClient);
- }
-
-
- /**
- * 扩展名匹配,包含query
- */
- @Test
- public void test6() {
- checkPath("/pathMatch/abc.do?abc=c&bdc=4", smartClient, tomcatClient);
- }
-
- /**
- * 扩展名匹配,包含query
- */
- @Test
- public void test7() {
- checkPath("/abc/abc.do?abc=c&bdc=4", smartClient, tomcatClient);
- }
-
- /**
- * 扩展名匹配,包含query
- */
- @Test
- public void test8() {
- checkPath("/adb/abc/abc.do?abc=c&bdc=4", smartClient, tomcatClient);
- }
-
- @After
- public void destroy() {
- smartClient.close();
- tomcatClient.close();
- }
-}
diff --git a/testsuite/src/test/resources/arquillian.xml b/testsuite/src/test/resources/arquillian.xml
new file mode 100644
index 0000000000000000000000000000000000000000..0514924d66d57e03b71562587fb8144b4adada6c
--- /dev/null
+++ b/testsuite/src/test/resources/arquillian.xml
@@ -0,0 +1,48 @@
+
+
+
+
+
+
+
+
+
+
+ 8080
+ RFC2965
+ RFC2965
+ src/test/resources/default.properties
+ true
+
+ text/html iso-8859-1
+
+ true
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/testsuite/src/test/resources/default.properties b/testsuite/src/test/resources/default.properties
new file mode 100644
index 0000000000000000000000000000000000000000..1a441165817fef4f81a39470e19dc7ec87919da7
--- /dev/null
+++ b/testsuite/src/test/resources/default.properties
@@ -0,0 +1,27 @@
+#
+# This file defines users passwords and roles for a HashUserRealm
+#
+# The format is
+# : [, ...]
+#
+# Passwords may be clear text, obfuscated or checksummed. The class
+# org.eclipse.util.Password should be used to generate obfuscated
+# passwords or password checksums
+#
+# If DIGEST Authentication is used, the password must be in a recoverable
+# format, either plain text or OBF:.
+#
+jetty: MD5:164c88b302622e17050af52c89945d44,user
+admin: CRYPT:adpexzg3FUZAk,server-administrator,content-administrator,admin,user
+other: OBF:1xmk1w261u9r1w1c1xmq,user
+plain: plain,user
+user: password,user
+
+# This entry is for digest auth. The credential is a MD5 hash of username:realmname:password
+digest: MD5:6e120743ad67abfbc385bc2bb754e297,user
+
+j2ee: j2ee,Administrator,Employee
+javajoe: javajoe,VP,Manager
+
+# CN=CTS, OU=Java Software, O=Sun Microsystems Inc., L=Burlington, ST=MA, C=US
+CN\=CTS,\ OU\=Java\ Software,\ O\=Sun\ Microsystems\ Inc.,\ L\=Burlington,\ ST\=MA,\ C\=US=,,Administrator
diff --git a/testsuite/src/test/resources/servlet_spec_fragment_web/webdefault.xml b/testsuite/src/test/resources/servlet_spec_fragment_web/webdefault.xml
new file mode 100644
index 0000000000000000000000000000000000000000..e653db53398e3797b37d2af2bdc80f4484c122bc
--- /dev/null
+++ b/testsuite/src/test/resources/servlet_spec_fragment_web/webdefault.xml
@@ -0,0 +1,399 @@
+
+
+
+
+
+
+
+
+
+ Default web.xml file.
+ This file is applied to a Web application before its own WEB_INF/web.xml file
+
+
+
+
+
+
+
+ org.eclipse.jetty.servlet.listener.ELContextCleaner
+
+
+
+
+
+
+
+ org.eclipse.jetty.servlet.listener.IntrospectorCleaner
+
+
+
+
+
+
+
+
+
+
+
+ default
+ org.eclipse.jetty.servlet.DefaultServlet
+
+ acceptRanges
+ true
+
+
+ dirAllowed
+ true
+
+
+ welcomeServlets
+ exact
+
+
+ redirectWelcome
+ false
+
+
+ maxCacheSize
+ 256000000
+
+
+ maxCachedFileSize
+ 200000000
+
+
+ maxCachedFiles
+ 2048
+
+
+ etags
+ false
+
+
+ useFileMappedBuffer
+ true
+
+ 0
+
+
+
+ default
+ /
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ jsp
+ org.eclipse.jetty.jsp.JettyJspServlet
+
+ xpoweredBy
+ false
+
+
+ compilerTargetVM
+ 1.8
+
+
+ compilerSourceVM
+ 1.8
+
+ 0
+
+
+
+ jsp
+ *.jsp
+ *.jspf
+ *.jspx
+ *.xsp
+ *.JSP
+ *.JSPF
+ *.JSPX
+ *.XSP
+
+
+
+
+
+
+
+ 30
+
+
+
+
+
+
+
+ index.html
+ index.htm
+ index.jsp
+
+
+
+
+
+
+
+ ar
+ ISO-8859-6
+
+
+ be
+ ISO-8859-5
+
+
+ bg
+ ISO-8859-5
+
+
+ ca
+ ISO-8859-1
+
+
+ cs
+ ISO-8859-2
+
+
+ da
+ ISO-8859-1
+
+
+ de
+ ISO-8859-1
+
+
+ el
+ ISO-8859-7
+
+
+ en
+ ISO-8859-1
+
+
+ es
+ ISO-8859-1
+
+
+ et
+ ISO-8859-1
+
+
+ fi
+ ISO-8859-1
+
+
+ fr
+ ISO-8859-1
+
+
+ hr
+ ISO-8859-2
+
+
+ hu
+ ISO-8859-2
+
+
+ is
+ ISO-8859-1
+
+
+ it
+ ISO-8859-1
+
+
+ iw
+ ISO-8859-8
+
+
+ ja
+ Shift_JIS
+
+
+ ko
+ EUC-KR
+
+
+ lt
+ ISO-8859-2
+
+
+ lv
+ ISO-8859-2
+
+
+ mk
+ ISO-8859-5
+
+
+ nl
+ ISO-8859-1
+
+
+ no
+ ISO-8859-1
+
+
+ pl
+ ISO-8859-2
+
+
+ pt
+ ISO-8859-1
+
+
+ ro
+ ISO-8859-2
+
+
+ ru
+ ISO-8859-5
+
+
+ sh
+ ISO-8859-5
+
+
+ sk
+ ISO-8859-2
+
+
+ sl
+ ISO-8859-2
+
+
+ sq
+ ISO-8859-2
+
+
+ sr
+ ISO-8859-5
+
+
+ sv
+ ISO-8859-1
+
+
+ tr
+ ISO-8859-9
+
+
+ uk
+ ISO-8859-5
+
+
+ zh
+ GB2312
+
+
+ zh_TW
+ Big5
+
+
+
+
+
+
+
+
+ Disable TRACE
+ /
+ TRACE
+
+
+
+
+
+ Enable everything but TRACE
+ /
+ TRACE
+
+
+
+
+
diff --git a/testsuite/src/test/resources/simplelogger.properties b/testsuite/src/test/resources/simplelogger.properties
new file mode 100644
index 0000000000000000000000000000000000000000..c42caf080b586f0d20afc650927bc85f6661b3a4
--- /dev/null
+++ b/testsuite/src/test/resources/simplelogger.properties
@@ -0,0 +1,8 @@
+org.slf4j.simpleLogger.defaultLogLevel=info
+#org.slf4j.simpleLogger.log.org.eclipse.jetty=debug
+#org.slf4j.simpleLogger.log.org.eclipse.jetty.security=info
+#org.slf4j.simpleLogger.log.org.eclipse.jetty.annotations=debug
+org.slf4j.simpleLogger.log.org.eclipse.jetty.io=info
+org.slf4j.simpleLogger.log.org.eclipse.jetty.server=info
+org.slf4j.simpleLogger.log.org.eclipse.jetty.util=info
+