diff --git a/src/test/java/shine/auth/AuthWebSocketIntegrationTest.java b/src/test/java/shine/auth/AuthWebSocketIntegrationTest.java deleted file mode 100644 index 11b25c7..0000000 --- a/src/test/java/shine/auth/AuthWebSocketIntegrationTest.java +++ /dev/null @@ -1,524 +0,0 @@ -//package shine.auth; -// -//import com.fasterxml.jackson.databind.JsonNode; -//import com.fasterxml.jackson.databind.ObjectMapper; -//import org.junit.jupiter.api.Assertions; -//import org.junit.jupiter.api.Test; -//import utils.crypto.Ed25519Util; -// -//import java.net.URI; -//import java.net.http.HttpClient; -//import java.net.http.WebSocket; -//import java.nio.charset.StandardCharsets; -//import java.time.Duration; -//import java.util.Base64; -//import java.util.UUID; -//import java.util.concurrent.CompletableFuture; -//import java.util.concurrent.CompletionStage; -//import java.util.concurrent.TimeUnit; -// -///** -// * Интеграционные тесты авторификации по JSON-протоколу через WebSocket. -// * -// * Требуется запущенный сервер на: -// * ws://localhost:7070/ws -// * -// * Операции: -// * - AddUser -// * - AuthChallenge -// * - CreateAuthSession -// * - RefreshSession -// * - CloseActiveSession -// * - (позже) ListSessions -// */ -//public class AuthWebSocketIntegrationTest { -// -// private static final String WS_URI = "ws://localhost:7070/ws"; -// private static final ObjectMapper JSON = new ObjectMapper(); -// private static final HttpClient HTTP_CLIENT = HttpClient.newHttpClient(); -// -// /** Таймаут ожидания ответа от сервера в каждом helper-е (секунд). */ -// private static final long WS_TIMEOUT_SEC = 15; -// -// // ======================================================================== -// // DTO -// // ======================================================================== -// -// /** Тестовый пользователь. */ -// private static class TestUser { -// String login; -// long loginId; -// long bchId; -// -// byte[] loginPriv; -// byte[] devicePriv; -// -// String loginPubB64; -// String devicePubB64; -// } -// -// /** Токены созданной сессии. */ -// private static class SessionTokens { -// String sessionId; -// String sessionPwd; -// String storagePwd; -// } -// -// // ======================================================================== -// // ВСПОМОГАТЕЛЬНЫЕ МЕТОДЫ -// // ======================================================================== -// -// /** -// * Создать тестового пользователя с уникальным логином и ключами Ed25519. -// */ -// private TestUser createRandomUser() { -// TestUser u = new TestUser(); -// -// long ts = System.currentTimeMillis(); -// u.login = "anya_test_auth_scenario_" + ts; -// u.loginId = ts; // просто уникальный long -// u.bchId = ts % 1_000_000; // что-нибудь псевдоуникальное -// -// // Генерируем ключи детерминированно от логина — чтобы AddUser и Auth совпадали -// u.loginPriv = Ed25519Util.generatePrivateKeyFromString("login-key-" + u.login); -// u.devicePriv = Ed25519Util.generatePrivateKeyFromString("device-key-" + u.login); -// -// byte[] loginPub = Ed25519Util.derivePublicKey(u.loginPriv); -// byte[] devicePub = Ed25519Util.derivePublicKey(u.devicePriv); -// -// u.loginPubB64 = Ed25519Util.keyToBase64(loginPub); -// u.devicePubB64 = Ed25519Util.keyToBase64(devicePub); -// -// return u; -// } -// -// /** -// * Универсальный helper для одношаговой операции (AddUser, RefreshSession и т.п.). -// * Открывает WebSocket, отправляет JSON, ждёт один ответ. -// * -// * @param requestJson JSON-запрос -// * @param label ярлык для логов -// * @return JsonNode root ответа -// */ -// private JsonNode callSingleJsonOp(String requestJson, String label) throws Exception { -// System.out.println(); -// System.out.println("===== " + label + " ====="); -// System.out.println("📤 Request:"); -// System.out.println(requestJson); -// -// CompletableFuture future = new CompletableFuture<>(); -// -// HTTP_CLIENT.newWebSocketBuilder() -// .connectTimeout(Duration.ofSeconds(WS_TIMEOUT_SEC)) -// .buildAsync(URI.create(WS_URI), new WebSocket.Listener() { -// -// @Override -// public void onOpen(WebSocket webSocket) { -// webSocket.request(1); -// webSocket.sendText(requestJson, true); -// } -// -// @Override -// public CompletionStage onText(WebSocket webSocket, -// CharSequence data, -// boolean last) { -// String msg = data.toString(); -// System.out.println("📥 Response:"); -// System.out.println(msg); -// System.out.println("----------------------------------------"); -// try { -// JsonNode root = JSON.readTree(msg); -// future.complete(root); -// } catch (Exception e) { -// future.completeExceptionally(e); -// } finally { -// try { -// webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "test done"); -// } catch (Exception ignored) { -// } -// } -// webSocket.request(1); -// return CompletableFuture.completedFuture(null); -// } -// -// @Override -// public void onError(WebSocket webSocket, Throwable error) { -// if (!future.isDone()) { -// future.completeExceptionally(error); -// } -// } -// -// @Override -// public CompletionStage onClose(WebSocket webSocket, -// int statusCode, -// String reason) { -// if (!future.isDone()) { -// future.completeExceptionally(new IllegalStateException( -// "WebSocket closed before response. code=" + statusCode + ", reason=" + reason)); -// } -// return CompletableFuture.completedFuture(null); -// } -// }); -// -// return future.get(WS_TIMEOUT_SEC, TimeUnit.SECONDS); -// } -// -// /** -// * Helper для двухшагового сценария: -// * 1) AuthChallenge -// * 2) CreateAuthSession -// */ -// private SessionTokens createSessionForUser(TestUser user, String logPrefix) throws Exception { -// System.out.println(); -// System.out.println("===== " + logPrefix + " createSessionForUser: " + user.login + " ====="); -// -// CompletableFuture resultFuture = new CompletableFuture<>(); -// -// HTTP_CLIENT.newWebSocketBuilder() -// .connectTimeout(Duration.ofSeconds(WS_TIMEOUT_SEC)) -// .buildAsync(URI.create(WS_URI), new WebSocket.Listener() { -// -// int step = 0; -// WebSocket ws; -// String currentAuthNonce; -// -// @Override -// public void onOpen(WebSocket webSocket) { -// this.ws = webSocket; -// webSocket.request(1); -// -// // Шаг 1: AuthChallenge -// String reqId = "auth-challenge-" + UUID.randomUUID(); -// String json = """ -// { -// "op": "AuthChallenge", -// "requestId": "%s", -// "payload": { -// "login": "%s" -// } -// } -// """.formatted(reqId, user.login); -// -// System.out.println(); -// System.out.println(logPrefix + " 📤 [STEP1 AuthChallenge] Request:"); -// System.out.println(json); -// webSocket.sendText(json, true); -// } -// -// @Override -// public CompletionStage onText(WebSocket webSocket, -// CharSequence data, -// boolean last) { -// String msg = data.toString(); -// System.out.println(); -// System.out.println(logPrefix + " 📥 Incoming message (step " + step + "):"); -// System.out.println(msg); -// System.out.println("--------------------------------------------------"); -// -// try { -// if (step == 0) { -// // Ответ на AuthChallenge -// JsonNode root = JSON.readTree(msg); -// int status = root.path("status").asInt(); -// if (status != 200) { -// String code = root.path("payload").path("code").asText(); -// String message = root.path("payload").path("message").asText(); -// throw new IllegalStateException( -// "AuthChallenge failed: status=" + status + -// ", code=" + code + -// ", message=" + message); -// } -// -// currentAuthNonce = root.path("payload").path("authNonce").asText(null); -// if (currentAuthNonce == null || currentAuthNonce.isBlank()) { -// throw new IllegalStateException("AuthChallenge: empty authNonce in response"); -// } -// System.out.println(logPrefix + " 🔑 authNonce = " + currentAuthNonce); -// -// // Шаг 2: CreateAuthSession -// long timeMs = System.currentTimeMillis(); -// String signatureB64 = buildAuthorificatedSignature( -// user.devicePriv, -// currentAuthNonce, -// timeMs -// ); -// String storagePwd = generateFakeStoragePwd(); -// -// String reqId2 = "create-session-" + UUID.randomUUID(); -// String json2 = """ -// { -// "op": "CreateAuthSession", -// "requestId": "%s", -// "payload": { -// "storagePwd": "%s", -// "timeMs": %d, -// "signatureB64": "%s", -// "clientInfo": "AuthTestClient/1.0" -// } -// } -// """.formatted( -// reqId2, -// storagePwd, -// timeMs, -// signatureB64 -// ); -// -// System.out.println(); -// System.out.println(logPrefix + " 📤 [STEP2 CreateAuthSession] Request:"); -// System.out.println(json2); -// -// step = 1; -// webSocket.sendText(json2, true); -// } else if (step == 1) { -// // Ответ на CreateAuthSession -// JsonNode root = JSON.readTree(msg); -// int status = root.path("status").asInt(); -// if (status != 200) { -// String code = root.path("payload").path("code").asText(); -// String message = root.path("payload").path("message").asText(); -// throw new IllegalStateException( -// "CreateAuthSession failed: status=" + status + -// ", code=" + code + -// ", message=" + message); -// } -// -// String sessionId = root.path("payload").path("sessionId").asText(null); -// String sessionPwd = root.path("payload").path("sessionPwd").asText(null); -// if (sessionId == null || sessionPwd == null) { -// throw new IllegalStateException("CreateAuthSession: sessionId or sessionPwd is null"); -// } -// -// SessionTokens tokens = new SessionTokens(); -// tokens.sessionId = sessionId; -// tokens.sessionPwd = sessionPwd; -// tokens.storagePwd = null; // мы знаем, какой отправляли, при желании можно сохранить -// -// System.out.println(logPrefix + " 🆔 sessionId = " + sessionId); -// System.out.println(logPrefix + " 🔐 sessionPwd = " + sessionPwd); -// -// resultFuture.complete(tokens); -// -// try { -// webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "session created"); -// } catch (Exception ignored) { -// } -// } else { -// // Лишние сообщения — считаем ошибкой -// throw new IllegalStateException("Unexpected extra message on step=" + step); -// } -// } catch (Exception ex) { -// if (!resultFuture.isDone()) { -// resultFuture.completeExceptionally(ex); -// } -// try { -// webSocket.sendClose(WebSocket.NORMAL_CLOSURE, "error in test"); -// } catch (Exception ignored) { -// } -// } finally { -// webSocket.request(1); -// } -// -// return CompletableFuture.completedFuture(null); -// } -// -// @Override -// public void onError(WebSocket webSocket, Throwable error) { -// System.out.println(logPrefix + " ❌ WebSocket error: " + error.getMessage()); -// if (!resultFuture.isDone()) { -// resultFuture.completeExceptionally(error); -// } -// } -// -// @Override -// public CompletionStage onClose(WebSocket webSocket, -// int statusCode, -// String reason) { -// System.out.println(logPrefix + " 🔚 WebSocket closed. code=" + statusCode + ", reason=" + reason); -// if (!resultFuture.isDone()) { -// resultFuture.completeExceptionally( -// new IllegalStateException("Closed before session tokens were received")); -// } -// return CompletableFuture.completedFuture(null); -// } -// }); -// -// // ждём результат или ошибку -// return resultFuture.get(WS_TIMEOUT_SEC, TimeUnit.SECONDS); -// } -// -// /** -// * Собрать подпись над строкой "AUTHORIFICATED:" + timeMs + authNonce -// * приватным ключом устройства. -// */ -// private String buildAuthorificatedSignature(byte[] devicePrivKey, -// String authNonce, -// long timeMs) { -// String preimageStr = "AUTHORIFICATED:" + timeMs + authNonce; -// byte[] preimage = preimageStr.getBytes(StandardCharsets.UTF_8); -// byte[] sig = Ed25519Util.sign(preimage, devicePrivKey); -// return Base64.getEncoder().encodeToString(sig); -// } -// -// /** Просто base64 от 32 байт 1..32 — для storagePwd. */ -// private String generateFakeStoragePwd() { -// byte[] data = new byte[32]; -// for (int i = 0; i < data.length; i++) { -// data[i] = (byte) (i + 1); -// } -// return Base64.getEncoder().encodeToString(data); -// } -// -// // ======================================================================== -// // ТЕСТЫ -// // ======================================================================== -// -// /** -// * 1) Регистрируем пользователя через AddUser -// */ -// @Test -// void addUser_shouldSucceed() throws Exception { -// TestUser user = createRandomUser(); -// -// String reqId = "add-" + UUID.randomUUID(); -// String json = """ -// { -// "op": "AddUser", -// "requestId": "%s", -// "payload": { -// "login": "%s", -// "loginId": %d, -// "bchId": %d, -// "loginKey": "%s", -// "deviceKey": "%s", -// "bchLimit": 1000000 -// } -// } -// """.formatted( -// reqId, -// user.login, -// user.loginId, -// user.bchId, -// user.loginPubB64, -// user.devicePubB64 -// ); -// -// JsonNode resp = callSingleJsonOp(json, "TEST addUser_shouldSucceed"); -// int status = resp.path("status").asInt(); -// String code = resp.path("payload").path("code").asText(null); -// -// Assertions.assertEquals( -// 200, -// status, -// "Ожидался status=200 при AddUser, но сервер вернул: status=" + status + ", code=" + code -// ); -// -// System.out.println("✅ [TEST] AddUser прошёл успешно для login=" + user.login); -// } -// -// /** -// * 2) Создать пользователя и сразу сделать CreateAuthSession (AuthChallenge + CreateAuthSession). -// */ -// @Test -// void createSession_flow_shouldReturnSessionIdAndPwd() throws Exception { -// TestUser user = createRandomUser(); -// -// // Сначала регистрируем пользователя -// { -// String reqId = "add-" + UUID.randomUUID(); -// String json = """ -// { -// "op": "AddUser", -// "requestId": "%s", -// "payload": { -// "login": "%s", -// "loginId": %d, -// "bchId": %d, -// "loginKey": "%s", -// "deviceKey": "%s", -// "bchLimit": 1000000 -// } -// } -// """.formatted( -// reqId, -// user.login, -// user.loginId, -// user.bchId, -// user.loginPubB64, -// user.devicePubB64 -// ); -// JsonNode resp = callSingleJsonOp(json, "TEST createSession_flow / AddUser"); -// int status = resp.path("status").asInt(); -// Assertions.assertEquals(200, status, "AddUser должен вернуть 200"); -// } -// -// SessionTokens tokens = createSessionForUser(user, "[createSession_flow]"); -// Assertions.assertNotNull(tokens.sessionId, "sessionId не должен быть null"); -// Assertions.assertNotNull(tokens.sessionPwd, "sessionPwd не должен быть null"); -// -// System.out.println("✅ [TEST] Сессия успешно создана: sessionId=" + tokens.sessionId); -// } -// -// /** -// * 3) Сценарий с двумя сессиями (упрощённая версия): -// * - создаём пользователя -// * - создаём первую сессию -// * - создаём вторую сессию -// * - убеждаемся, что sessionId разные -// * -// * Полный цикл с ListSessions / CloseActiveSession можно будет нарастить поверх -// * этого теста, когда добавим JSON-обработчик Net_ListSessions. -// */ -// @Test -// void fullTwoSessionLifecycleScenario() throws Exception { -// TestUser user = createRandomUser(); -// -// // 1) AddUser -// String reqId = "add-" + UUID.randomUUID(); -// String jsonAdd = """ -// { -// "op": "AddUser", -// "requestId": "%s", -// "payload": { -// "login": "%s", -// "loginId": %d, -// "bchId": %d, -// "loginKey": "%s", -// "deviceKey": "%s", -// "bchLimit": 1000000 -// } -// } -// """.formatted( -// reqId, -// user.login, -// user.loginId, -// user.bchId, -// user.loginPubB64, -// user.devicePubB64 -// ); -// -// JsonNode addResp = callSingleJsonOp(jsonAdd, "SCENARIO fullTwoSessionLifecycle / AddUser"); -// int addStatus = addResp.path("status").asInt(); -// Assertions.assertEquals(200, addStatus, "AddUser должен вернуть 200"); -// -// System.out.println("✅ [SC] Пользователь создан: " + user.login); -// -// // 2) Первая сессия -// SessionTokens s1 = createSessionForUser(user, "[SC S1]"); -// // 3) Вторая сессия -// SessionTokens s2 = createSessionForUser(user, "[SC S2]"); -// -// Assertions.assertNotEquals( -// s1.sessionId, -// s2.sessionId, -// "Первая и вторая сессия должны иметь разные sessionId" -// ); -// -// System.out.println(); -// System.out.println("✅ [SC] Полный сценарий (упрощённый) успешно отработал:"); -// System.out.println(" session1 = " + s1.sessionId); -// System.out.println(" session2 = " + s2.sessionId); -// -// System.out.println("\nℹ️ ListSessions / CloseActiveSession / повторные проверки можно будет добавить, " + -// "когда JSON-обработчик Net_ListSessions будет реализован на сервере."); -// } -//} diff --git a/src/test/java/test/it/AddUserIT.java b/src/test/java/test/it/AddUserIT.java index 6cd9260..81089bf 100644 --- a/src/test/java/test/it/AddUserIT.java +++ b/src/test/java/test/it/AddUserIT.java @@ -8,38 +8,96 @@ import static org.junit.jupiter.api.Assertions.*; public class AddUserIT { + // ANSI цвета (работает в большинстве терминалов) + private static final String R = "\u001B[0m"; + private static final String G = "\u001B[32m"; + private static final String Y = "\u001B[33m"; + private static final String RED = "\u001B[31m"; + private static final String C = "\u001B[36m"; + + private static void line() { + System.out.println(C + "------------------------------------------------------------" + R); + } + + private static void title(String s) { + System.out.println(C + "\n============================================================" + R); + System.out.println(C + s + R); + System.out.println(C + "============================================================\n" + R); + } + + private static void ok(String s) { + System.out.println(G + "✅ " + s + R); + } + + private static void warn(String s) { + System.out.println(Y + "⚠️ " + s + R); + } + + private static void boom(String s) { + System.out.println(RED + "****************************************************************" + R); + System.out.println(RED + "❌ " + s + R); + System.out.println(RED + "****************************************************************" + R); + } + @Test void addUser_shouldReturn200_orAlreadyExists() { + title("AddUserIT: проверка добавления пользователя (200 OK) или 'уже существует' (409 USER_ALREADY_EXISTS)"); + System.out.println("Ожидание:"); + System.out.println(" - сервер принимает AddUser и возвращает:"); + System.out.println(" * 200 (пользователь создан/добавлен)"); + System.out.println(" * либо 409 + payload.code=USER_ALREADY_EXISTS (если уже есть)\n"); + try (WsTestClient client = new WsTestClient(TestConfig.WS_URI)) { String reqId = "it-adduser-1"; String reqJson = JsonBuilders.addUser(reqId); - TestLog.section("AddUserIT: AddUser"); - TestLog.req("AddUser requestId=" + reqId, reqJson); + System.out.println("📤 Отправляем AddUser запрос:"); + System.out.println(reqJson); + line(); String resp = client.request(reqId, reqJson, Duration.ofSeconds(5)); - TestLog.resp("AddUser responseId=" + reqId, resp); + + System.out.println("📥 Ответ сервера:"); + System.out.println(resp); + line(); int st = JsonParsers.status(resp); + System.out.println("ℹ️ status=" + st); boolean created = (st == 200); boolean already = (st == 409); if (already) { + // ВАЖНО: payload.code (не errorCode) String code = JsonParsers.errorCode(resp); - // если сервер кладет code в payload.code — парсер должен это поддерживать (см. ниже) - assertEquals("USER_ALREADY_EXISTS", code, - "Expected errorCode=USER_ALREADY_EXISTS, but got: " + code + ", resp=" + resp); + + System.out.println("ℹ️ server_code=" + code); + + // Если 409 пришёл, требуем понятный code + try { + assertEquals("USER_ALREADY_EXISTS", code, + "Expected code=USER_ALREADY_EXISTS, but got: " + code + ", resp=" + resp); + ok("409 получен корректно: USER_ALREADY_EXISTS"); + } catch (AssertionError ae) { + boom("409 получен, но code не тот. " + ae.getMessage()); + throw ae; + } } if (created) { - System.out.println("✅ AddUser: создан/добавлен (status=200)"); + ok("ТЕСТ ПРОЙДЕН: AddUser создан/добавлен (status=200)"); } else if (already) { - System.out.println("✅ AddUser: уже есть в системе (status=409, USER_ALREADY_EXISTS)"); + ok("ТЕСТ ПРОЙДЕН: AddUser уже есть в системе (status=409, USER_ALREADY_EXISTS)"); } else { + boom("Неожиданный status=" + st + ", resp=" + resp); fail("❌ AddUser: неожиданный status=" + st + ", resp=" + resp); } + + } catch (AssertionError | RuntimeException e) { + // чтобы “красным” было видно даже если Gradle/IDE печатает стек отдельно + boom("ТЕСТ УПАЛ: AddUserIT. Причина: " + e.getMessage()); + throw e; } } -} \ No newline at end of file +} diff --git a/src/test/java/test/it/SessionsIT.java b/src/test/java/test/it/SessionsIT.java index 0755beb..e9e89ee 100644 --- a/src/test/java/test/it/SessionsIT.java +++ b/src/test/java/test/it/SessionsIT.java @@ -10,15 +10,91 @@ import static org.junit.jupiter.api.Assertions.*; public class SessionsIT { + // ANSI цвета + private static final String R = "\u001B[0m"; + private static final String G = "\u001B[32m"; + private static final String Y = "\u001B[33m"; + private static final String RED = "\u001B[31m"; + private static final String C = "\u001B[36m"; + + private static void line() { + System.out.println(C + "------------------------------------------------------------" + R); + } + + private static void title(String s) { + System.out.println(C + "\n============================================================" + R); + System.out.println(C + s + R); + System.out.println(C + "============================================================\n" + R); + } + + private static void stepTitle(String s) { + System.out.println(C + "\n-------------------- " + s + " --------------------" + R); + } + + private static void ok(String s) { + System.out.println(G + "✅ " + s + R); + } + + private static void warn(String s) { + System.out.println(Y + "⚠️ " + s + R); + } + + private static void boom(String s) { + System.out.println(RED + "****************************************************************" + R); + System.out.println(RED + "❌ " + s + R); + System.out.println(RED + "****************************************************************" + R); + } + + private static void send(String op, String json) { + System.out.println("📤 [" + op + "] Request JSON:"); + System.out.println(json); + line(); + } + + private static void recv(String op, String json) { + System.out.println("📥 [" + op + "] Response JSON:"); + System.out.println(json); + line(); + } + + private static void assert200(String op, String resp) { + int st = JsonParsers.status(resp); + try { + assertEquals(200, st, op + ": expected status=200, but got=" + st + ", resp=" + resp); + ok(op + ": status=200"); + } catch (AssertionError ae) { + boom(op + ": ожидали 200, но получили " + st); + throw ae; + } + } + @BeforeAll static void ensureUserExists() { + title("SessionsIT (BeforeAll): предусловие — пользователь должен существовать (AddUser: 200 или 409)"); + try (WsTestClient client = new WsTestClient(TestConfig.WS_URI)) { String reqId = "it-adduser-beforeall"; - String resp = client.request(reqId, JsonBuilders.addUser(reqId), Duration.ofSeconds(5)); + String reqJson = JsonBuilders.addUser(reqId); + + send("AddUser(BeforeAll)", reqJson); + String resp = client.request(reqId, reqJson, Duration.ofSeconds(5)); + recv("AddUser(BeforeAll)", resp); + int st = JsonParsers.status(resp); // 200 или "уже есть" — ок - if (!(st == 200 || st == 409)) { + if (st == 200) { + ok("BeforeAll: пользователь создан/добавлен (status=200)"); + } else if (st == 409) { + String code = JsonParsers.errorCode(resp); + if ("USER_ALREADY_EXISTS".equals(code)) { + ok("BeforeAll: пользователь уже есть (status=409, USER_ALREADY_EXISTS)"); + } else { + boom("BeforeAll: status=409, но code неожиданный: " + code); + fail("User precondition failed. status=409, code=" + code + ", resp=" + resp); + } + } else { + boom("BeforeAll: предусловие не выполнено. status=" + st); fail("User precondition failed. status=" + st + ", resp=" + resp); } } @@ -26,141 +102,246 @@ public class SessionsIT { @Test void sessions_flow_shouldCreateListRefreshCloseCorrectly() { + title("SessionsIT: полный сценарий сессий (создать 2, проверить list, refresh/close, проверить очистку)"); + System.out.println("Ожидание сценария:"); + System.out.println(" 1) Создаём SESSION1 через AuthChallenge + CreateAuthSession"); + System.out.println(" 2) Создаём SESSION2 и делаем ListSessions внутри неё (AUTH_STATUS_USER) → должны быть SESSION1 и SESSION2"); + System.out.println(" 3) Делаем ListSessions в AUTH_IN_PROGRESS (подпись по nonce) → должны быть SESSION1 и SESSION2"); + System.out.println(" 4) Refresh SESSION1 (входим в AUTH_STATUS_USER) и Close SESSION2"); + System.out.println(" 5) Проверяем ListSessions (AUTH_IN_PROGRESS) → осталась только SESSION1"); + System.out.println(" 6) Закрываем SESSION1 в AUTH_IN_PROGRESS"); + System.out.println(" 7) Проверяем ListSessions → пусто\n"); + String s1Id, s1Pwd; String s2Id, s2Pwd; - // --- create session1 --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-1"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + try { + // --- create session1 --- + stepTitle("ШАГ 1: создать SESSION1 (AuthChallenge -> CreateAuthSession)"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-1"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge#1", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge#1", resp1); - String r2 = "it-create-1"; - String storagePwd = TestConfig.fakeStoragePwd(); - String resp2 = c.request(r2, JsonBuilders.createAuthSession(r2, nonce, storagePwd), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); + assert200("AuthChallenge#1", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce, "AuthChallenge#1: nonce must not be null"); + ok("AuthChallenge#1: authNonce получен: " + nonce); - s1Id = JsonParsers.sessionId(resp2); - s1Pwd = JsonParsers.sessionPwd(resp2); - assertNotNull(s1Id); - assertNotNull(s1Pwd); - } + String r2 = "it-create-1"; + String storagePwd = TestConfig.fakeStoragePwd(); + String req2 = JsonBuilders.createAuthSession(r2, nonce, storagePwd); + send("CreateAuthSession#1", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("CreateAuthSession#1", resp2); - // --- create session2 and list inside (AUTH_STATUS_USER) --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-2"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + assert200("CreateAuthSession#1", resp2); - String r2 = "it-create-2"; - String resp2 = c.request(r2, JsonBuilders.createAuthSession(r2, nonce, TestConfig.fakeStoragePwd()), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); + s1Id = JsonParsers.sessionId(resp2); + s1Pwd = JsonParsers.sessionPwd(resp2); + assertNotNull(s1Id, "CreateAuthSession#1: sessionId must not be null"); + assertNotNull(s1Pwd, "CreateAuthSession#1: sessionPwd must not be null"); + ok("SESSION1 получена: sessionId=" + s1Id + ", sessionPwd=[получен]"); + } - s2Id = JsonParsers.sessionId(resp2); - s2Pwd = JsonParsers.sessionPwd(resp2); - assertNotNull(s2Id); - assertNotNull(s2Pwd); + // --- create session2 and list inside (AUTH_STATUS_USER) --- + stepTitle("ШАГ 2: создать SESSION2 и ListSessions внутри неё (AUTH_STATUS_USER) → должны быть SESSION1+SESSION2"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-2"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge#2", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge#2", resp1); - // list inside session2 (у тебя это AUTH_STATUS_USER без подписи) - String r3 = "it-list-in-session2"; - String resp3 = c.request(r3, JsonBuilders.listSessions(r3, 0L, ""), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp3)); - List ids = JsonParsers.sessionIds(resp3); + assert200("AuthChallenge#2", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce); + ok("AuthChallenge#2: authNonce получен: " + nonce); - assertTrue(ids.contains(s1Id), "Must contain session1"); - assertTrue(ids.contains(s2Id), "Must contain session2"); - } + String r2 = "it-create-2"; + String req2 = JsonBuilders.createAuthSession(r2, nonce, TestConfig.fakeStoragePwd()); + send("CreateAuthSession#2", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("CreateAuthSession#2", resp2); - // --- list in AUTH_IN_PROGRESS (подпись по nonce) --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-list"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + assert200("CreateAuthSession#2", resp2); - long timeMs = System.currentTimeMillis(); - String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + s2Id = JsonParsers.sessionId(resp2); + s2Pwd = JsonParsers.sessionPwd(resp2); + assertNotNull(s2Id); + assertNotNull(s2Pwd); + ok("SESSION2 получена: sessionId=" + s2Id + ", sessionPwd=[получен]"); - String r2 = "it-list-auth-in-progress"; - String resp2 = c.request(r2, JsonBuilders.listSessions(r2, timeMs, sig), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); + // list inside session2 (у тебя это AUTH_STATUS_USER без подписи) + String r3 = "it-list-in-session2"; + String req3 = JsonBuilders.listSessions(r3, 0L, ""); + send("ListSessions(in SESSION2)", req3); + String resp3 = c.request(r3, req3, Duration.ofSeconds(5)); + recv("ListSessions(in SESSION2)", resp3); - List ids = JsonParsers.sessionIds(resp2); - assertTrue(ids.contains(s1Id)); - assertTrue(ids.contains(s2Id)); - } + assert200("ListSessions(in SESSION2)", resp3); + List ids = JsonParsers.sessionIds(resp3); + ok("ListSessions(in SESSION2): sessions=" + ids); - // --- refresh session1 and close session2 (from session1) --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + assertTrue(ids.contains(s1Id), "Must contain session1"); + assertTrue(ids.contains(s2Id), "Must contain session2"); + ok("Проверка OK: список содержит SESSION1 и SESSION2"); + } - String r1 = "it-refresh-s1"; - String resp1 = c.request(r1, JsonBuilders.refreshSession(r1, s1Id, s1Pwd), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - assertNotNull(JsonParsers.storagePwd(resp1)); + // --- list in AUTH_IN_PROGRESS (подпись по nonce) --- + stepTitle("ШАГ 3: ListSessions в AUTH_IN_PROGRESS (nonce+signature) → должны быть SESSION1+SESSION2"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-list"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge(list)", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge(list)", resp1); - String r2 = "it-close-s2"; - String resp2 = c.request(r2, JsonBuilders.closeActiveSession(r2, s2Id, 0L, ""), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); - } + assert200("AuthChallenge(list)", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce); + ok("AuthChallenge(list): authNonce=" + nonce); - // --- verify only session1 remains (AUTH_IN_PROGRESS list) --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-list2"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + long timeMs = System.currentTimeMillis(); + String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + ok("Подпись для AUTH_IN_PROGRESS: timeMs=" + timeMs + ", signatureB64=[сгенерирована]"); - long timeMs = System.currentTimeMillis(); - String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + String r2 = "it-list-auth-in-progress"; + String req2 = JsonBuilders.listSessions(r2, timeMs, sig); + send("ListSessions(AUTH_IN_PROGRESS)", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("ListSessions(AUTH_IN_PROGRESS)", resp2); - String r2 = "it-list-after-close-s2"; - String resp2 = c.request(r2, JsonBuilders.listSessions(r2, timeMs, sig), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); + assert200("ListSessions(AUTH_IN_PROGRESS)", resp2); - List ids = JsonParsers.sessionIds(resp2); - assertTrue(ids.contains(s1Id)); - assertFalse(ids.contains(s2Id)); - } + List ids = JsonParsers.sessionIds(resp2); + ok("ListSessions(AUTH_IN_PROGRESS): sessions=" + ids); - // --- close session1 in AUTH_IN_PROGRESS --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-close-s1"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + assertTrue(ids.contains(s1Id)); + assertTrue(ids.contains(s2Id)); + ok("Проверка OK: AUTH_IN_PROGRESS список содержит SESSION1 и SESSION2"); + } - long timeMs = System.currentTimeMillis(); - String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + // --- refresh session1 and close session2 (from session1) --- + stepTitle("ШАГ 4: Refresh SESSION1 (входим) и Close SESSION2 (из SESSION1)"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r2 = "it-close-s1"; - String resp2 = c.request(r2, JsonBuilders.closeActiveSession(r2, s1Id, timeMs, sig), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); - } + String r1 = "it-refresh-s1"; + String req1 = JsonBuilders.refreshSession(r1, s1Id, s1Pwd); + send("RefreshSession(SESSION1)", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("RefreshSession(SESSION1)", resp1); - // --- verify empty list --- - try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { - String r1 = "it-auth-list-empty"; - String resp1 = c.request(r1, JsonBuilders.authChallenge(r1), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp1)); - String nonce = JsonParsers.authNonce(resp1); - assertNotNull(nonce); + assert200("RefreshSession(SESSION1)", resp1); + assertNotNull(JsonParsers.storagePwd(resp1)); + ok("RefreshSession: storagePwd получен"); - long timeMs = System.currentTimeMillis(); - String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + String r2 = "it-close-s2"; + String req2 = JsonBuilders.closeActiveSession(r2, s2Id, 0L, ""); + send("CloseActiveSession(SESSION2)", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("CloseActiveSession(SESSION2)", resp2); - String r2 = "it-list-empty"; - String resp2 = c.request(r2, JsonBuilders.listSessions(r2, timeMs, sig), Duration.ofSeconds(5)); - assertEquals(200, JsonParsers.status(resp2)); + assert200("CloseActiveSession(SESSION2)", resp2); + ok("SESSION2 закрыта"); + } - List ids = JsonParsers.sessionIds(resp2); - assertTrue(ids.isEmpty(), "Sessions must be empty"); + // --- verify only session1 remains (AUTH_IN_PROGRESS list) --- + stepTitle("ШАГ 5: ListSessions(AUTH_IN_PROGRESS) → должна остаться только SESSION1"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-list2"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge(list2)", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge(list2)", resp1); + + assert200("AuthChallenge(list2)", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce); + + long timeMs = System.currentTimeMillis(); + String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + + String r2 = "it-list-after-close-s2"; + String req2 = JsonBuilders.listSessions(r2, timeMs, sig); + send("ListSessions(after close S2)", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("ListSessions(after close S2)", resp2); + + assert200("ListSessions(after close S2)", resp2); + + List ids = JsonParsers.sessionIds(resp2); + ok("ListSessions(after close S2): sessions=" + ids); + + assertTrue(ids.contains(s1Id)); + assertFalse(ids.contains(s2Id)); + ok("Проверка OK: осталась только SESSION1"); + } + + // --- close session1 in AUTH_IN_PROGRESS --- + stepTitle("ШАГ 6: Close SESSION1 в AUTH_IN_PROGRESS"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-close-s1"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge(close S1)", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge(close S1)", resp1); + + assert200("AuthChallenge(close S1)", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce); + + long timeMs = System.currentTimeMillis(); + String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + + String r2 = "it-close-s1"; + String req2 = JsonBuilders.closeActiveSession(r2, s1Id, timeMs, sig); + send("CloseActiveSession(SESSION1)", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("CloseActiveSession(SESSION1)", resp2); + + assert200("CloseActiveSession(SESSION1)", resp2); + ok("SESSION1 закрыта"); + } + + // --- verify empty list --- + stepTitle("ШАГ 7: ListSessions(AUTH_IN_PROGRESS) → ожидаем пустой список"); + try (WsTestClient c = new WsTestClient(TestConfig.WS_URI)) { + String r1 = "it-auth-list-empty"; + String req1 = JsonBuilders.authChallenge(r1); + send("AuthChallenge(list empty)", req1); + String resp1 = c.request(r1, req1, Duration.ofSeconds(5)); + recv("AuthChallenge(list empty)", resp1); + + assert200("AuthChallenge(list empty)", resp1); + String nonce = JsonParsers.authNonce(resp1); + assertNotNull(nonce); + + long timeMs = System.currentTimeMillis(); + String sig = JsonBuilders.signAuthorificated(nonce, timeMs); + + String r2 = "it-list-empty"; + String req2 = JsonBuilders.listSessions(r2, timeMs, sig); + send("ListSessions(empty)", req2); + String resp2 = c.request(r2, req2, Duration.ofSeconds(5)); + recv("ListSessions(empty)", resp2); + + assert200("ListSessions(empty)", resp2); + + List ids = JsonParsers.sessionIds(resp2); + ok("ListSessions(empty): sessions=" + ids); + + assertTrue(ids.isEmpty(), "Sessions must be empty"); + ok("Проверка OK: список пуст"); + } + + ok("ТЕСТ ПРОЙДЕН ЦЕЛИКОМ: SessionsIT (весь сценарий сессий выполнен успешно)"); + + } catch (AssertionError | RuntimeException e) { + boom("ТЕСТ УПАЛ: SessionsIT. Причина: " + e.getMessage()); + throw e; } } -} \ No newline at end of file +} diff --git a/src/test/java/test/it/TestLog.java b/src/test/java/test/it/TestLog.java new file mode 100644 index 0000000..08e3494 --- /dev/null +++ b/src/test/java/test/it/TestLog.java @@ -0,0 +1,32 @@ +package test.it; + +public final class TestLog { + private TestLog(){} + + // включается так: ./gradlew test -Dit.verbose=true + public static final boolean VERBOSE = true; //Boolean.parseBoolean(System.getProperty("it.verbose", "false")); + + public static void info(String s) { + if (VERBOSE) System.out.println(s); + } + + public static void section(String title) { + if (!VERBOSE) return; + System.out.println("\n\n=================================================="); + System.out.println(title); + System.out.println("==================================================\n"); + } + + public static void req(String title, String json) { + if (!VERBOSE) return; + System.out.println("\n📤 " + title); + System.out.println(json); + } + + public static void resp(String title, String json) { + if (!VERBOSE) return; + System.out.println("\n📥 " + title); + System.out.println(json); + System.out.println("-----------------------------------------------------"); + } +} \ No newline at end of file