diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/HybridServer.java b/src/main/java/es/uvigo/esei/dai/hybridserver/HybridServer.java new file mode 100644 index 0000000000000000000000000000000000000000..d3a3912c05bea8820310473eaeffe06b02447bb0 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/HybridServer.java @@ -0,0 +1,88 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 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() { + 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; + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/Launcher.java b/src/main/java/es/uvigo/esei/dai/hybridserver/Launcher.java new file mode 100644 index 0000000000000000000000000000000000000000..8226d68e33e400eb25cf79074f5d0247714a9e82 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/Launcher.java @@ -0,0 +1,24 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver; + +public class Launcher { + public static void main(String[] args) { + // TODO Ejecutar el servidor + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPHeaders.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPHeaders.java new file mode 100644 index 0000000000000000000000000000000000000000..15aade40f84a763047e59047d07fca4d9505e182 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPHeaders.java @@ -0,0 +1,35 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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; + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPParseException.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPParseException.java new file mode 100644 index 0000000000000000000000000000000000000000..73a54ffb8084030f5e365ad97d329f9bd5c141d5 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPParseException.java @@ -0,0 +1,41 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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); + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequest.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequest.java new file mode 100644 index 0000000000000000000000000000000000000000..a1c7077084a561463448db35c4de9b3ba8d5415f --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequest.java @@ -0,0 +1,89 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 getResourceParameters() { + // TODO Completar + return null; + } + + public String getHttpVersion() { + // TODO Completar + return null; + } + + public Map 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 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(); + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequestMethod.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequestMethod.java new file mode 100644 index 0000000000000000000000000000000000000000..8ddef7b62a5d6f036b4b78165008e7f25cc5c7cf --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPRequestMethod.java @@ -0,0 +1,29 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.http; + +public enum HTTPRequestMethod { + HEAD, + GET, + POST, + PUT, + DELETE, + TRACE, + OPTIONS, + CONNECT; +} \ No newline at end of file diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponse.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponse.java new file mode 100644 index 0000000000000000000000000000000000000000..1f97a5f433ba696157cd660d5e2950747327c838 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponse.java @@ -0,0 +1,97 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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) { + } + + public String getVersion() { + // TODO Completar + return null; + } + + public void setVersion(String version) { + } + + public String getContent() { + // TODO Completar + return null; + } + + public void setContent(String content) { + } + + public Map 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() { + } + + public List 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); + } + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponseStatus.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponseStatus.java new file mode 100644 index 0000000000000000000000000000000000000000..e20ab1fe1ee3614e0f10b390ccdbcbee5ae983ca --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/HTTPResponseStatus.java @@ -0,0 +1,81 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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); + } +} diff --git a/src/main/java/es/uvigo/esei/dai/hybridserver/http/MIME.java b/src/main/java/es/uvigo/esei/dai/hybridserver/http/MIME.java new file mode 100644 index 0000000000000000000000000000000000000000..1e79d9d26742ecfa094d8acbcb6bbe14ac894fe0 --- /dev/null +++ b/src/main/java/es/uvigo/esei/dai/hybridserver/http/MIME.java @@ -0,0 +1,34 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/HybridServerFirstReleaseTestSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/HybridServerFirstReleaseTestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..0736a6d652b309884770501a85b3250d8bcda8dc --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/HybridServerFirstReleaseTestSuite.java @@ -0,0 +1,30 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver; + +import org.junit.platform.suite.api.SelectClasses; +import org.junit.platform.suite.api.Suite; + +@Suite +@SelectClasses({ + Week1TestSuite.class, + Week2TestSuite.class, + Week3TestSuite.class +}) +public class HybridServerFirstReleaseTestSuite { +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/Week1TestSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/Week1TestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..dfb32df348704236622b75640a694ea7fe4685c9 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/Week1TestSuite.java @@ -0,0 +1,33 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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.week1.HTTPRequestResponseSuite; +import es.uvigo.esei.dai.hybridserver.week1.WelcomePageTest; + +@Suite +@SelectClasses({ + WelcomePageTest.class, + HTTPRequestResponseSuite.class +}) +public class Week1TestSuite { + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/Week2TestSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/Week2TestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..b81b96d7ddd4d6150cc153f3b87e51f473c56b67 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/Week2TestSuite.java @@ -0,0 +1,33 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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.week1.HTTPRequestResponseSuite; +import es.uvigo.esei.dai.hybridserver.week2.ClientRequetsTest; + +@Suite +@SelectClasses({ + ClientRequetsTest.class, + HTTPRequestResponseSuite.class +}) +public class Week2TestSuite { + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/Week3TestSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/Week3TestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..d99e12f1e12c41ce5e5ec400f838899b4795e2ee --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/Week3TestSuite.java @@ -0,0 +1,33 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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.week3.ClientRequestsWithDatabaseTest; +import es.uvigo.esei.dai.hybridserver.week3.CustomPortTest; + +@Suite +@SelectClasses({ + CustomPortTest.class, + ClientRequestsWithDatabaseTest.class +}) +public class Week3TestSuite { + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/HybridServerTestCase.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/HybridServerTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..18d9d5483d0aea34bf4f1226bb43f2ab9e2bdd1f --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/HybridServerTestCase.java @@ -0,0 +1,47 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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(); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/JdbcTestCase.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/JdbcTestCase.java new file mode 100644 index 0000000000000000000000000000000000000000..d3341759279da22d60cf94c6540e350314804071 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/JdbcTestCase.java @@ -0,0 +1,86 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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(); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/MySqlJdbcDatabaseTester.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/MySqlJdbcDatabaseTester.java new file mode 100644 index 0000000000000000000000000000000000000000..ae782e3a8b125383b0e5d0e624e593c4ba1774cd --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/MySqlJdbcDatabaseTester.java @@ -0,0 +1,53 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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; + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/TestUtils.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/TestUtils.java new file mode 100644 index 0000000000000000000000000000000000000000..d789de8a6ed98d6ce605cc3a1c94cd011a41cf77 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/TestUtils.java @@ -0,0 +1,256 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 reader a un fichero en el classpath. + * + * @param filePath + * ruta absoluta del fichero, que debe estar en el classpath del sistema. + * @return reader 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 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 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 null 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 mapToNameValuePair(Map map) { + final Form form = Form.form(); + + for (Map.Entry entry : map.entrySet()) { + form.add(entry.getKey(), entry.getValue()); + } + + return form.build(); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Column.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Column.java new file mode 100644 index 0000000000000000000000000000000000000000..bce41129472b6991a681bbcb86d13d08dc97017a --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Column.java @@ -0,0 +1,51 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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; + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesAndCaseMatcher.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesAndCaseMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..a6f66d45cdb24bb9793bdcc0543caec4a708fc47 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesAndCaseMatcher.java @@ -0,0 +1,52 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 { + 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); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesMatcher.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..cb4a68836c5d89d0582df40c5653de35f8d3cb6d --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/EqualsToIgnoringSpacesMatcher.java @@ -0,0 +1,52 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 { + 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); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Table.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Table.java new file mode 100644 index 0000000000000000000000000000000000000000..ac89c0b8f8bf25e9a4393d6d57059f82e1cf7aee --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/Table.java @@ -0,0 +1,57 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 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 getColumns() { + return columns; + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHas.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHas.java new file mode 100644 index 0000000000000000000000000000000000000000..a980338e07e9966c873c9e3a50b8809346695ea7 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHas.java @@ -0,0 +1,57 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 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(); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHasNot.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHasNot.java new file mode 100644 index 0000000000000000000000000000000000000000..68d67532cb19f84c70047603703d6966f21b4dde --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableHasNot.java @@ -0,0 +1,57 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 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(); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableMatcher.java b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableMatcher.java new file mode 100644 index 0000000000000000000000000000000000000000..eca6224e234f8476f7cf96723839bdc710dfea35 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/utils/matchers/TableMatcher.java @@ -0,0 +1,56 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +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 { + 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); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPBadRequestsTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPBadRequestsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d7063cd4308c91de2327747932c121fb85c1a1e7 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPBadRequestsTest.java @@ -0,0 +1,86 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week1; + +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 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))); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETParametersTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETParametersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..436ba2e166aaae285e5c55727a6493e3704ffbfb --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETParametersTest.java @@ -0,0 +1,96 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourceTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourceTest.java new file mode 100644 index 0000000000000000000000000000000000000000..e1d083e779571e6e363c7603dbbfb1aff6645412 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourceTest.java @@ -0,0 +1,92 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourcesTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourcesTest.java new file mode 100644 index 0000000000000000000000000000000000000000..232c5d1421183f9b2ad9361e19a6fb01d3268790 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETResourcesTest.java @@ -0,0 +1,92 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETRootTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETRootTest.java new file mode 100644 index 0000000000000000000000000000000000000000..250bb0ef77fcb53f87f8f88c453da3bf9745d972 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestGETRootTest.java @@ -0,0 +1,87 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTEncodedTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTEncodedTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d2ac5b23c96ac8f5e5ba16faa55cda94af4bcc1c --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTEncodedTest.java @@ -0,0 +1,112 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTMultipleParametersTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTMultipleParametersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4383b9ff4e4756c86ab0f940db3ea0ff20fddfc6 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTMultipleParametersTest.java @@ -0,0 +1,97 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTOneParameterTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTOneParameterTest.java new file mode 100644 index 0000000000000000000000000000000000000000..6a32a042ba2775f8c03e51e6cbc2a2c7852469d6 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestPOSTOneParameterTest.java @@ -0,0 +1,89 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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))); + } + +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestResponseSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestResponseSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..7f17f7b3b20ce504bda2f9e957a9220357393ec5 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestResponseSuite.java @@ -0,0 +1,28 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week1; + +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.week1") +@IncludeTags({ "request", "response" }) +public class HTTPRequestResponseSuite { +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..360778c37e53d3797f114c535950785c04cd865b --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPRequestSuite.java @@ -0,0 +1,28 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week1; + +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.week1") +@IncludeTags("response") +public class HTTPRequestSuite { +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentTest.java new file mode 100644 index 0000000000000000000000000000000000000000..953144cabd33c473e63c170d168f217d7829a352 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentTest.java @@ -0,0 +1,38 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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"))); + } + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentWithHeadersTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentWithHeadersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..df38ae1ce3df5e7f3e2ec6791feb32814aaa2a86 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseNoContentWithHeadersTest.java @@ -0,0 +1,47 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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")); + } + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseSuite.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseSuite.java new file mode 100644 index 0000000000000000000000000000000000000000..79f5705c0979c8a8784b172a7f7a8707bbe8ac27 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseSuite.java @@ -0,0 +1,28 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week1; + +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.week1") +@IncludeTags("request") +public class HTTPResponseSuite { +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseTest.java new file mode 100644 index 0000000000000000000000000000000000000000..626020e14a72dea18aa036f06d31cd7fc65dcb2b --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseTest.java @@ -0,0 +1,39 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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"))); + } + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseWithHeadersTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseWithHeadersTest.java new file mode 100644 index 0000000000000000000000000000000000000000..42a4879e501e37e49b086f8d4e3597e44e940127 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/HTTPResponseWithHeadersTest.java @@ -0,0 +1,49 @@ +package es.uvigo.esei.dai.hybridserver.week1; + +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")); + } + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week1/WelcomePageTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/WelcomePageTest.java new file mode 100644 index 0000000000000000000000000000000000000000..5d5a5b050f0502ff97dc2a85b8a291e188ee6b5b --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week1/WelcomePageTest.java @@ -0,0 +1,36 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week1; + +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.RepeatedTest; + +import es.uvigo.esei.dai.hybridserver.utils.HybridServerTestCase; + +public class WelcomePageTest extends HybridServerTestCase { + + @RepeatedTest(10) + public void testWelcome() throws IOException { + assertThat(getContentWithType(url, "text/html"), containsString("Hybrid Server")); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week2/ClientRequetsTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week2/ClientRequetsTest.java new file mode 100644 index 0000000000000000000000000000000000000000..fa2bb48f893fbc5442a24a87c7be0fbda59decd2 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week2/ClientRequetsTest.java @@ -0,0 +1,159 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week2; + +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 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 = "Testing POST"; + + // 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 = "" + uuid + ""; + 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 = "Testing POST"; + + assertThat(postStatus(url + "html", singletonMap("xxx", content)), is(equalTo(400))); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week3/ClientRequestsWithDatabaseTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week3/ClientRequestsWithDatabaseTest.java new file mode 100644 index 0000000000000000000000000000000000000000..a2a9c9b66d9dedac3ee2e8cffac785dc9da07c54 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week3/ClientRequestsWithDatabaseTest.java @@ -0,0 +1,166 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week3; + +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 = "Testing POST"; + + // 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 = "" + uuid + ""; + 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 = "Testing POST"; + + assertThat(postStatus(url + "html", singletonMap("xxx", content)), is(equalTo(400))); + } +} diff --git a/src/test/java/es/uvigo/esei/dai/hybridserver/week3/CustomPortTest.java b/src/test/java/es/uvigo/esei/dai/hybridserver/week3/CustomPortTest.java new file mode 100644 index 0000000000000000000000000000000000000000..2fba0575d7130740b21536290a8e71130728f3f2 --- /dev/null +++ b/src/test/java/es/uvigo/esei/dai/hybridserver/week3/CustomPortTest.java @@ -0,0 +1,83 @@ +/** + * HybridServer + * Copyright (C) 2023 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 . + */ +package es.uvigo.esei.dai.hybridserver.week3; + +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()); + } +} diff --git a/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.dtd b/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.dtd new file mode 100644 index 0000000000000000000000000000000000000000..8cf9b83ae7648276801aab4249632ae6543a0213 --- /dev/null +++ b/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.dtd @@ -0,0 +1,8 @@ + + + + + diff --git a/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.xml b/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.xml new file mode 100644 index 0000000000000000000000000000000000000000..256e19838f1158c1cef1b0bea7487cd9b9c8bdfb --- /dev/null +++ b/src/test/resources/es/uvigo/esei/dai/hybridserver/week3/dataset.xml @@ -0,0 +1,24 @@ + + + + + + + + + + + + + +