diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index 4ae7f8a..ef03a67 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -11,7 +11,7 @@ jobs:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- - name: Set up JDK 23
+ - name: Set up JDK 17
uses: actions/setup-java@v3
with:
java-version: '17'
diff --git a/frontendtest/index.html b/frontendtest/index.html
new file mode 100644
index 0000000..ff39d8c
--- /dev/null
+++ b/frontendtest/index.html
@@ -0,0 +1 @@
+
Welcome, {{username}}
\ No newline at end of file
diff --git a/frontendtest/login.html b/frontendtest/login.html
new file mode 100644
index 0000000..2d6d129
--- /dev/null
+++ b/frontendtest/login.html
@@ -0,0 +1 @@
+Login Page
\ No newline at end of file
diff --git a/frontendtest/register.html b/frontendtest/register.html
new file mode 100644
index 0000000..9e943d3
--- /dev/null
+++ b/frontendtest/register.html
@@ -0,0 +1,20 @@
+
+
+
+ Register
+
+
+Register
+
+
+Already have an account? Login here
+
+
diff --git a/pom.xml b/pom.xml
index 7c571a1..9ffc60e 100644
--- a/pom.xml
+++ b/pom.xml
@@ -65,8 +65,8 @@
maven-compiler-plugin
3.10.1
- 23
- 23
+ 17
+ 17
diff --git a/src/main/java/urlshortener/Server.java b/src/main/java/urlshortener/Server.java
index 59cca9c..184dcbe 100644
--- a/src/main/java/urlshortener/Server.java
+++ b/src/main/java/urlshortener/Server.java
@@ -18,8 +18,8 @@ public static void main(String[] args) throws Exception {
// Setup H2 database in memory
conn = DriverManager.getConnection(AppConfig.DB_URL, AppConfig.DB_USER, AppConfig.DB_PASS);
try (Statement stmt = conn.createStatement()) {
- stmt.execute("CREATE TABLE users (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
- }
+ stmt.execute("DROP TABLE IF EXISTS users");
+ stmt.execute("CREATE TABLE users (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))"); }
HttpServer server = HttpServer.create(new InetSocketAddress(AppConfig.PORT), 0);
server.createContext("/register", new RegisterHandler(getConn()));
@@ -27,7 +27,6 @@ public static void main(String[] args) throws Exception {
server.createContext("/index", new HomePageHandler(getConn()));
server.createContext("/", new HomePageHandler(getConn()));
server.createContext("/shorten", new UrlHandler());
- server.createContext("/s", new RedirectHandler());
server.setExecutor(null);
server.start();
diff --git a/src/main/java/urlshortener/database/Database.java b/src/main/java/urlshortener/database/Database.java
index e84af0b..a57df25 100644
--- a/src/main/java/urlshortener/database/Database.java
+++ b/src/main/java/urlshortener/database/Database.java
@@ -1,11 +1,14 @@
package urlshortener.database;
+import lombok.Setter;
+
import java.sql.*;
public class Database {
- private static final String JDBC_URL = "jdbc:h2:./shorten-db";
+ @Setter
+ private static String jdbcUrl = "jdbc:h2:./shorten-db"; // default
- static {
+ public static void initSchema() {
try (Connection conn = getConnection(); Statement stmt = conn.createStatement()) {
stmt.executeUpdate("CREATE TABLE IF NOT EXISTS urls (" +
"id IDENTITY PRIMARY KEY, " +
@@ -17,7 +20,7 @@ public class Database {
}
public static Connection getConnection() throws SQLException {
- return DriverManager.getConnection(JDBC_URL, "sa", "");
+ return DriverManager.getConnection(jdbcUrl, "sa", "");
}
public static void insertUrl(String shortCode, String longUrl) throws SQLException {
diff --git a/src/main/java/urlshortener/service/HomePageHandler.java b/src/main/java/urlshortener/service/HomePageHandler.java
index 73e242c..9cc5d6a 100644
--- a/src/main/java/urlshortener/service/HomePageHandler.java
+++ b/src/main/java/urlshortener/service/HomePageHandler.java
@@ -14,6 +14,7 @@
public class HomePageHandler implements HttpHandler {
private static Connection conn;
+ String fileLocation = "frontend/index.html";
public HomePageHandler(Connection conn) {
HomePageHandler.conn = conn;
@@ -32,8 +33,7 @@ public void handle(HttpExchange exchange) throws IOException {
exchange.sendResponseHeaders(405, -1);
return;
}
-
- String html = new String(Files.readAllBytes(Paths.get("frontend/index.html")));
+ String html = new String(Files.readAllBytes(Paths.get(fileLocation)));
html = html.replace("{{username}}", username);
byte[] response = html.getBytes();
diff --git a/src/test/java/urlshortener/FakeHttpExchange.java b/src/test/java/urlshortener/FakeHttpExchange.java
new file mode 100644
index 0000000..af762c9
--- /dev/null
+++ b/src/test/java/urlshortener/FakeHttpExchange.java
@@ -0,0 +1,71 @@
+package urlshortener;
+
+import com.sun.net.httpserver.Headers;
+import com.sun.net.httpserver.HttpContext;
+import com.sun.net.httpserver.HttpExchange;
+import com.sun.net.httpserver.HttpPrincipal;
+import lombok.Getter;
+
+import java.io.*;
+import java.net.InetSocketAddress;
+import java.net.URI;
+import java.nio.charset.StandardCharsets;
+import java.util.*;
+
+public class FakeHttpExchange extends HttpExchange {
+ private final ByteArrayOutputStream responseStream = new ByteArrayOutputStream();
+ private final Headers requestHeaders = new Headers();
+ private final Headers responseHeaders = new Headers();
+ private final URI uri;
+ private final String method;
+ private ByteArrayOutputStream responseBody = new ByteArrayOutputStream();
+ private InputStream requestBody = InputStream.nullInputStream();
+ @Getter
+ private int statusCode;
+
+
+ public FakeHttpExchange(String method, String uri) {
+ this.method = method;
+ this.uri = URI.create(uri);
+ }
+
+ @Override public Headers getRequestHeaders() { return requestHeaders; }
+ @Override public Headers getResponseHeaders() { return responseHeaders; }
+ @Override public URI getRequestURI() { return uri; }
+ @Override public String getRequestMethod() { return method; }
+ @Override public OutputStream getResponseBody() { return responseStream; }
+ @Override public InputStream getRequestBody() { return InputStream.nullInputStream(); }
+
+ @Override public HttpContext getHttpContext() { return null; }
+ @Override public void close() {}
+ @Override public InetSocketAddress getRemoteAddress() { return null; }
+
+ public String getResponseText() {
+ return responseBody.toString(StandardCharsets.UTF_8);
+ }
+
+ @Override
+ public int getResponseCode() {
+ return 0;
+ }
+
+ @Override
+ public void sendResponseHeaders(int code, long length) {
+ this.statusCode = code;
+ }
+
+ @Override public InetSocketAddress getLocalAddress() { return null; }
+ @Override public String getProtocol() { return null; }
+ @Override public Object getAttribute(String s) { return null; }
+ @Override public void setAttribute(String s, Object o) {}
+ @Override public void setStreams(InputStream inputStream, OutputStream outputStream) {}
+
+ @Override
+ public HttpPrincipal getPrincipal() {
+ return null;
+ }
+
+ public void setRequestBody(String body) {
+ this.requestBody = new ByteArrayInputStream(body.getBytes(StandardCharsets.UTF_8));
+ }
+}
diff --git a/src/test/java/urlshortener/ServerTest.java b/src/test/java/urlshortener/ServerTest.java
index 2d54720..3967d4c 100644
--- a/src/test/java/urlshortener/ServerTest.java
+++ b/src/test/java/urlshortener/ServerTest.java
@@ -19,7 +19,7 @@ static void setupDatabase() throws Exception {
// Use real in-memory H2 database for integration-style test
conn = DriverManager.getConnection("jdbc:h2:mem:testdb", "sa", "");
try (Statement stmt = conn.createStatement()) {
- stmt.execute("CREATE TABLE users (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
+ stmt.execute("CREATE TABLE userstest (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
}
}
@@ -27,7 +27,7 @@ static void setupDatabase() throws Exception {
void testUsersTableCreatedSuccessfully() throws Exception {
Statement stmt = conn.createStatement();
ResultSet rs = stmt.executeQuery("SELECT * FROM INFORMATION_SCHEMA.TABLES WHERE TABLE_NAME = 'USERS'");
- assertTrue(rs.next(), "Users table should exist");
+ assertTrue(rs.next(), "Userstest table should exist");
}
@Test
@@ -40,11 +40,11 @@ void testMockedConnectionTableCreation() throws Exception {
when(mockStmt.execute(anyString())).thenReturn(true);
// Run the DB setup logic
- mockConn.createStatement().execute("CREATE TABLE users (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
+ mockConn.createStatement().execute("CREATE TABLE userstest (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
// Verify SQL execution
verify(mockConn).createStatement();
- verify(mockStmt).execute("CREATE TABLE users (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
+ verify(mockStmt).execute("CREATE TABLE userstest (username VARCHAR(255) PRIMARY KEY, password VARCHAR(255))");
}
@Test
diff --git a/src/test/java/urlshortener/service/HomePageHandlerTest.java b/src/test/java/urlshortener/service/HomePageHandlerTest.java
new file mode 100644
index 0000000..477b11a
--- /dev/null
+++ b/src/test/java/urlshortener/service/HomePageHandlerTest.java
@@ -0,0 +1,76 @@
+package urlshortener.service;
+
+
+import org.junit.jupiter.api.*;
+import urlshortener.FakeHttpExchange;
+import urlshortener.config.AppConfig;
+import urlshortener.service.HomePageHandler;
+
+import java.io.ByteArrayOutputStream;
+import java.io.FileWriter;
+import java.io.PrintWriter;
+import java.nio.charset.StandardCharsets;
+import java.nio.file.*;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.SQLException;
+
+import static java.nio.charset.StandardCharsets.UTF_8;
+
+class HomePageHandlerTest {
+
+ Connection conn = DriverManager.getConnection("jdbc:h2:mem:testdb", "sa", "");
+
+ private static final String HTML_TEMPLATE =
+ "Welcome, {{username}} ";
+ private static final String INDEX_PATH = "frontendtest/index.html";
+
+ HomePageHandlerTest() throws SQLException {
+ }
+
+ @BeforeAll
+ static void setup() throws Exception {
+ Files.createDirectories(Paths.get("frontendtest"));
+ try (PrintWriter writer = new PrintWriter(new FileWriter(INDEX_PATH))) {
+ writer.write(HTML_TEMPLATE);
+ }
+ }
+
+// @AfterAll
+// static void cleanup() throws Exception {
+// Files.deleteIfExists(Paths.get(INDEX_PATH));
+// Files.deleteIfExists(Paths.get("frontendtest"));
+// }
+
+ @Test
+ void testHomePageHandlerWithUsernameQuery() throws Exception {
+ FakeHttpExchange exchange = new FakeHttpExchange("GET", "/?username=sa");
+ HomePageHandler handler = new HomePageHandler(conn);
+ handler.fileLocation = INDEX_PATH;
+
+ handler.handle(exchange);
+
+ // Properly read the actual HTML string from the output stream
+ String response = convertStreamToString((ByteArrayOutputStream) exchange.getResponseBody()); // custom method that does .toString(StandardCharsets.UTF_8)
+ Assertions.assertTrue(response.contains("Welcome, sa"));
+ }
+
+ @Test
+ void testHomePageHandlerWithoutQuery() throws Exception {
+ FakeHttpExchange exchange = new FakeHttpExchange("GET", "/");
+ HomePageHandler handler = new HomePageHandler(conn);
+ handler.fileLocation = INDEX_PATH;
+
+ handler.handle(exchange);
+
+ String response = convertStreamToString((ByteArrayOutputStream) exchange.getResponseBody()); // custom method that does .toString(StandardCharsets.UTF_8)
+ Assertions.assertFalse(response.contains("Welcome, sa"));
+ }
+
+ public String convertStreamToString(ByteArrayOutputStream outputStream) {
+ if (outputStream == null) {
+ return "";
+ }
+ return outputStream.toString(StandardCharsets.UTF_8);
+ }
+}
diff --git a/src/test/java/urlshortener/service/UrlHandlerTest.java b/src/test/java/urlshortener/service/UrlHandlerTest.java
new file mode 100644
index 0000000..94c8fc5
--- /dev/null
+++ b/src/test/java/urlshortener/service/UrlHandlerTest.java
@@ -0,0 +1,29 @@
+package urlshortener.service;
+
+import org.junit.jupiter.api.BeforeAll;
+import org.junit.jupiter.api.Test;
+import urlshortener.database.Database;
+
+import static org.junit.jupiter.api.Assertions.*;
+
+public class UrlHandlerTest {
+
+ @BeforeAll
+ static void setupDatabase() {
+ // Use in-memory DB for isolated testing
+ Database.setJdbcUrl("jdbc:h2:mem:testdb;DB_CLOSE_DELAY=-1");
+ Database.initSchema(); // Create `urls` table
+ }
+
+ @Test
+ void testInsertAndRetrieveUrl() throws Exception {
+ String shortCode = "abc123";
+ String longUrl = "https://example.com";
+
+ Database.insertUrl(shortCode, longUrl);
+ String fetched = Database.getLongUrl(shortCode);
+
+ assertEquals(longUrl, fetched);
+ }
+
+}