Commit 9bdbb995 authored by Miguel Reboiro Jato's avatar Miguel Reboiro Jato

Initial commit

Initial commit with the basic project configuration and information.
parents
#Eclipse
.settings
.project
.classpath
#Maven
target
#General
bak
*.tar.gz
This diff is collapsed.
This diff is collapsed.
<?xml version="1.0" encoding="UTF-8"?>
<project xmlns="http://maven.apache.org/POM/4.0.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>hybrid-server</artifactId>
<groupId>es.uvigo.esei.dai</groupId>
<version>1.0.0-SNAPSHOT</version>
<name>Hybrid Server</name>
<description>Servidor Híbrido de Documentos Estructurados</description>
<url>https://sing-group.org/dt/gitlab/dai-2526/hybrid-server</url>
<contributors>
<contributor>
<name>Miguel Reboiro Jato</name>
<email>mrjato@uvigo.gal</email>
<organization>Escola Superior de Enxeñaría Informática -
Universidade de Vigo</organization>
<organizationUrl>https://esei.uvigo.es/</organizationUrl>
<roles>
<role>professor</role>
</roles>
</contributor>
</contributors>
<!-- developers>
<developer>
<id>[Login el email de la ESEI (p.ej. student@esei.uvigo.es => student)]</id>
<email>[xxx@esei.uvigo.es]</email>
<name>[Nombre completo]</name>
<organization>Escola Superior de Enxeñaría Informática - Universidade de
Vigo</organization>
<roles>
<role>student</role>
</roles>
</developer>
<developer>
<id>[Login el email de la ESEI (p.ej. student@esei.uvigo.es => student)]</id>
<email>[xxx@esei.uvigo.es]</email>
<name>[Nombre completo]</name>
<organization>Escola Superior de Enxeñaría Informática - Universidade de
Vigo</organization>
<roles>
<role>student</role>
</roles>
</developer>
</developers -->
<properties>
<group.name>[nombre_del_grupo]</group.name>
<maven.compiler.source>11</maven.compiler.source>
<maven.compiler.target>11</maven.compiler.target>
<project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
<project.reporting.outputEncoding>UTF-8</project.reporting.outputEncoding>
<main.class>es.uvigo.esei.dai.hybridserver.Launcher</main.class>
<!-- Dependencies versions -->
<jakarta.xml.ws-api.version>4.0.0</jakarta.xml.ws-api.version>
<jaxws-rt.version>4.0.3</jaxws-rt.version>
<mysql-connector-j.version>8.4.0</mysql-connector-j.version>
<!-- Test dependencies versions -->
<junit.jupiter.version>5.13.4</junit.jupiter.version>
<hamcrest.version>2.2</hamcrest.version>
<dbunit.version>2.7.3</dbunit.version>
<fluent-hc.version>4.5.14</fluent-hc.version>
<slf4j.version>2.0.7</slf4j.version>
<!-- Plugin versions -->
<exec-maven-plugin.version>3.1.0</exec-maven-plugin.version>
<maven-compiler-plugin.version>3.11.0</maven-compiler-plugin.version>
<maven-jxr-plugin.version>3.3.0</maven-jxr-plugin.version>
<maven-surefire-plugin.version>3.1.2</maven-surefire-plugin.version>
</properties>
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.junit</groupId>
<artifactId>junit-bom</artifactId>
<version>${junit.jupiter.version}</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
<dependencies>
<dependency>
<groupId>jakarta.xml.ws</groupId>
<artifactId>jakarta.xml.ws-api</artifactId>
<version>${jakarta.xml.ws-api.version}</version>
</dependency>
<dependency>
<groupId>com.mysql</groupId>
<artifactId>mysql-connector-j</artifactId>
<version>${mysql-connector-j.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>com.sun.xml.ws</groupId>
<artifactId>jaxws-rt</artifactId>
<version>${jaxws-rt.version}</version>
<scope>runtime</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-suite-engine</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.hamcrest</groupId>
<artifactId>hamcrest</artifactId>
<version>${hamcrest.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.dbunit</groupId>
<artifactId>dbunit</artifactId>
<version>${dbunit.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.apache.httpcomponents</groupId>
<artifactId>fluent-hc</artifactId>
<version>${fluent-hc.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-api</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.slf4j</groupId>
<artifactId>slf4j-simple</artifactId>
<version>${slf4j.version}</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<version>${maven-compiler-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.codehaus.mojo</groupId>
<artifactId>exec-maven-plugin</artifactId>
<version>${exec-maven-plugin.version}</version>
<configuration>
<mainClass>es.uvigo.esei.dai.hybridserver.Launcher</mainClass>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<configuration>
<testFailureIgnore>true</testFailureIgnore>
<includes>
<include>
es/uvigo/esei/dai/hybridserver/HybridServerFirstReleaseTestSuite.java
</include>
</includes>
</configuration>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
<executions>
<execution>
<phase>test</phase>
<goals>
<goal>report-only</goal>
</goals>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-assembly-plugin</artifactId>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>single</goal>
</goals>
<configuration>
<appendAssemblyId>false</appendAssemblyId>
<finalName>hybrid-server-${group.name}.r1</finalName>
<outputDirectory>${project.basedir}</outputDirectory>
<descriptors>
<descriptor>
src/main/assembly/assembly-first-release.xml
</descriptor>
</descriptors>
</configuration>
</execution>
</executions>
</plugin>
</plugins>
</build>
<reporting>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-report-plugin</artifactId>
<version>${maven-surefire-plugin.version}</version>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-jxr-plugin</artifactId>
<version>${maven-jxr-plugin.version}</version>
</plugin>
</plugins>
</reporting>
</project>
<assembly xmlns="http://maven.apache.org/ASSEMBLY/2.2.0"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/ASSEMBLY/2.2.0 http://maven.apache.org/xsd/assembly-2.2.0.xsd">
<id>first-release</id>
<formats>
<format>tar.gz</format>
</formats>
<includeBaseDirectory>false</includeBaseDirectory>
<fileSets>
<fileSet>
<directory>${project.build.sourceDirectory}</directory>
<outputDirectory>src/main/java</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.basedir}/src/main/resources</directory>
<outputDirectory>src/main/resources</outputDirectory>
</fileSet>
<fileSet>
<directory>${project.build.directory}/site</directory>
<outputDirectory>site</outputDirectory>
</fileSet>
</fileSets>
<files>
<file>
<source>pom.xml</source>
<outputDirectory>/</outputDirectory>
</file>
<file>
<source>ENTREGA1.md</source>
<outputDirectory>/</outputDirectory>
</file>
</files>
</assembly>
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
import java.io.IOException;
import java.net.ServerSocket;
import java.net.Socket;
import java.util.Map;
import java.util.Properties;
public class HybridServer implements AutoCloseable {
private static final int SERVICE_PORT = 8888;
private Thread serverThread;
private boolean stop;
public HybridServer() {
// TODO Inicializar con los parámetros por defecto
}
public HybridServer(Map<String, String> pages) {
// TODO Inicializar con la base de datos en memoria conteniendo "pages"
}
public HybridServer(Properties properties) {
// TODO Inicializar con los parámetros recibidos
}
public int getPort() {
return SERVICE_PORT;
}
public void start() {
this.serverThread = new Thread() {
@Override
public void run() {
try (final ServerSocket serverSocket = new ServerSocket(SERVICE_PORT)) {
while (true) {
try (Socket socket = serverSocket.accept()) {
if (stop)
break;
// TODO Responder al cliente
}
}
} catch (IOException e) {
e.printStackTrace();
}
}
};
this.stop = false;
this.serverThread.start();
}
@Override
public void close() {
// TODO Si es necesario, añadir el código para liberar otros recursos.
this.stop = true;
try (Socket socket = new Socket("localhost", SERVICE_PORT)) {
// Esta conexión se hace, simplemente, para "despertar" el hilo servidor
} catch (IOException e) {
throw new RuntimeException(e);
}
try {
this.serverThread.join();
} catch (InterruptedException e) {
throw new RuntimeException(e);
}
this.serverThread = null;
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
public class Launcher {
public static void main(String[] args) {
// TODO Ejecutar el servidor
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
public enum HTTPHeaders {
CONTENT_LENGTH("Content-Length"),
CONTENT_TYPE("Content-Type"),
HTTP_1_1("HTTP/1.1"),
CONNECTION("Connection");
private final String header;
private HTTPHeaders(String header) {
this.header = header;
}
public String getHeader() {
return this.header;
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
public class HTTPParseException extends Exception {
private static final long serialVersionUID = 1L;
public HTTPParseException() {
}
public HTTPParseException(String message) {
super(message);
}
public HTTPParseException(Throwable cause) {
super(cause);
}
public HTTPParseException(String message, Throwable cause) {
super(message, cause);
}
public HTTPParseException(String message, Throwable cause, boolean enableSuppression, boolean writableStackTrace) {
super(message, cause, enableSuppression, writableStackTrace);
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
import java.io.IOException;
import java.io.Reader;
import java.util.Map;
public class HTTPRequest {
public HTTPRequest(Reader reader) throws IOException, HTTPParseException {
// TODO Completar. Cualquier error en el procesado debe lanzar una HTTPParseException
}
public HTTPRequestMethod getMethod() {
// TODO Completar
return null;
}
public String getResourceChain() {
// TODO Completar
return null;
}
public String[] getResourcePath() {
// TODO Completar
return null;
}
public String getResourceName() {
// TODO Completar
return null;
}
public Map<String, String> getResourceParameters() {
// TODO Completar
return null;
}
public String getHttpVersion() {
// TODO Completar
return null;
}
public Map<String, String> getHeaderParameters() {
// TODO Completar
return null;
}
public String getContent() {
// TODO Completar
return null;
}
public int getContentLength() {
// TODO Completar
return -1;
}
@Override
public String toString() {
final StringBuilder sb = new StringBuilder().append(this.getMethod().name()).append(' ')
.append(this.getResourceChain()).append(' ').append(this.getHttpVersion()).append("\r\n");
for (Map.Entry<String, String> param : this.getHeaderParameters().entrySet()) {
sb.append(param.getKey()).append(": ").append(param.getValue()).append("\r\n");
}
if (this.getContentLength() > 0) {
sb.append("\r\n").append(this.getContent());
}
return sb.toString();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
public enum HTTPRequestMethod {
HEAD,
GET,
POST,
PUT,
DELETE,
TRACE,
OPTIONS,
CONNECT;
}
\ No newline at end of file
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
import java.io.IOException;
import java.io.StringWriter;
import java.io.Writer;
import java.util.List;
import java.util.Map;
public class HTTPResponse {
public HTTPResponse() {
// TODO Completar
}
public HTTPResponseStatus getStatus() {
// TODO Completar
return null;
}
public void setStatus(HTTPResponseStatus status) {
// TODO Completar
}
public String getVersion() {
// TODO Completar
return null;
}
public void setVersion(String version) {
// TODO Completar
}
public String getContent() {
// TODO Completar
return null;
}
public void setContent(String content) {
// TODO Completar
}
public Map<String, String> getParameters() {
// TODO Completar
return null;
}
public String putParameter(String name, String value) {
// TODO Completar
return null;
}
public boolean containsParameter(String name) {
// TODO Completar
return false;
}
public String removeParameter(String name) {
// TODO Completar
return null;
}
public void clearParameters() {
// TODO Completar
}
public List<String> listParameters() {
// TODO Completar
return null;
}
public void print(Writer writer) throws IOException {
// TODO Completar
}
@Override
public String toString() {
try (final StringWriter writer = new StringWriter()) {
this.print(writer);
return writer.toString();
} catch (IOException e) {
throw new RuntimeException("Unexpected I/O exception", e);
}
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
public enum HTTPResponseStatus {
S100("Continue"),
S101("Switching Protocols"),
S200("OK"),
S201("Created"),
S202("Accepted"),
S203("Non-Authoritative Information"),
S204("No Content"),
S205("Reset Content"),
S206("Partial Content"),
S300("Multiple Choices"),
S301("Moved Permanently"),
S302("Found"),
S303("See Other"),
S304("Not Modified"),
S305("Use Proxy"),
S307("Temporary Redirect"),
S400("Bad Request"),
S401("Unauthorized"),
S402("Payment Required"),
S403("Forbidden"),
S404("Not Found"),
S405("Method Not Allowed"),
S406("Not Acceptable"),
S407("Proxy Authentication Required"),
S408("Request Time-out"),
S409("Conflict"),
S410("Gone"),
S411("Length Required"),
S412("Precondition Failed"),
S413("Request Entity Too Large"),
S414("Request-URI Too Large"),
S415("Unsupported Media Type"),
S416("Requested range not satisfiable"),
S417("Expectation Failed"),
S500("Internal Server Error"),
S501("Not Implemented"),
S502("Bad Gateway"),
S503("Service Unavailable"),
S504("Gateway Time-out"),
S505("HTTP Version not supported");
private final int code;
private final String status;
private HTTPResponseStatus(String status) {
this.code = Integer.parseInt(this.name().substring(1));
this.status = status;
}
public int getCode() {
return this.code;
}
public String getStatus() {
return this.status;
}
public static HTTPResponseStatus forCode(int code) {
return HTTPResponseStatus.valueOf("S" + code);
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.http;
public enum MIME {
APPLICATION_XML("application/xml"),
FORM("application/x-www-form-urlencoded"),
TEXT_HTML("text/html");
private String mime;
private MIME(String mime) {
this.mime = mime;
}
public String getMime() {
return this.mime;
}
}
\ No newline at end of file
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
@Suite
@SelectClasses({
Step1TestSuite.class,
Step2TestSuite.class,
Step3TestSuite.class
})
public class HybridServerFirstReleaseTestSuite {
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
import es.uvigo.esei.dai.hybridserver.step1.HTTPRequestResponseSuite;
import es.uvigo.esei.dai.hybridserver.step1.WelcomePageTest;
@Suite
@SelectClasses({
WelcomePageTest.class,
HTTPRequestResponseSuite.class
})
public class Step1TestSuite {
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
import es.uvigo.esei.dai.hybridserver.step1.HTTPRequestResponseSuite;
import es.uvigo.esei.dai.hybridserver.step2.ClientRequetsTest;
@Suite
@SelectClasses({
ClientRequetsTest.class,
HTTPRequestResponseSuite.class
})
public class Step2TestSuite {
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver;
import org.junit.platform.suite.api.SelectClasses;
import org.junit.platform.suite.api.Suite;
import es.uvigo.esei.dai.hybridserver.step3.ClientRequestsWithDatabaseTest;
import es.uvigo.esei.dai.hybridserver.step3.CustomPortTest;
@Suite
@SelectClasses({
CustomPortTest.class,
ClientRequestsWithDatabaseTest.class
})
public class Step3TestSuite {
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step1;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Named.named;
import static org.junit.jupiter.params.provider.Arguments.arguments;
import java.io.StringReader;
import java.util.stream.Stream;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.Arguments;
import org.junit.jupiter.params.provider.MethodSource;
import es.uvigo.esei.dai.hybridserver.http.HTTPParseException;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
@Tag("request")
public class HTTPBadRequestsTest {
public static Stream<Arguments> badRequests() {
return Stream
.of(
arguments(
named(
"Missing method",
"/hello HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
),
arguments(
named(
"Missing resource",
"GET HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
),
arguments(
named(
"Missing version",
"GET /hello\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
),
arguments(
named(
"Missing first line",
"Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
),
arguments(
named(
"Invalid header",
"GET /hello/world.html?country=Spain&province=Ourense&city=Ourense HTTP/1.1\r\n"
+ "Host\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
),
arguments(
named(
"Missing new line after header",
"GET /hello/world.html?country=Spain&province=Ourense&city=Ourense HTTP/1.1"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n"
)
)
);
}
@ParameterizedTest
@MethodSource("badRequests")
public void testThatThrowsHTTPParseException(final String requestText) {
assertThrows(HTTPParseException.class, () -> new HTTPRequest(new StringReader(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.ArrayMatching.arrayContaining;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestGETParametersTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
requestText =
"GET /hello/world.html?country=Spain&province=Ourense&city=Ourense HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n";
request = new HTTPRequest(new StringReader(requestText + "\r\n"));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.GET)));
}
@Test
public final void testGetResourceChain() {
assertThat(
request.getResourceChain(), is(equalTo("/hello/world.html?country=Spain&province=Ourense&city=Ourense"))
);
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(arrayContaining("hello", "world.html")));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(equalTo("hello/world.html")));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(
request.getResourceParameters(),
allOf(hasEntry("country", "Spain"), hasEntry("province", "Ourense"), hasEntry("city", "Ourense"))
);
assertThat(request.getResourceParameters(), is(aMapWithSize(3)));
}
@Test
public final void testGetHeaderParameters() {
assertThat(
request.getHeaderParameters(),
allOf(hasEntry("Host", "localhost"), hasEntry("Accept", "text/html"), hasEntry("Accept-Encoding", "gzip,deflate"))
);
assertThat(request.getHeaderParameters(), is(aMapWithSize(3)));
}
@Test
public final void testGetContent() {
assertThat(request.getContent(), is(nullValue()));
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(0)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.ArrayMatching.arrayContaining;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestGETResourceTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"GET /hello HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n";
this.request = new HTTPRequest(new StringReader(this.requestText + "\r\n"));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.GET)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/hello")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(arrayContaining("hello")));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(equalTo("hello")));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(this.request.getResourceParameters(), is(anEmptyMap()));
}
@Test
public final void testGetHeaderParameters() {
assertThat(
request.getHeaderParameters(),
allOf(hasEntry("Host", "localhost"), hasEntry("Accept", "text/html"), hasEntry("Accept-Encoding", "gzip,deflate"))
);
assertThat(request.getHeaderParameters(), is(aMapWithSize(3)));
}
@Test
public final void testGetContent() {
assertThat(request.getContent(), is(nullValue()));
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(0)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.ArrayMatching.arrayContaining;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestGETResourcesTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"GET /hello/world.html HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Accept: text/html\r\n"
+ "Accept-Encoding: gzip,deflate\r\n";
this.request = new HTTPRequest(new StringReader(this.requestText + "\r\n"));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.GET)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/hello/world.html")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(arrayContaining("hello", "world.html")));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(equalTo("hello/world.html")));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(this.request.getResourceParameters(), is(anEmptyMap()));
}
@Test
public final void testGetHeaderParameters() {
assertThat(
request.getHeaderParameters(),
allOf(hasEntry("Host", "localhost"), hasEntry("Accept", "text/html"), hasEntry("Accept-Encoding", "gzip,deflate"))
);
assertThat(request.getHeaderParameters(), is(aMapWithSize(3)));
}
@Test
public final void testGetContent() {
assertThat(request.getContent(), is(nullValue()));
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(0)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.nullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsArrayWithSize.emptyArray;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.collection.IsMapWithSize.anEmptyMap;
import static org.hamcrest.text.IsEmptyString.emptyString;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestGETRootTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"GET / HTTP/1.1\r\n"
+ "Host: localhost\r\n";
this.request = new HTTPRequest(new StringReader(this.requestText + "\r\n"));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.GET)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(emptyArray()));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(emptyString()));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(this.request.getResourceParameters(), is(anEmptyMap()));
}
@Test
public final void testGetHeaderParameters() {
assertThat(request.getHeaderParameters(), hasEntry("Host", "localhost"));
assertThat(request.getHeaderParameters(), is(aMapWithSize(1)));
}
@Test
public final void testGetContent() {
assertThat(request.getContent(), is(nullValue()));
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(0)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsArrayWithSize.emptyArray;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.text.IsEmptyString.emptyString;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestPOSTEncodedTest {
private String requestText;
private String encodedRequestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"POST / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: 116\r\n"
+ "\r\n"
+ "message=Hello world!!&mensaje=¡¡Hola mundo!!&mensaxe=Ola mundo!!&mensagem=Olá mundo!!";
this.encodedRequestText =
"POST / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Content-Type: application/x-www-form-urlencoded\r\n"
+ "Content-Length: 116\r\n"
+ "\r\n"
+ "message=Hello+world%21%21&mensaje=%C2%A1%C2%A1Hola+mundo%21%21&mensaxe=Ola+mundo%21%21&mensagem=Ol%C3%A1+mundo%21%21";
this.request = new HTTPRequest(new StringReader(this.encodedRequestText));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.POST)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(emptyArray()));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(emptyString()));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(
request.getResourceParameters(),
allOf(
hasEntry("message", "Hello world!!"), hasEntry("mensaje", "¡¡Hola mundo!!"), hasEntry("mensaxe", "Ola mundo!!"),
hasEntry("mensagem", "Olá mundo!!")
)
);
assertThat(request.getResourceParameters(), is(aMapWithSize(4)));
}
@Test
public final void testGetHeaderParameters() {
assertThat(
request.getHeaderParameters(),
allOf(
hasEntry("Host", "localhost"), hasEntry("Content-Type", "application/x-www-form-urlencoded"),
hasEntry("Content-Length", "116")
)
);
assertThat(request.getHeaderParameters(), is(aMapWithSize(3)));
}
@Test
public final void testGetContent() {
assertThat(
request.getContent(),
is(equalTo("message=Hello world!!&mensaje=¡¡Hola mundo!!&mensaxe=Ola mundo!!&mensagem=Olá mundo!!"))
);
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(116)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.ArrayMatching.arrayContaining;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestPOSTMultipleParametersTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"POST /resource HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Content-Length: 85\r\n"
+ "\r\n"
+ "message=Hello world!!&mensaje=¡¡Hola mundo!!&mensaxe=Ola mundo!!&mensagem=Olá mundo!!";
this.request = new HTTPRequest(new StringReader(this.requestText));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.POST)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/resource")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(arrayContaining("resource")));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(equalTo("resource")));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(
request.getResourceParameters(),
allOf(
hasEntry("message", "Hello world!!"), hasEntry("mensaje", "¡¡Hola mundo!!"), hasEntry("mensaxe", "Ola mundo!!"),
hasEntry("mensagem", "Olá mundo!!")
)
);
assertThat(request.getResourceParameters(), is(aMapWithSize(4)));
}
@Test
public final void testGetHeaderParameters() {
assertThat(request.getHeaderParameters(), allOf(hasEntry("Host", "localhost"), hasEntry("Content-Length", "85")));
assertThat(request.getHeaderParameters(), is(aMapWithSize(2)));
}
@Test
public final void testGetContent() {
assertThat(
request.getContent(),
is(equalTo("message=Hello world!!&mensaje=¡¡Hola mundo!!&mensaxe=Ola mundo!!&mensagem=Olá mundo!!"))
);
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(85)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.allOf;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import static org.hamcrest.collection.IsArrayWithSize.emptyArray;
import static org.hamcrest.collection.IsMapContaining.hasEntry;
import static org.hamcrest.collection.IsMapWithSize.aMapWithSize;
import static org.hamcrest.text.IsEmptyString.emptyString;
import java.io.StringReader;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequest;
import es.uvigo.esei.dai.hybridserver.http.HTTPRequestMethod;
@Tag("request")
public class HTTPRequestPOSTOneParameterTest {
private String requestText;
private HTTPRequest request;
@BeforeEach
public void setUp() throws Exception {
this.requestText =
"POST / HTTP/1.1\r\n"
+ "Host: localhost\r\n"
+ "Content-Length: 21\r\n"
+ "\r\n"
+ "message=Hello world!!";
this.request = new HTTPRequest(new StringReader(this.requestText));
}
@Test
public final void testGetMethod() {
assertThat(request.getMethod(), is(equalTo(HTTPRequestMethod.POST)));
}
@Test
public final void testGetResourceChain() {
assertThat(request.getResourceChain(), is(equalTo("/")));
}
@Test
public final void testGetResourcePath() {
assertThat(request.getResourcePath(), is(emptyArray()));
}
@Test
public final void testGetResourceName() {
assertThat(request.getResourceName(), is(emptyString()));
}
@Test
public final void testGetHttpVersion() {
assertThat(request.getHttpVersion(), is(equalTo(HTTPHeaders.HTTP_1_1.getHeader())));
}
@Test
public final void testGetResourceParameters() {
assertThat(request.getResourceParameters(), hasEntry("message", "Hello world!!"));
assertThat(request.getResourceParameters(), is(aMapWithSize(1)));
}
@Test
public final void testGetHeaderParameters() {
assertThat(request.getHeaderParameters(), allOf(hasEntry("Host", "localhost"), hasEntry("Content-Length", "21")));
assertThat(request.getHeaderParameters(), is(aMapWithSize(2)));
}
@Test
public final void testGetContent() {
assertThat(request.getContent(), is(equalTo("message=Hello world!!")));
}
@Test
public final void testGetContentLength() {
assertThat(request.getContentLength(), is(equalTo(21)));
}
@Test
public final void testToString() {
assertThat(request.toString(), is(equalTo(requestText)));
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step1;
import org.junit.platform.suite.api.IncludeTags;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
@Suite
@SelectPackages("es.uvigo.esei.dai.hybridserver.step1")
@IncludeTags({ "request", "response" })
public class HTTPRequestResponseSuite {
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step1;
import org.junit.platform.suite.api.IncludeTags;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
@Suite
@SelectPackages("es.uvigo.esei.dai.hybridserver.step1")
@IncludeTags("response")
public class HTTPRequestSuite {
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponse;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponseStatus;
@Tag("response")
public class HTTPResponseNoContentTest {
private HTTPResponse response;
@BeforeEach
public void setUp() throws Exception {
this.response = new HTTPResponse();
this.response.setStatus(HTTPResponseStatus.S200);
this.response.setVersion(HTTPHeaders.HTTP_1_1.getHeader());
}
@Test
public final void testPrint() throws IOException {
try (final StringWriter writer = new StringWriter()) {
this.response.print(writer);
assertThat(writer.toString(), is(equalTo("HTTP/1.1 200 OK\r\n\r\n")));
}
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponse;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponseStatus;
@Tag("response")
public class HTTPResponseNoContentWithHeadersTest {
private HTTPResponse response;
@BeforeEach
public void setUp() throws Exception {
this.response = new HTTPResponse();
this.response.setStatus(HTTPResponseStatus.S200);
this.response.setVersion(HTTPHeaders.HTTP_1_1.getHeader());
this.response.putParameter("Content-Type", "text/html");
this.response.putParameter("Content-Encoding", "deflate");
this.response.putParameter("Content-Language", "en");
}
@Test
public final void testPrint() throws IOException {
try (final StringWriter writer = new StringWriter()) {
this.response.print(writer);
final String responseText = writer.toString();
assertThat(responseText, startsWith("HTTP/1.1 200 OK"));
assertThat(responseText, containsString("Content-Type: text/html"));
assertThat(responseText, containsString("Content-Encoding: deflate"));
assertThat(responseText, containsString("Content-Language: en"));
assertThat(responseText, endsWith("\r\n\r\n"));
}
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step1;
import org.junit.platform.suite.api.IncludeTags;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;
@Suite
@SelectPackages("es.uvigo.esei.dai.hybridserver.step1")
@IncludeTags("request")
public class HTTPResponseSuite {
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponse;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponseStatus;
@Tag("response")
public class HTTPResponseTest {
private HTTPResponse response;
@BeforeEach
public void setUp() throws Exception {
this.response = new HTTPResponse();
this.response.setContent("Hello World");
this.response.setStatus(HTTPResponseStatus.S200);
this.response.setVersion(HTTPHeaders.HTTP_1_1.getHeader());
}
@Test
public final void testPrint() throws IOException {
try (final StringWriter writer = new StringWriter()) {
this.response.print(writer);
assertThat(writer.toString(), is(equalTo("HTTP/1.1 200 OK\r\nContent-Length: 11\r\n\r\nHello World")));
}
}
}
package es.uvigo.esei.dai.hybridserver.step1;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.endsWith;
import static org.hamcrest.CoreMatchers.startsWith;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.io.StringWriter;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.http.HTTPHeaders;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponse;
import es.uvigo.esei.dai.hybridserver.http.HTTPResponseStatus;
@Tag("response")
public class HTTPResponseWithHeadersTest {
private HTTPResponse response;
@BeforeEach
public void setUp() throws Exception {
this.response = new HTTPResponse();
this.response.setContent("Hello World");
this.response.setStatus(HTTPResponseStatus.S200);
this.response.setVersion(HTTPHeaders.HTTP_1_1.getHeader());
this.response.putParameter("Content-Type", "text/html");
this.response.putParameter("Content-Encoding", "deflate");
this.response.putParameter("Content-Language", "en");
}
@Test
public final void testPrint() throws IOException {
try (final StringWriter writer = new StringWriter()) {
this.response.print(writer);
final String responseText = writer.toString();
assertThat(responseText, startsWith("HTTP/1.1 200 OK"));
assertThat(responseText, containsString("Content-Length: 11"));
assertThat(responseText, containsString("Content-Type: text/html"));
assertThat(responseText, containsString("Content-Encoding: deflate"));
assertThat(responseText, containsString("Content-Language: en"));
assertThat(responseText, endsWith("\r\n\r\nHello World"));
}
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step1;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContentWithType;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.utils.HybridServerTestCase;
public class WelcomePageTest extends HybridServerTestCase {
@Test
public void testWelcome() throws IOException {
for (int i = 0; i < 10; i++) {
assertThat(getContentWithType(url, "text/html"), containsString("Hybrid Server"));
}
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step2;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.deleteStatus;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.extractUUIDFromText;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContent;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContentWithType;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getStatus;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.postContent;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.postStatus;
import static java.util.Collections.singletonMap;
import static java.util.stream.Collectors.toMap;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.util.Map;
import java.util.stream.Stream;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.HybridServer;
import es.uvigo.esei.dai.hybridserver.utils.HybridServerTestCase;
public class ClientRequetsTest extends HybridServerTestCase {
private String invalidUUID;
private String[][] pages;
@BeforeEach
public void setup() {
this.invalidUUID = "12345678-abcd-1234-ab12-9876543210ab";
}
@Override
protected HybridServer createHybridServer() {
// El servidor debe tener las siguientes páginas en memoria
this.pages = new String[][] {
// { "uuid", "texto contenido por la página" }
{ "6df1047e-cf19-4a83-8cf3-38f5e53f7725", "This is the html page 6df1047e-cf19-4a83-8cf3-38f5e53f7725." },
{ "79e01232-5ea4-41c8-9331-1c1880a1d3c2", "This is the html page 79e01232-5ea4-41c8-9331-1c1880a1d3c2." },
{ "a35b6c5e-22d6-4707-98b4-462482e26c9e", "This is the html page a35b6c5e-22d6-4707-98b4-462482e26c9e." },
{ "3aff2f9c-0c7f-4630-99ad-27a0cf1af137", "This is the html page 3aff2f9c-0c7f-4630-99ad-27a0cf1af137." },
{ "77ec1d68-84e1-40f4-be8e-066e02f4e373", "This is the html page 77ec1d68-84e1-40f4-be8e-066e02f4e373." },
{ "8f824126-0bd1-4074-b88e-c0b59d3e67a3", "This is the html page 8f824126-0bd1-4074-b88e-c0b59d3e67a3." },
{ "c6c80c75-b335-4f68-b7a7-59434413ce6c", "This is the html page c6c80c75-b335-4f68-b7a7-59434413ce6c." },
{ "f959ecb3-6382-4ae5-9325-8fcbc068e446", "This is the html page f959ecb3-6382-4ae5-9325-8fcbc068e446." },
{ "2471caa8-e8df-44d6-94f2-7752a74f6819", "This is the html page 2471caa8-e8df-44d6-94f2-7752a74f6819." },
{ "fa0979ca-2734-41f7-84c5-e40e0886e408", "This is the html page fa0979ca-2734-41f7-84c5-e40e0886e408." } };
// Creación del servidor con las páginas ya en memoria.
final Map<String, String> pages = Stream.of(this.pages).collect(toMap(entry -> entry[0], entry -> entry[1]));
return new HybridServer(pages);
}
// Ejercicio 2
@Test
public void testGetHtmlPage() throws IOException {
for (String[] page : pages) {
final String uuid = page[0];
final String content = page[1];
final String pageURL = url + "html?uuid=" + uuid;
assertThat(getContentWithType(pageURL, "text/html"), containsString(content));
}
}
// Ejercicio 3
@Test
public void testGetHtmlList() throws IOException {
final String pageURL = url + "html";
final String content = getContentWithType(pageURL, "text/html");
for (String[] page : pages) {
final String uuid = page[0];
assertThat(content, containsString(uuid));
}
}
// Ejercicio 4
@Test
public void testPost() throws IOException {
final String content = "<html><body>Testing POST</body></html>";
// Envío de la página y extracción del uuid de la nueva página
final String responseContent = postContent(url + "html", singletonMap("html", content));
final String uuid = extractUUIDFromText(responseContent);
assertThat(uuid, is(notNullValue()));
// Verificación de que la página de respuesta contiene un enlace a la nueva página
final String uuidHyperlink = "<a href=\"html?uuid=" + uuid + "\">" + uuid + "</a>";
assertThat(responseContent, containsString(uuidHyperlink));
// Recuperación de la nueva página
final String url = this.url + "html?uuid=" + uuid;
assertThat("The new page couldn't be retrieved", getContent(url), is(equalTo(content)));
}
@Test
public void testDelete() throws IOException {
final String uuid = pages[4][0];
final String url = this.url + "html?uuid=" + uuid;
assertThat("The page couldn't be deleted", deleteStatus(url), is(equalTo(200)));
assertThat("The page already exists", getStatus(url), is(equalTo(404)));
}
// Ejercicio 5
@Test
public void testGetInvalidHtmlPage() throws IOException {
final String pageURL = url + "html?uuid=" + invalidUUID;
assertThat(getStatus(pageURL), is(equalTo(404)));
}
@Test
public void testGetInvalidResource() throws IOException {
final String pageURL = url + "xxx?uuid=" + pages[0];
assertThat(getStatus(pageURL), is(equalTo(400)));
}
@Test
public void testDeleteNonexistentPage() throws IOException {
final String pageURL = this.url + "html?uuid=" + invalidUUID;
assertThat(deleteStatus(pageURL), is(equalTo(404)));
}
@Test
public void testPostInvalidContent() throws IOException {
final String content = "<html><body>Testing POST</body></html>";
assertThat(postStatus(url + "html", singletonMap("xxx", content)), is(equalTo(400)));
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step3;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.deleteStatus;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.extractUUIDFromText;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContent;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContentWithType;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getStatus;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.postContent;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.postStatus;
import static es.uvigo.esei.dai.hybridserver.utils.matchers.TableMatcher.hasTable;
import static java.util.Collections.singletonMap;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.CoreMatchers.notNullValue;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.util.Properties;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import es.uvigo.esei.dai.hybridserver.HybridServer;
import es.uvigo.esei.dai.hybridserver.utils.JdbcTestCase;
public class ClientRequestsWithDatabaseTest extends JdbcTestCase {
private HybridServer server;
private String url;
private String invalidUUID;
private String[][] pages;
@BeforeEach
public void initAttributes() {
this.invalidUUID = "12345678-abcd-1234-ab12-9876543210ab";
// Estas páginas se insertan en la base de datos al inicio del test.
this.pages = new String[][] {
// { "uuid", "texto contenido por la página" }
{ "6df1047e-cf19-4a83-8cf3-38f5e53f7725", "This is the html page 6df1047e-cf19-4a83-8cf3-38f5e53f7725." },
{ "79e01232-5ea4-41c8-9331-1c1880a1d3c2", "This is the html page 79e01232-5ea4-41c8-9331-1c1880a1d3c2." },
{ "a35b6c5e-22d6-4707-98b4-462482e26c9e", "This is the html page a35b6c5e-22d6-4707-98b4-462482e26c9e." },
{ "3aff2f9c-0c7f-4630-99ad-27a0cf1af137", "This is the html page 3aff2f9c-0c7f-4630-99ad-27a0cf1af137." },
{ "77ec1d68-84e1-40f4-be8e-066e02f4e373", "This is the html page 77ec1d68-84e1-40f4-be8e-066e02f4e373." },
{ "8f824126-0bd1-4074-b88e-c0b59d3e67a3", "This is the html page 8f824126-0bd1-4074-b88e-c0b59d3e67a3." },
{ "c6c80c75-b335-4f68-b7a7-59434413ce6c", "This is the html page c6c80c75-b335-4f68-b7a7-59434413ce6c." },
{ "f959ecb3-6382-4ae5-9325-8fcbc068e446", "This is the html page f959ecb3-6382-4ae5-9325-8fcbc068e446." },
{ "2471caa8-e8df-44d6-94f2-7752a74f6819", "This is the html page 2471caa8-e8df-44d6-94f2-7752a74f6819." },
{ "fa0979ca-2734-41f7-84c5-e40e0886e408", "This is the html page fa0979ca-2734-41f7-84c5-e40e0886e408." } };
}
@BeforeEach
public void startServer() throws Exception {
final Properties properties = new Properties();
properties.setProperty("port", Integer.toString(8888));
properties.setProperty("numClients", "50");
properties.setProperty("db.url", getConnectionUrl());
properties.setProperty("db.user", getUsername());
properties.setProperty("db.password", getPassword());
this.server = new HybridServer(properties);
this.url = String.format("http://localhost:%d/", this.server.getPort());
this.server.start();
}
@AfterEach
public void stopServer() {
this.server.close();
}
@Test
public void testGetHtmlList() throws IOException {
final String pageURL = url + "html";
final String content = getContentWithType(pageURL, "text/html");
for (String[] page : pages) {
final String uuid = page[0];
assertThat(content, containsString(uuid));
}
}
@Test
public void testPost() throws Exception {
final String content = "<html><body>Testing POST</body></html>";
// Envío de la página y extracción del uuid de la nueva página
final String responseContent = postContent(url + "html", singletonMap("html", content));
final String uuid = extractUUIDFromText(responseContent);
assertThat(uuid, is(notNullValue()));
// Verificación de que la página de respuesta contiene un enlace a la nueva página
final String uuidHyperlink = "<a href=\"html?uuid=" + uuid + "\">" + uuid + "</a>";
assertThat(responseContent, containsString(uuidHyperlink));
// Recuperación de la nueva página
final String url = this.url + "html?uuid=" + uuid;
assertThat("The new page couldn't be retrieved", getContent(url), is(equalTo(content)));
// Comprobación de la inserción en la base de datos
assertThat(getConnection(), hasTable(getSchema(), "HTML").withColumn("uuid").withValue(uuid));
}
@Test
public void testDelete() throws Exception {
final String uuid = pages[4][0];
final String url = this.url + "html?uuid=" + uuid;
// Eliminación de la página
assertThat("The page couldn't be deleted", deleteStatus(url), is(equalTo(200)));
// Comprobación de la eliminación en la base de datos
assertThat(getConnection(), hasTable(getSchema(), "HTML").withColumn("uuid").withoutValue(uuid));
// Comprobación de la eliminación vía web
assertThat("The page already exists", getStatus(url), is(equalTo(404)));
}
// Ejercicio 5
@Test
public void testGetInvalidHtmlPage() throws IOException {
final String pageURL = url + "html?uuid=" + invalidUUID;
assertThat(getStatus(pageURL), is(equalTo(404)));
}
@Test
public void testGetInvalidResource() throws IOException {
final String pageURL = url + "xxx?uuid=" + pages[0];
assertThat(getStatus(pageURL), is(equalTo(400)));
}
@Test
public void testDeleteNonexistentPage() throws IOException {
final String pageURL = this.url + "html?uuid=" + invalidUUID;
assertThat(deleteStatus(pageURL), is(equalTo(404)));
}
@Test
public void testPostInvalidContent() throws IOException {
final String content = "<html><body>Testing POST</body></html>";
assertThat(postStatus(url + "html", singletonMap("xxx", content)), is(equalTo(400)));
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.step3;
import static es.uvigo.esei.dai.hybridserver.utils.TestUtils.getContentWithType;
import static org.hamcrest.CoreMatchers.containsString;
import static org.hamcrest.MatcherAssert.assertThat;
import java.io.IOException;
import java.util.Properties;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.Timeout;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
import es.uvigo.esei.dai.hybridserver.HybridServer;
@Timeout(5L)
public class CustomPortTest {
public HybridServer startServer() {
final HybridServer server = new HybridServer();
server.start();
return server;
}
public HybridServer startServer(int port) {
final Properties properties = new Properties();
properties.setProperty("port", Integer.toString(port));
properties.setProperty("numClients", "50");
properties.setProperty("db.url", "jdbc:mysql://localhost/hstestdb");
properties.setProperty("db.user", "dai");
properties.setProperty("db.password", "daipassword");
final HybridServer server = new HybridServer(properties);
server.start();
return server;
}
@Test
public void testWelcome() throws IOException {
try (HybridServer server = startServer()) {
final String url = getUrlForHome(server);
for (int i = 0; i < 10; i++) {
assertThat(getContentWithType(url, "text/html"), containsString("Hybrid Server"));
}
}
}
@ParameterizedTest
@ValueSource(ints = { 1234, 4242, 7315, 8833, 10201, 21386, 33217, 45450, 55881, 60000 })
public void testMultipleWelcome(int port) throws IOException {
try (HybridServer server = startServer(port)) {
final String url = getUrlForHome(server);
for (int i = 0; i < 10; i++) {
assertThat(getContentWithType(url, "text/html"), containsString("Hybrid Server"));
}
}
}
private String getUrlForHome(HybridServer server) {
return String.format("http://localhost:%d/", server.getPort());
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Timeout;
import es.uvigo.esei.dai.hybridserver.HybridServer;
@Timeout(5L)
public abstract class HybridServerTestCase {
protected HybridServer server;
protected String url;
@BeforeEach
public void startServer() {
this.server = createHybridServer();
this.url = String.format("http://localhost:%d/", this.server.getPort());
this.server.start();
}
@AfterEach
public void stopServer() {
this.server.close();
}
protected HybridServer createHybridServer() {
return new HybridServer();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils;
import java.sql.Connection;
import org.dbunit.IDatabaseTester;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.dataset.IDataSet;
import org.dbunit.dataset.xml.FlatXmlDataSetBuilder;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
public abstract class JdbcTestCase {
private IDatabaseTester tester;
private IDatabaseConnection connection;
@BeforeEach
public void setUpJdbc() throws Exception {
this.tester = this.createDatabaseTester();
this.connection = this.tester.getConnection();
this.tester.setDataSet(getDataSet());
this.tester.onSetup();
}
@AfterEach
public void tearDownJdbc() throws Exception {
try {
this.tester.onTearDown();
this.connection.close();
} finally {
this.connection = null;
}
}
protected IDatabaseTester createDatabaseTester() throws ClassNotFoundException {
return new MySqlJdbcDatabaseTester(getConnectionUrl(), getUsername(), getPassword());
}
protected String getSchema() {
return "hstestdb";
}
protected String getConnectionUrl() {
// Esta base de datos debe existir con las tablas creadas
// y el usuario debe tener acceso.
return "jdbc:mysql://localhost/" + this.getSchema();
}
protected String getUsername() {
return "hsdb";
}
protected String getPassword() {
return "hsdbpass";
}
protected IDataSet getDataSet() throws Exception {
return new FlatXmlDataSetBuilder()
.setMetaDataSetFromDtd(getClass().getResourceAsStream("dataset.dtd"))
.setCaseSensitiveTableNames(false)
.setColumnSensing(true).build(getClass().getResourceAsStream("dataset.xml"));
}
protected Connection getConnection() throws Exception {
return this.connection.getConnection();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils;
import org.dbunit.JdbcDatabaseTester;
import org.dbunit.database.DatabaseConfig;
import org.dbunit.database.IDatabaseConnection;
import org.dbunit.ext.mysql.MySqlDataTypeFactory;
import org.dbunit.ext.mysql.MySqlMetadataHandler;
public class MySqlJdbcDatabaseTester extends JdbcDatabaseTester {
private final static String MYSQL_DRIVER = "com.mysql.cj.jdbc.Driver";
public MySqlJdbcDatabaseTester(String connectionUrl) throws ClassNotFoundException {
super(MYSQL_DRIVER, connectionUrl);
}
public MySqlJdbcDatabaseTester(String connectionUrl, String username, String password) throws ClassNotFoundException {
super(MYSQL_DRIVER, connectionUrl, username, password);
}
public MySqlJdbcDatabaseTester(String connectionUrl, String username, String password, String schema)
throws ClassNotFoundException {
super(MYSQL_DRIVER, connectionUrl, username, password, schema);
}
@Override
public IDatabaseConnection getConnection() throws Exception {
final IDatabaseConnection connection = super.getConnection();
connection.getConfig().setProperty(DatabaseConfig.FEATURE_QUALIFIED_TABLE_NAMES, true);
connection.getConfig().setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new MySqlDataTypeFactory());
connection.getConfig().setProperty(DatabaseConfig.PROPERTY_METADATA_HANDLER, new MySqlMetadataHandler());
return connection;
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils;
import static org.junit.jupiter.api.Assertions.assertEquals;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.Reader;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.fluent.Form;
import org.apache.http.client.fluent.Request;
import org.apache.http.util.EntityUtils;
public final class TestUtils {
private TestUtils() {
}
/**
* Devuelve un <i>reader</i> a un fichero en el classpath.
*
* @param filePath
* ruta absoluta del fichero, que debe estar en el classpath del sistema.
* @return <i>reader</i> asociado al fichero o {@code null} si el fichero no existe.
*/
public static final Reader openReaderToFile(String filePath) {
return new InputStreamReader(TestUtils.class.getResourceAsStream(filePath));
}
/**
* Realiza una petición por GET y devuelve el contenido de la respuesta.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @return contenido de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static String getContent(String url) throws IOException {
final HttpResponse response = Request.Get(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.execute()
.returnResponse();
assertEquals(200, response.getStatusLine().getStatusCode());
return EntityUtils.toString(response.getEntity());
}
/**
* Realiza una petición por GET y devuelve el contenido de la respuesta.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @return contenido de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static String getContentWithType(String url, String contentType) throws IOException {
final HttpResponse response = Request.Get(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.execute()
.returnResponse();
assertEquals(200, response.getStatusLine().getStatusCode());
assertEquals(contentType, response.getEntity().getContentType().getValue());
return EntityUtils.toString(response.getEntity());
}
/**
* Realiza una petición por GET y devuelve el código de la respuesta HTTP.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @return código de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static int getStatus(String url) throws IOException {
return Request.Get(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.execute()
.returnResponse().getStatusLine().getStatusCode();
}
/**
* Realiza una petición por POST y devuelve el contenido de la respuesta.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @param content
* parámetros que se incluirán en la petición HTTP.
* @return contenido de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static String postContent(String url, Map<String, String> content) throws IOException {
final HttpResponse response = Request.Post(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.bodyForm(mapToNameValuePair(content))
.execute().returnResponse();
assertEquals(200, response.getStatusLine().getStatusCode());
return EntityUtils.toString(response.getEntity());
}
/**
* Realiza una petición por POST y devuelve el código de la respuesta.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @param content
* parámetros que se incluirán en la petición HTTP.
* @return código de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static int postStatus(String url, Map<String, String> content) throws IOException {
return Request.Post(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.bodyForm(mapToNameValuePair(content))
.execute().returnResponse().getStatusLine().getStatusCode();
}
/**
* Realiza una petición por DELETE y devuelve el código de la respuesta HTTP.
*
* La petición se hace en UTF-8 y solicitando el cierre de la conexión.
*
* Este método comprueba que el código de respuesta HTTP sea 200 OK.
*
* @param url
* URL de la página solicitada.
* @return código de la respuesta HTTP.
* @throws IOException
* en el caso de que se produzca un error de conexión.
*/
public static int deleteStatus(String url) throws IOException {
return Request.Delete(url)
.addHeader("Connection", "close")
.addHeader("Content-encoding", "UTF-8")
.execute().returnResponse().getStatusLine().getStatusCode();
}
/**
* Extrae un UUID de un texto. En el caso de que existan varios UUID en el texto se devolverá, únicamente, el primero
* de ellos.
*
* @param text
* texto del cual se quiere extraer el UUID.
* @return UUID encontrado en el texto o <code>null</code> en el caso de que no exista ninguno.
*/
public static String extractUUIDFromText(String text) {
final String patternString = "[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}";
final Pattern pattern = Pattern.compile(patternString);
final Matcher matcher = pattern.matcher(text);
return matcher.find() ? matcher.group() : null;
}
/**
* Lee por completo un recurso en el classpath, cuya ruta es relativa a una clase.
*
* @param clazz
* clase de referencia para obtener el recurso.
* @param resourcePath
* ruta al recurso relativa a la clase.
* @return contenido del flujo de entrada.
*/
public static String readResourceToString(Class<?> clazz, String resourcePath) {
return readToString(clazz.getResourceAsStream(resourcePath));
}
/**
* Lee por completo un InputStream y devuelve su contenido en forma de cadena de texto.
*
* @param is
* flujo de entrada del que se va a leer.
* @return contenido del flujo de entrada.
*/
public static String readToString(InputStream is) {
try (final Reader reader = new InputStreamReader(is)) {
final char[] buffer = new char[4096];
final StringBuilder sb = new StringBuilder();
int read;
while ((read = reader.read(buffer, 0, buffer.length)) != -1) {
sb.append(buffer, 0, read);
}
return sb.toString();
} catch (IOException ioe) {
throw new RuntimeException(ioe);
}
}
private static List<NameValuePair> mapToNameValuePair(Map<String, String> map) {
final Form form = Form.form();
for (Map.Entry<String, String> entry : map.entrySet()) {
form.add(entry.getKey(), entry.getValue());
}
return form.build();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
public class Column {
private final Table table;
private final String name;
private String value;
Column(Table table, String name) {
this.table = table;
this.name = name;
}
public TableHas withValue(String value) {
this.value = value;
this.table.addColumn(this);
return new TableHas(table);
}
public TableHasNot withoutValue(String value) {
this.value = value;
this.table.addColumn(this);
return new TableHasNot(table);
}
String getName() {
return name;
}
String getValue() {
return value;
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
/**
* Comprueba que dos cadenas de texto son iguales ignorando los espacios en blanco y las mayúsculas y minúsculas.
*/
public class EqualsToIgnoringSpacesAndCaseMatcher extends BaseMatcher<String> {
private final String expected;
public EqualsToIgnoringSpacesAndCaseMatcher(String expected) {
this.expected = expected;
}
@Override
public boolean matches(Object item) {
if (item instanceof String) {
final String text = (String) item;
return expected.replaceAll("\\s", "").equalsIgnoreCase(text.replaceAll("\\s", ""));
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("Strings are not equal ignoring whitespaces and case");
}
public static EqualsToIgnoringSpacesAndCaseMatcher equalsToIgnoringSpacesAndCase(String expected) {
return new EqualsToIgnoringSpacesAndCaseMatcher(expected);
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import org.hamcrest.BaseMatcher;
import org.hamcrest.Description;
/**
* Comprueba que dos cadenas de texto son iguales ignorando los espacios en blanco.
*/
public class EqualsToIgnoringSpacesMatcher extends BaseMatcher<String> {
private final String expected;
public EqualsToIgnoringSpacesMatcher(String expected) {
this.expected = expected;
}
@Override
public boolean matches(Object item) {
if (item instanceof String) {
final String text = (String) item;
return expected.replaceAll("\\s", "").equals(text.replaceAll("\\s", ""));
}
return false;
}
@Override
public void describeTo(Description description) {
description.appendText("Strings are not equal ignoring whitespaces");
}
public static EqualsToIgnoringSpacesMatcher equalsToIgnoringSpaces(String expected) {
return new EqualsToIgnoringSpacesMatcher(expected);
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import java.util.LinkedList;
import java.util.List;
public class Table {
private final String schema;
private final String name;
private final List<Column> columns;
Table(String schema, String name) {
this.schema = schema;
this.name = name;
this.columns = new LinkedList<>();
}
public Column withColumn(String name) {
return new Column(this, name);
}
void addColumn(Column column) {
this.columns.add(column);
}
String getSchema() {
return schema;
}
String getName() {
return name;
}
String getQualifiedName() {
return this.schema + "." + this.getName();
}
List<Column> getColumns() {
return columns;
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hamcrest.Description;
public class TableHas extends TableMatcher {
TableHas(Table table) {
super(table);
}
@Override
public void describeTo(Description description) {
description.appendText("No row matching query: " + this.toSQL());
}
@Override
protected String toSQL() {
final StringBuilder sb = new StringBuilder();
sb.append("SELECT * FROM ").append(table.getQualifiedName());
final List<Column> columns = table.getColumns();
if (!columns.isEmpty()) {
sb.append(" WHERE 1=1");
for (Column column : columns) {
sb.append(" AND ").append(column.getName()).append(" = \"").append(column.getValue()).append('"');
}
}
return sb.toString();
}
@Override
protected boolean checkResults(ResultSet results) throws SQLException {
return results.next();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.List;
import org.hamcrest.Description;
public class TableHasNot extends TableMatcher {
TableHasNot(Table table) {
super(table);
}
@Override
public void describeTo(Description description) {
description.appendText("There is a row matching query: " + this.toSQL());
}
@Override
protected String toSQL() {
final StringBuilder sb = new StringBuilder();
sb.append("SELECT * FROM ").append(table.getQualifiedName());
final List<Column> columns = table.getColumns();
if (!columns.isEmpty()) {
sb.append(" WHERE 1=1");
for (Column column : columns) {
sb.append(" AND ").append(column.getName()).append(" = \"").append(column.getValue()).append('"');
}
}
return sb.toString();
}
@Override
protected boolean checkResults(ResultSet results) throws SQLException {
return !results.next();
}
}
/**
* HybridServer
* Copyright (C) 2025 Miguel Reboiro-Jato
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
package es.uvigo.esei.dai.hybridserver.utils.matchers;
import java.sql.Connection;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import org.hamcrest.TypeSafeMatcher;
public abstract class TableMatcher extends TypeSafeMatcher<Connection> {
protected final Table table;
TableMatcher(Table table) {
this.table = table;
}
@Override
protected boolean matchesSafely(Connection connection) {
try (Statement statement = connection.createStatement()) {
try (ResultSet results = statement.executeQuery(this.toSQL())) {
return checkResults(results);
}
} catch (SQLException e) {
return false;
}
}
protected abstract String toSQL();
protected abstract boolean checkResults(ResultSet results) throws SQLException;
public static Table hasTable(String schema, String name) {
return new Table(schema, name);
}
public Column andColumn(String name) {
return new Column(this.table, name);
}
}
<?xml version="1.0" encoding="UTF-8"?>
<!ELEMENT dataset (hstestdb.HTML+)>
<!ELEMENT hstestdb.HTML EMPTY>
<!ATTLIST hstestdb.HTML
uuid CDATA #REQUIRED
content CDATA #REQUIRED
>
<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE dataset SYSTEM "dataset.dtd" >
<dataset>
<hstestdb.HTML uuid="6df1047e-cf19-4a83-8cf3-38f5e53f7725"
content="&lt;html&gt;&lt;body&gt;This is the html page 6df1047e-cf19-4a83-8cf3-38f5e53f7725.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="79e01232-5ea4-41c8-9331-1c1880a1d3c2"
content="&lt;html&gt;&lt;body&gt;This is the html page 79e01232-5ea4-41c8-9331-1c1880a1d3c2.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="a35b6c5e-22d6-4707-98b4-462482e26c9e"
content="&lt;html&gt;&lt;body&gt;This is the html page a35b6c5e-22d6-4707-98b4-462482e26c9e.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="3aff2f9c-0c7f-4630-99ad-27a0cf1af137"
content="&lt;html&gt;&lt;body&gt;This is the html page 3aff2f9c-0c7f-4630-99ad-27a0cf1af137.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="77ec1d68-84e1-40f4-be8e-066e02f4e373"
content="&lt;html&gt;&lt;body&gt;This is the html page 77ec1d68-84e1-40f4-be8e-066e02f4e373.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="8f824126-0bd1-4074-b88e-c0b59d3e67a3"
content="&lt;html&gt;&lt;body&gt;This is the html page 8f824126-0bd1-4074-b88e-c0b59d3e67a3.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="c6c80c75-b335-4f68-b7a7-59434413ce6c"
content="&lt;html&gt;&lt;body&gt;This is the html page c6c80c75-b335-4f68-b7a7-59434413ce6c.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="f959ecb3-6382-4ae5-9325-8fcbc068e446"
content="&lt;html&gt;&lt;body&gt;This is the html page f959ecb3-6382-4ae5-9325-8fcbc068e446.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="2471caa8-e8df-44d6-94f2-7752a74f6819"
content="&lt;html&gt;&lt;body&gt;This is the html page 2471caa8-e8df-44d6-94f2-7752a74f6819.&lt;/body&gt;&lt;/html&gt;" />
<hstestdb.HTML uuid="fa0979ca-2734-41f7-84c5-e40e0886e408"
content="&lt;html&gt;&lt;body&gt;This is the html page fa0979ca-2734-41f7-84c5-e40e0886e408.&lt;/body&gt;&lt;/html&gt;" />
</dataset>
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment