AGENTS.md + code cleanup

This commit is contained in:
Oracle 2026-04-23 13:36:46 +02:00
parent 21b4169130
commit 9df61e0cd3
Signed by: Oracle
SSH key fingerprint: SHA256:x4/RtnjUyuHkdvmwNDsWSfcfF1V5PNr3OpriZqOvCX8
20 changed files with 365 additions and 910 deletions

View file

@ -5,13 +5,9 @@ import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.security.*;
import java.util.*;
import java.util.concurrent.CompletableFuture;
import static org.junit.jupiter.api.Assertions.*;
@ -32,17 +28,12 @@ class SecureCompletionClientE2ETest {
assertTrue(keyDir.mkdirs(), "Key directory should be created");
}
@AfterEach
void tearDown() {
// Cleanup is handled by @TempDir
}
// Full Lifecycle E2E Tests
@Test
@Order(1)
@DisplayName("E2E: Generate keys, save to disk, load in new client, validate")
void e2e_fullLifecycle_generateSaveLoadValidate() throws Exception {
void e2e_fullLifecycle_generateSaveLoadValidate() {
// Step 1: Generate keys and save to disk
SecureCompletionClient generateClient = new SecureCompletionClient(BASE_URL, false, true, 2);
generateClient.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -83,7 +74,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(2)
@DisplayName("E2E: Generate plaintext keys, load, and validate")
void e2e_plaintextKeys_generateLoadValidate() throws Exception {
void e2e_plaintextKeys_generateLoadValidate() {
// Generate plaintext keys (no password)
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -137,7 +128,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(4)
@DisplayName("E2E: HTTP status mapping covers all documented cases")
void e2e_httpStatusMapping_allCases() throws Exception {
void e2e_httpStatusMapping_allCases() {
SecureCompletionClient client = new SecureCompletionClient();
// 200 - success (null exception)
@ -187,7 +178,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(5)
@DisplayName("E2E: Retryable status codes match Constants.RETRYABLE_STATUS_CODES")
void e2e_retryableStatusCodes_matchConstants() throws Exception {
void e2e_retryableStatusCodes_matchConstants() {
SecureCompletionClient client = new SecureCompletionClient();
for (int code : Constants.RETRYABLE_STATUS_CODES) {
@ -200,13 +191,16 @@ class SecureCompletionClientE2ETest {
@Test
@Order(6)
@DisplayName("E2E: URL encoding of public key PEM")
void e2e_urlEncoding_publicKey() throws Exception {
void e2e_urlEncoding_publicKey() {
SecureCompletionClient client = new SecureCompletionClient();
String pemKey = "-----BEGIN PUBLIC KEY-----\nMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB" +
"IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBI" +
"kAMBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB" +
"IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBIjAN\n-----END PUBLIC KEY-----";
String pemKey = """
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBI\
kAMBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB\
IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBIjAN
-----END PUBLIC KEY-----""";
String encoded = client.urlEncodePublicKey(pemKey);
@ -266,7 +260,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(8)
@DisplayName("E2E: Client constructor parameters are correctly set")
void e2e_clientConstructor_parametersSetCorrectly() throws Exception {
void e2e_clientConstructor_parametersSetCorrectly() {
SecureCompletionClient client = new SecureCompletionClient(
"https://custom.api.com",
true,
@ -283,7 +277,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(9)
@DisplayName("E2E: Client strips trailing slashes from routerUrl")
void e2e_clientConstructor_stripsTrailingSlashes() throws Exception {
void e2e_clientConstructor_stripsTrailingSlashes() {
SecureCompletionClient client = new SecureCompletionClient(
"https://api.example.com///",
false, true, 1
@ -295,7 +289,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(10)
@DisplayName("E2E: Client uses default values when constructed with no args")
void e2e_clientConstructor_defaultValues() throws Exception {
void e2e_clientConstructor_defaultValues() {
SecureCompletionClient client = new SecureCompletionClient();
assertEquals(Constants.DEFAULT_BASE_URL, client.getRouterUrl());
@ -329,7 +323,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(12)
@DisplayName("E2E: Generate keys without saving produces in-memory keys")
void e2e_generateKeys_noSave_producesInMemoryKeys() throws Exception {
void e2e_generateKeys_noSave_producesInMemoryKeys() {
SecureCompletionClient client = new SecureCompletionClient();
client.generateKeys(false);
@ -338,13 +332,13 @@ class SecureCompletionClientE2ETest {
assertNotNull(privateKey, "Private key should be in memory");
assertNotNull(publicPem, "Public PEM should be in memory");
assertTrue(privateKey.getAlgorithm().equals("RSA"));
assertEquals("RSA", privateKey.getAlgorithm());
}
@Test
@Order(13)
@DisplayName("E2E: SecurityError is thrown for null key validation")
void e2e_nullKeyValidation_throwsSecurityError() throws Exception {
void e2e_nullKeyValidation_throwsSecurityError() {
SecureCompletionClient client = new SecureCompletionClient();
SecurityError error = assertThrows(SecurityError.class,
@ -357,7 +351,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(14)
@DisplayName("E2E: mapHttpStatus returns null for 200 status")
void e2e_mapHttpStatus_200_returnsNull() throws Exception {
void e2e_mapHttpStatus_200_returnsNull() {
SecureCompletionClient client = new SecureCompletionClient();
Exception result = client.mapHttpStatus(200, "Success");
@ -367,7 +361,7 @@ class SecureCompletionClientE2ETest {
@Test
@Order(15)
@DisplayName("E2E: mapHttpStatus includes response body in error message")
void e2e_mapHttpStatus_includesResponseBody() throws Exception {
void e2e_mapHttpStatus_includesResponseBody() {
SecureCompletionClient client = new SecureCompletionClient();
Exception e400 = client.mapHttpStatus(400, "Invalid parameter: email");

View file

@ -5,12 +5,7 @@ import ai.nomyo.util.Pass2Key;
import org.junit.jupiter.api.*;
import org.junit.jupiter.api.io.TempDir;
import javax.crypto.BadPaddingException;
import javax.crypto.IllegalBlockSizeException;
import javax.crypto.NoSuchPaddingException;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigInteger;
import java.nio.file.Files;
import java.nio.file.Path;
@ -51,7 +46,7 @@ class SecureCompletionClientTest {
assertNotNull(privateKey, "Private key should not be null");
assertNotNull(publicPemKey, "Public PEM key should not be null");
assertTrue(privateKey.getAlgorithm().equals("RSA"), "Key algorithm should be RSA");
assertEquals("RSA", privateKey.getAlgorithm(), "Key algorithm should be RSA");
assertTrue(publicPemKey.contains("BEGIN PUBLIC KEY"), "Public key should be valid PEM");
}
@ -81,8 +76,8 @@ class SecureCompletionClientTest {
client2.generateKeys(false);
PrivateKey secondKey = client2.getPrivateKey();
assertNotEquals(firstKey.getEncoded().length, secondKey.getEncoded().length,
"Different keys should have different encoded lengths");
assertNotEquals(java.util.Arrays.hashCode(firstKey.getEncoded()), java.util.Arrays.hashCode(secondKey.getEncoded()),
"Different keys should have different encoded content");
}
// Key Generation with File Save Tests
@ -90,7 +85,7 @@ class SecureCompletionClientTest {
@Test
@Order(4)
@DisplayName("generateKeys with saveToFile=true should create key files")
void generateKeys_withSaveToFile_shouldCreateKeyFiles(@TempDir Path tempDir) throws Exception {
void generateKeys_withSaveToFile_shouldCreateKeyFiles(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -124,7 +119,7 @@ class SecureCompletionClientTest {
@Test
@Order(6)
@DisplayName("generateKeys should not overwrite existing key files")
void generateKeys_shouldNotOverwriteExistingKeys(@TempDir Path tempDir) throws Exception {
void generateKeys_shouldNotOverwriteExistingKeys(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -143,7 +138,7 @@ class SecureCompletionClientTest {
@Test
@Order(7)
@DisplayName("loadKeys should load plaintext private key from file")
void loadKeys_plaintext_shouldLoadPrivateKey(@TempDir Path tempDir) throws Exception {
void loadKeys_plaintext_shouldLoadPrivateKey(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
client.generateKeys(true, keyDir.getAbsolutePath(), null);
@ -164,7 +159,7 @@ class SecureCompletionClientTest {
@Test
@Order(8)
@DisplayName("loadKeys should load encrypted private key with correct password")
void loadKeys_encrypted_correctPassword_shouldLoadPrivateKey(@TempDir Path tempDir) throws Exception {
void loadKeys_encrypted_correctPassword_shouldLoadPrivateKey(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
client.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -186,7 +181,7 @@ class SecureCompletionClientTest {
@Test
@Order(9)
@DisplayName("loadKeys should handle wrong password gracefully")
void loadKeys_encrypted_wrongPassword_shouldHandleGracefully(@TempDir Path tempDir) throws Exception {
void loadKeys_encrypted_wrongPassword_shouldHandleGracefully(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
client.generateKeys(true, keyDir.getAbsolutePath(), TEST_PASSWORD);
@ -220,7 +215,7 @@ class SecureCompletionClientTest {
@Test
@Order(11)
@DisplayName("validateRsaKey should accept valid 4096-bit key")
void validateRsaKey_validKey_shouldPass() throws Exception {
void validateRsaKey_validKey_shouldPass() {
client.generateKeys(false);
PrivateKey key = client.getPrivateKey();
@ -231,7 +226,7 @@ class SecureCompletionClientTest {
@Test
@Order(12)
@DisplayName("validateRsaKey should reject null key")
void validateRsaKey_nullKey_shouldThrowSecurityError() throws Exception {
void validateRsaKey_nullKey_shouldThrowSecurityError() {
SecurityError error = assertThrows(SecurityError.class, () ->
client.validateRsaKey(null));
@ -273,7 +268,7 @@ class SecureCompletionClientTest {
@Test
@Order(15)
@DisplayName("Full roundtrip: generate, save, load should produce same key")
void roundtrip_generateSaveLoad_shouldProduceSameKey(@TempDir Path tempDir) throws Exception {
void roundtrip_generateSaveLoad_shouldProduceSameKey(@TempDir Path tempDir) {
File keyDir = tempDir.toFile();
// Generate and save