add tests
This commit is contained in:
@@ -0,0 +1,102 @@
|
|||||||
|
package com.krrishg.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.AfterEach;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class EncryptionServiceTest {
|
||||||
|
|
||||||
|
private Path tempKeyPath;
|
||||||
|
private EncryptionService service;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
try {
|
||||||
|
tempKeyPath = Files.createTempFile("test-encryption", ".key");
|
||||||
|
service = new EncryptionService(tempKeyPath.toString());
|
||||||
|
service.init();
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@AfterEach
|
||||||
|
void tearDown() throws IOException {
|
||||||
|
Files.deleteIfExists(tempKeyPath);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void encryptAndDecryptRoundtrip() {
|
||||||
|
String plaintext = "Hello, World!";
|
||||||
|
|
||||||
|
String encrypted = service.encrypt(plaintext);
|
||||||
|
assertNotNull(encrypted);
|
||||||
|
assertNotEquals(plaintext, encrypted);
|
||||||
|
|
||||||
|
String decrypted = service.decrypt(encrypted);
|
||||||
|
assertEquals(plaintext, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void encryptAndDecryptSpecialCharacters() {
|
||||||
|
String plaintext = "Special chars: !@#$%^&*()_+-=[]{}|;':\",./<>?`~\n\t";
|
||||||
|
|
||||||
|
String encrypted = service.encrypt(plaintext);
|
||||||
|
String decrypted = service.decrypt(encrypted);
|
||||||
|
|
||||||
|
assertEquals(plaintext, decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void encryptAndDecryptEmptyString() {
|
||||||
|
String encrypted = service.encrypt("");
|
||||||
|
String decrypted = service.decrypt(encrypted);
|
||||||
|
|
||||||
|
assertEquals("", decrypted);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void differentPlaintextsProduceDifferentCiphertexts() {
|
||||||
|
String encrypted1 = service.encrypt("text1");
|
||||||
|
String encrypted2 = service.encrypt("text2");
|
||||||
|
|
||||||
|
assertNotEquals(encrypted1, encrypted2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void samePlaintextProducedDifferentCiphertextsDueToRandomIv() {
|
||||||
|
String encrypted1 = service.encrypt("same text");
|
||||||
|
String encrypted2 = service.encrypt("same text");
|
||||||
|
|
||||||
|
assertNotEquals(encrypted1, encrypted2);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void decryptThrowsOnInvalidData() {
|
||||||
|
assertThrows(RuntimeException.class, () -> service.decrypt("invalid-base64!"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initCreatesKeyFile() throws IOException {
|
||||||
|
assertTrue(Files.exists(tempKeyPath));
|
||||||
|
assertTrue(Files.size(tempKeyPath) > 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initLoadsExistingKeyFile() {
|
||||||
|
EncryptionService secondService = new EncryptionService(tempKeyPath.toString());
|
||||||
|
secondService.init();
|
||||||
|
|
||||||
|
String plaintext = "Persistent key test";
|
||||||
|
String encrypted = secondService.encrypt(plaintext);
|
||||||
|
String decrypted = secondService.decrypt(encrypted);
|
||||||
|
|
||||||
|
assertEquals(plaintext, decrypted);
|
||||||
|
}
|
||||||
|
}
|
||||||
66
backend/src/test/java/com/krrishg/config/GitConfigTest.java
Normal file
66
backend/src/test/java/com/krrishg/config/GitConfigTest.java
Normal file
@@ -0,0 +1,66 @@
|
|||||||
|
package com.krrishg.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
import java.nio.file.Files;
|
||||||
|
import java.nio.file.Path;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class GitConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getSiteRepoPathResolvesCorrectly() throws IOException {
|
||||||
|
Path tempDir = Files.createTempDirectory("git-config-test");
|
||||||
|
GitConfig config = new GitConfig();
|
||||||
|
setField(config, "reposPath", tempDir.toString());
|
||||||
|
setField(config, "authorName", "Indie Platform");
|
||||||
|
setField(config, "authorEmail", "git@indie.local");
|
||||||
|
config.init();
|
||||||
|
|
||||||
|
Path repoPath = config.getSiteRepoPath("test-site-id");
|
||||||
|
|
||||||
|
assertEquals(tempDir.resolve("test-site-id"), repoPath);
|
||||||
|
assertEquals("Indie Platform", config.getAuthorName());
|
||||||
|
assertEquals("git@indie.local", config.getAuthorEmail());
|
||||||
|
|
||||||
|
Files.deleteIfExists(tempDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void initCreatesDirectory() throws IOException {
|
||||||
|
Path tempDir = Files.createTempDirectory("git-config-init-test");
|
||||||
|
Path reposDir = tempDir.resolve("repos");
|
||||||
|
GitConfig config = new GitConfig();
|
||||||
|
setField(config, "reposPath", reposDir.toString());
|
||||||
|
|
||||||
|
assertFalse(Files.exists(reposDir));
|
||||||
|
config.init();
|
||||||
|
assertTrue(Files.exists(reposDir));
|
||||||
|
|
||||||
|
Files.deleteIfExists(reposDir);
|
||||||
|
Files.deleteIfExists(tempDir);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void settersUpdateAuthorInfo() {
|
||||||
|
GitConfig config = new GitConfig();
|
||||||
|
|
||||||
|
config.setAuthorName("Custom Author");
|
||||||
|
config.setAuthorEmail("custom@example.com");
|
||||||
|
|
||||||
|
assertEquals("Custom Author", config.getAuthorName());
|
||||||
|
assertEquals("custom@example.com", config.getAuthorEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
private void setField(Object target, String fieldName, Object value) {
|
||||||
|
try {
|
||||||
|
var field = target.getClass().getDeclaredField(fieldName);
|
||||||
|
field.setAccessible(true);
|
||||||
|
field.set(target, value);
|
||||||
|
} catch (Exception e) {
|
||||||
|
throw new RuntimeException(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,73 @@
|
|||||||
|
package com.krrishg.config;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class MapToJsonConverterTest {
|
||||||
|
|
||||||
|
private final MapToJsonConverter converter = new MapToJsonConverter();
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToDatabaseColumnSerializesMap() {
|
||||||
|
Map<String, String> map = Map.of("key1", "value1", "key2", "value2");
|
||||||
|
|
||||||
|
String json = converter.convertToDatabaseColumn(map);
|
||||||
|
|
||||||
|
assertNotNull(json);
|
||||||
|
assertTrue(json.contains("key1"));
|
||||||
|
assertTrue(json.contains("value1"));
|
||||||
|
assertTrue(json.contains("key2"));
|
||||||
|
assertTrue(json.contains("value2"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToEntityAttributeDeserializesJson() {
|
||||||
|
String json = "{\"a\":\"1\",\"b\":\"2\"}";
|
||||||
|
|
||||||
|
Map<String, String> result = converter.convertToEntityAttribute(json);
|
||||||
|
|
||||||
|
assertEquals(2, result.size());
|
||||||
|
assertEquals("1", result.get("a"));
|
||||||
|
assertEquals("2", result.get("b"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void roundtripPreservesMap() {
|
||||||
|
Map<String, String> original = Map.of("alpha", "beta", "gamma", "delta");
|
||||||
|
|
||||||
|
String json = converter.convertToDatabaseColumn(original);
|
||||||
|
Map<String, String> result = converter.convertToEntityAttribute(json);
|
||||||
|
|
||||||
|
assertEquals(original, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToDatabaseColumnReturnsNullForNullInput() {
|
||||||
|
assertNull(converter.convertToDatabaseColumn(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToDatabaseColumnReturnsNullForEmptyMap() {
|
||||||
|
assertNull(converter.convertToDatabaseColumn(Map.of()));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToEntityAttributeReturnsEmptyMapForNullInput() {
|
||||||
|
assertEquals(Map.of(), converter.convertToEntityAttribute(null));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToEntityAttributeReturnsEmptyMapForBlankInput() {
|
||||||
|
assertEquals(Map.of(), converter.convertToEntityAttribute(""));
|
||||||
|
assertEquals(Map.of(), converter.convertToEntityAttribute(" "));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void convertToEntityAttributeThrowsOnMalformedJson() {
|
||||||
|
assertThrows(RuntimeException.class, () ->
|
||||||
|
converter.convertToEntityAttribute("{invalid json}"));
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,254 @@
|
|||||||
|
package com.krrishg.controller;
|
||||||
|
|
||||||
|
import com.krrishg.config.EncryptionService;
|
||||||
|
import com.krrishg.config.GlobalExceptionHandler;
|
||||||
|
import com.krrishg.config.JwtAuthenticationToken;
|
||||||
|
import com.krrishg.config.UserPrincipal;
|
||||||
|
import com.krrishg.model.AuthProvider;
|
||||||
|
import com.krrishg.model.User;
|
||||||
|
import com.krrishg.repository.UserRepository;
|
||||||
|
import com.krrishg.support.TestSecurityConfig;
|
||||||
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.springframework.beans.factory.annotation.Autowired;
|
||||||
|
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
|
||||||
|
import org.springframework.boot.test.mock.mockito.MockBean;
|
||||||
|
import org.springframework.context.annotation.Import;
|
||||||
|
import org.springframework.http.MediaType;
|
||||||
|
import org.springframework.test.web.servlet.MockMvc;
|
||||||
|
|
||||||
|
import java.util.HashMap;
|
||||||
|
import java.util.Map;
|
||||||
|
import java.util.Optional;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.assertNull;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.verify;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.authentication;
|
||||||
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
||||||
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
||||||
|
|
||||||
|
@WebMvcTest(UserSettingsController.class)
|
||||||
|
@Import({GlobalExceptionHandler.class, TestSecurityConfig.class})
|
||||||
|
class UserSettingsControllerTest {
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private MockMvc mockMvc;
|
||||||
|
|
||||||
|
@Autowired
|
||||||
|
private ObjectMapper objectMapper;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private UserRepository userRepository;
|
||||||
|
|
||||||
|
@MockBean
|
||||||
|
private EncryptionService encryptionService;
|
||||||
|
|
||||||
|
private UUID userId;
|
||||||
|
private UserPrincipal principal;
|
||||||
|
private JwtAuthenticationToken auth;
|
||||||
|
private User testUser;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
userId = UUID.randomUUID();
|
||||||
|
principal = new UserPrincipal(userId, "user@test.com", "Test User");
|
||||||
|
auth = new JwtAuthenticationToken(principal, "test-token");
|
||||||
|
testUser = User.builder()
|
||||||
|
.id(userId)
|
||||||
|
.email("user@test.com")
|
||||||
|
.name("Test User")
|
||||||
|
.provider(AuthProvider.LOCAL)
|
||||||
|
.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getLlmConfigReturnsConfigWithAllFields() throws Exception {
|
||||||
|
Map<String, String> keys = new HashMap<>();
|
||||||
|
keys.put("gemini", "encrypted-gemini-key");
|
||||||
|
Map<String, String> urls = new HashMap<>();
|
||||||
|
urls.put("gemini", "https://custom.gemini.com");
|
||||||
|
Map<String, String> models = new HashMap<>();
|
||||||
|
models.put("gemini", "gemini-2.0-flash");
|
||||||
|
testUser.setLlmApiKeys(keys);
|
||||||
|
testUser.setLlmBaseUrls(urls);
|
||||||
|
testUser.setLlmModels(models);
|
||||||
|
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/user/llm-config")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.gemini.configured").value(true))
|
||||||
|
.andExpect(jsonPath("$.gemini.baseUrl").value("https://custom.gemini.com"))
|
||||||
|
.andExpect(jsonPath("$.gemini.model").value("gemini-2.0-flash"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getLlmConfigReturnsMinimalConfigWhenNoUrlsOrModels() throws Exception {
|
||||||
|
Map<String, String> keys = new HashMap<>();
|
||||||
|
keys.put("openai", "encrypted-openai-key");
|
||||||
|
testUser.setLlmApiKeys(keys);
|
||||||
|
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/user/llm-config")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(jsonPath("$.openai.configured").value(true))
|
||||||
|
.andExpect(jsonPath("$.openai.baseUrl").doesNotExist())
|
||||||
|
.andExpect(jsonPath("$.openai.model").doesNotExist());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getLlmConfigReturnsEmptyMapWhenNoKeys() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/user/llm-config")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isOk())
|
||||||
|
.andExpect(content().json("{}"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getLlmConfigReturns400WhenUserNotFound() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
mockMvc.perform(get("/api/user/llm-config")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigSavesApiKey() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
when(encryptionService.encrypt("sk-test-key")).thenReturn("encrypted-key");
|
||||||
|
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("provider", "openai");
|
||||||
|
request.put("apiKey", "sk-test-key");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
verify(userRepository).save(any(User.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigSavesBaseUrlAndModel() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
when(encryptionService.encrypt("key")).thenReturn("encrypted");
|
||||||
|
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("provider", "gemini");
|
||||||
|
request.put("apiKey", "key");
|
||||||
|
request.put("baseUrl", "https://gemini.api.com");
|
||||||
|
request.put("model", "gemini-2.0-flash");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
verify(userRepository).save(any(User.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigMergesWithExistingConfig() throws Exception {
|
||||||
|
Map<String, String> existingKeys = new HashMap<>();
|
||||||
|
existingKeys.put("gemini", "existing-gemini-key");
|
||||||
|
testUser.setLlmApiKeys(existingKeys);
|
||||||
|
testUser.setLlmBaseUrls(new HashMap<>(Map.of("gemini", "https://gemini.api.com")));
|
||||||
|
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
when(encryptionService.encrypt("new-openai-key")).thenReturn("encrypted-new-key");
|
||||||
|
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("provider", "openai");
|
||||||
|
request.put("apiKey", "new-openai-key");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
verify(userRepository).save(any(User.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigReturns400WhenProviderIsBlank() throws Exception {
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("provider", "");
|
||||||
|
request.put("apiKey", "key");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigReturns400WhenProviderIsNull() throws Exception {
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("apiKey", "key");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void saveLlmConfigSkipsEmptyApiKey() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
|
Map<String, String> request = new HashMap<>();
|
||||||
|
request.put("provider", "openai");
|
||||||
|
request.put("apiKey", "");
|
||||||
|
|
||||||
|
mockMvc.perform(put("/api/user/llm-config")
|
||||||
|
.with(authentication(auth))
|
||||||
|
.contentType(MediaType.APPLICATION_JSON)
|
||||||
|
.content(objectMapper.writeValueAsString(request)))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
assertNull(testUser.getLlmApiKeys());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteLlmConfigRemovesProviderConfig() throws Exception {
|
||||||
|
Map<String, String> keys = new HashMap<>();
|
||||||
|
keys.put("gemini", "encrypted-key");
|
||||||
|
keys.put("openai", "encrypted-key");
|
||||||
|
testUser.setLlmApiKeys(keys);
|
||||||
|
testUser.setLlmBaseUrls(new HashMap<>(Map.of("gemini", "url")));
|
||||||
|
testUser.setLlmModels(new HashMap<>(Map.of("gemini", "model")));
|
||||||
|
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.of(testUser));
|
||||||
|
|
||||||
|
mockMvc.perform(delete("/api/user/llm-config/gemini")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isOk());
|
||||||
|
|
||||||
|
verify(userRepository).save(any(User.class));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void deleteLlmConfigReturns400WhenUserNotFound() throws Exception {
|
||||||
|
when(userRepository.findById(userId)).thenReturn(Optional.empty());
|
||||||
|
|
||||||
|
mockMvc.perform(delete("/api/user/llm-config/openai")
|
||||||
|
.with(authentication(auth)))
|
||||||
|
.andExpect(status().isBadRequest());
|
||||||
|
}
|
||||||
|
}
|
||||||
62
backend/src/test/java/com/krrishg/dto/AuthResponseTest.java
Normal file
62
backend/src/test/java/com/krrishg/dto/AuthResponseTest.java
Normal file
@@ -0,0 +1,62 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import com.krrishg.model.AuthProvider;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class AuthResponseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void constructorSetsBearerTokenType() {
|
||||||
|
AuthResponse.UserInfo userInfo = new AuthResponse.UserInfo(
|
||||||
|
UUID.randomUUID(), "test@example.com", "Test", null, AuthProvider.LOCAL);
|
||||||
|
|
||||||
|
AuthResponse response = new AuthResponse("access-token", "refresh-token", userInfo);
|
||||||
|
|
||||||
|
assertEquals("access-token", response.getAccessToken());
|
||||||
|
assertEquals("refresh-token", response.getRefreshToken());
|
||||||
|
assertEquals("Bearer", response.getTokenType());
|
||||||
|
assertSame(userInfo, response.getUser());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderWorksWithTokenType() {
|
||||||
|
AuthResponse.UserInfo userInfo = AuthResponse.UserInfo.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.email("user@example.com")
|
||||||
|
.name("User")
|
||||||
|
.provider(AuthProvider.GOOGLE)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
AuthResponse response = AuthResponse.builder()
|
||||||
|
.accessToken("at")
|
||||||
|
.refreshToken("rt")
|
||||||
|
.tokenType("Custom")
|
||||||
|
.user(userInfo)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals("Custom", response.getTokenType());
|
||||||
|
assertEquals("user@example.com", response.getUser().getEmail());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void userInfoBuilderSetsAllFields() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
AuthResponse.UserInfo userInfo = AuthResponse.UserInfo.builder()
|
||||||
|
.id(id)
|
||||||
|
.email("avatar@example.com")
|
||||||
|
.name("Avatar User")
|
||||||
|
.avatarUrl("https://example.com/avatar.png")
|
||||||
|
.provider(AuthProvider.GITHUB)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(id, userInfo.getId());
|
||||||
|
assertEquals("avatar@example.com", userInfo.getEmail());
|
||||||
|
assertEquals("Avatar User", userInfo.getName());
|
||||||
|
assertEquals("https://example.com/avatar.png", userInfo.getAvatarUrl());
|
||||||
|
assertEquals(AuthProvider.GITHUB, userInfo.getProvider());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,38 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class LLMConfigRequestTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void compactConstructorSetsProviderAndApiKey() {
|
||||||
|
LLMConfigRequest request = new LLMConfigRequest("gemini", "test-key");
|
||||||
|
|
||||||
|
assertEquals("gemini", request.provider());
|
||||||
|
assertEquals("test-key", request.apiKey());
|
||||||
|
assertNull(request.baseUrl());
|
||||||
|
assertNull(request.model());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void threeArgConstructorSetsProviderApiKeyAndBaseUrl() {
|
||||||
|
LLMConfigRequest request = new LLMConfigRequest("openai", "sk-test", "https://api.openai.com");
|
||||||
|
|
||||||
|
assertEquals("openai", request.provider());
|
||||||
|
assertEquals("sk-test", request.apiKey());
|
||||||
|
assertEquals("https://api.openai.com", request.baseUrl());
|
||||||
|
assertNull(request.model());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fullConstructorSetsAllFields() {
|
||||||
|
LLMConfigRequest request = new LLMConfigRequest("gemini", "key", "https://custom.url", "gemini-2.0-flash");
|
||||||
|
|
||||||
|
assertEquals("gemini", request.provider());
|
||||||
|
assertEquals("key", request.apiKey());
|
||||||
|
assertEquals("https://custom.url", request.baseUrl());
|
||||||
|
assertEquals("gemini-2.0-flash", request.model());
|
||||||
|
}
|
||||||
|
}
|
||||||
30
backend/src/test/java/com/krrishg/dto/LLMOptionsTest.java
Normal file
30
backend/src/test/java/com/krrishg/dto/LLMOptionsTest.java
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class LLMOptionsTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderDefaults() {
|
||||||
|
LLMOptions options = LLMOptions.builder().build();
|
||||||
|
|
||||||
|
assertEquals(0.9, options.getTemperature());
|
||||||
|
assertEquals(4096, options.getMaxTokens());
|
||||||
|
assertEquals(60, options.getTimeoutSeconds());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderOverridesDefaults() {
|
||||||
|
LLMOptions options = LLMOptions.builder()
|
||||||
|
.temperature(0.5)
|
||||||
|
.maxTokens(2048)
|
||||||
|
.timeoutSeconds(30)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(0.5, options.getTemperature());
|
||||||
|
assertEquals(2048, options.getMaxTokens());
|
||||||
|
assertEquals(30, options.getTimeoutSeconds());
|
||||||
|
}
|
||||||
|
}
|
||||||
38
backend/src/test/java/com/krrishg/dto/ReferenceTest.java
Normal file
38
backend/src/test/java/com/krrishg/dto/ReferenceTest.java
Normal file
@@ -0,0 +1,38 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class ReferenceTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderSetsAllFields() {
|
||||||
|
Reference ref = Reference.builder()
|
||||||
|
.type(Reference.ReferenceType.URL)
|
||||||
|
.url("https://example.com")
|
||||||
|
.altText("Example Site")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(Reference.ReferenceType.URL, ref.getType());
|
||||||
|
assertEquals("https://example.com", ref.getUrl());
|
||||||
|
assertEquals("Example Site", ref.getAltText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderDefaultsToNull() {
|
||||||
|
Reference ref = Reference.builder().build();
|
||||||
|
|
||||||
|
assertNull(ref.getType());
|
||||||
|
assertNull(ref.getUrl());
|
||||||
|
assertNull(ref.getAltText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void referenceTypeEnumValues() {
|
||||||
|
assertArrayEquals(
|
||||||
|
new Reference.ReferenceType[]{Reference.ReferenceType.URL, Reference.ReferenceType.IMAGE},
|
||||||
|
Reference.ReferenceType.values()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import com.krrishg.model.SelfHostedConfig;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SelfHostedConfigResponseTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fromMapsAllFields() {
|
||||||
|
UUID id = UUID.randomUUID();
|
||||||
|
UUID siteId = UUID.randomUUID();
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.id(id)
|
||||||
|
.siteId(siteId)
|
||||||
|
.domain("example.com")
|
||||||
|
.sshHost("192.168.1.1")
|
||||||
|
.sshPort(2222)
|
||||||
|
.sshUser("deploy")
|
||||||
|
.deployPath("/var/www/html")
|
||||||
|
.nginxSitesPath("/etc/nginx/conf.d")
|
||||||
|
.sslEnabled(true)
|
||||||
|
.sslEmail("admin@example.com")
|
||||||
|
.deployedAt(now)
|
||||||
|
.createdAt(now)
|
||||||
|
.updatedAt(now)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SelfHostedConfigResponse response = SelfHostedConfigResponse.from(config, "ssh-ed25519 AAA...");
|
||||||
|
|
||||||
|
assertEquals(id, response.getId());
|
||||||
|
assertEquals(siteId, response.getSiteId());
|
||||||
|
assertEquals("example.com", response.getDomain());
|
||||||
|
assertEquals("192.168.1.1", response.getSshHost());
|
||||||
|
assertEquals(2222, response.getSshPort());
|
||||||
|
assertEquals("deploy", response.getSshUser());
|
||||||
|
assertEquals("/var/www/html", response.getDeployPath());
|
||||||
|
assertEquals("/etc/nginx/conf.d", response.getNginxSitesPath());
|
||||||
|
assertTrue(response.isSslEnabled());
|
||||||
|
assertEquals("admin@example.com", response.getSslEmail());
|
||||||
|
assertEquals("ssh-ed25519 AAA...", response.getPublicKey());
|
||||||
|
assertEquals(now, response.getDeployedAt());
|
||||||
|
assertEquals(now, response.getCreatedAt());
|
||||||
|
assertEquals(now, response.getUpdatedAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void fromHandlesNullOptionalFields() {
|
||||||
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.siteId(UUID.randomUUID())
|
||||||
|
.domain("example.com")
|
||||||
|
.sshHost("host")
|
||||||
|
.sshUser("user")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SelfHostedConfigResponse response = SelfHostedConfigResponse.from(config, null);
|
||||||
|
|
||||||
|
assertNull(response.getSslEmail());
|
||||||
|
assertNull(response.getPublicKey());
|
||||||
|
assertNull(response.getDeployedAt());
|
||||||
|
assertFalse(response.isSslEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
57
backend/src/test/java/com/krrishg/dto/SiteStructureTest.java
Normal file
57
backend/src/test/java/com/krrishg/dto/SiteStructureTest.java
Normal file
@@ -0,0 +1,57 @@
|
|||||||
|
package com.krrishg.dto;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.Map;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SiteStructureTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderSetsAllFields() {
|
||||||
|
Map<String, String> colors = Map.of("primary", "#000", "secondary", "#fff");
|
||||||
|
Map<String, String> fonts = Map.of("heading", "Arial");
|
||||||
|
Map<String, String> spacing = Map.of("margin", "16px");
|
||||||
|
|
||||||
|
SiteStructure.ThemeConfig theme = new SiteStructure.ThemeConfig(colors, fonts, spacing);
|
||||||
|
|
||||||
|
SiteStructure.PageStructure page = SiteStructure.PageStructure.builder()
|
||||||
|
.id("home")
|
||||||
|
.title("Home")
|
||||||
|
.slug("/")
|
||||||
|
.seoTitle("Home Page")
|
||||||
|
.seoDescription("Welcome")
|
||||||
|
.orderIndex(0)
|
||||||
|
.rawHtml("<h1>Hello</h1>")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
SiteStructure structure = SiteStructure.builder()
|
||||||
|
.theme(theme)
|
||||||
|
.pages(List.of(page))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertNotNull(structure.getTheme());
|
||||||
|
assertEquals("#000", structure.getTheme().getColors().get("primary"));
|
||||||
|
assertEquals("Arial", structure.getTheme().getFonts().get("heading"));
|
||||||
|
assertEquals("16px", structure.getTheme().getSpacing().get("margin"));
|
||||||
|
|
||||||
|
assertEquals(1, structure.getPages().size());
|
||||||
|
assertEquals("home", structure.getPages().get(0).getId());
|
||||||
|
assertEquals("Home", structure.getPages().get(0).getTitle());
|
||||||
|
assertEquals("/", structure.getPages().get(0).getSlug());
|
||||||
|
assertEquals("Home Page", structure.getPages().get(0).getSeoTitle());
|
||||||
|
assertEquals("Welcome", structure.getPages().get(0).getSeoDescription());
|
||||||
|
assertEquals(0, structure.getPages().get(0).getOrderIndex());
|
||||||
|
assertEquals("<h1>Hello</h1>", structure.getPages().get(0).getRawHtml());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderHandlesNullOptionalFields() {
|
||||||
|
SiteStructure structure = SiteStructure.builder().build();
|
||||||
|
|
||||||
|
assertNull(structure.getTheme());
|
||||||
|
assertNull(structure.getPages());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package com.krrishg.model;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class AuthProviderTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void enumValues() {
|
||||||
|
assertArrayEquals(
|
||||||
|
new AuthProvider[]{AuthProvider.LOCAL, AuthProvider.GOOGLE, AuthProvider.GITHUB, AuthProvider.OPENID},
|
||||||
|
AuthProvider.values()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,67 @@
|
|||||||
|
package com.krrishg.model;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.List;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class GenerationVersionTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderSetsAllFields() {
|
||||||
|
UUID siteId = UUID.randomUUID();
|
||||||
|
UUID userId = UUID.randomUUID();
|
||||||
|
LocalDateTime now = LocalDateTime.now();
|
||||||
|
|
||||||
|
GenerationVersion version = GenerationVersion.builder()
|
||||||
|
.id("mongo-id")
|
||||||
|
.siteId(siteId)
|
||||||
|
.userId(userId)
|
||||||
|
.versionNumber(1)
|
||||||
|
.prompt("Build a landing page")
|
||||||
|
.fullStructure("{\"theme\":{}}")
|
||||||
|
.createdAt(now)
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals("mongo-id", version.getId());
|
||||||
|
assertEquals(siteId, version.getSiteId());
|
||||||
|
assertEquals(userId, version.getUserId());
|
||||||
|
assertEquals(1, version.getVersionNumber());
|
||||||
|
assertEquals("Build a landing page", version.getPrompt());
|
||||||
|
assertEquals("{\"theme\":{}}", version.getFullStructure());
|
||||||
|
assertEquals(now, version.getCreatedAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderSupportsReferenceEntries() {
|
||||||
|
GenerationVersion.ReferenceEntry entry = GenerationVersion.ReferenceEntry.builder()
|
||||||
|
.type("IMAGE")
|
||||||
|
.url("https://example.com/img.png")
|
||||||
|
.altText("Screenshot")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
GenerationVersion version = GenerationVersion.builder()
|
||||||
|
.siteId(UUID.randomUUID())
|
||||||
|
.userId(UUID.randomUUID())
|
||||||
|
.versionNumber(2)
|
||||||
|
.prompt("With references")
|
||||||
|
.references(List.of(entry))
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(1, version.getReferences().size());
|
||||||
|
assertEquals("IMAGE", version.getReferences().get(0).getType());
|
||||||
|
assertEquals("https://example.com/img.png", version.getReferences().get(0).getUrl());
|
||||||
|
assertEquals("Screenshot", version.getReferences().get(0).getAltText());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void noArgsConstructorCreatesEmptyObject() {
|
||||||
|
GenerationVersion version = new GenerationVersion();
|
||||||
|
assertNull(version.getId());
|
||||||
|
assertNull(version.getSiteId());
|
||||||
|
assertEquals(0, version.getVersionNumber());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package com.krrishg.model;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import java.time.LocalDateTime;
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SelfHostedConfigTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void prePersistSetsIdAndTimestamps() {
|
||||||
|
SelfHostedConfig config = new SelfHostedConfig();
|
||||||
|
config.setSiteId(UUID.randomUUID());
|
||||||
|
config.setDomain("example.com");
|
||||||
|
config.setSshHost("192.168.1.1");
|
||||||
|
config.setSshUser("deploy");
|
||||||
|
|
||||||
|
assertNull(config.getId());
|
||||||
|
assertNull(config.getCreatedAt());
|
||||||
|
assertNull(config.getUpdatedAt());
|
||||||
|
|
||||||
|
config.onCreate();
|
||||||
|
|
||||||
|
assertNotNull(config.getId());
|
||||||
|
assertNotNull(config.getCreatedAt());
|
||||||
|
assertNotNull(config.getUpdatedAt());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void prePersistDoesNotOverrideExistingId() {
|
||||||
|
UUID existingId = UUID.randomUUID();
|
||||||
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.id(existingId)
|
||||||
|
.siteId(UUID.randomUUID())
|
||||||
|
.domain("example.com")
|
||||||
|
.sshHost("host")
|
||||||
|
.sshUser("user")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
config.onCreate();
|
||||||
|
|
||||||
|
assertEquals(existingId, config.getId());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void preUpdateSetsUpdatedAt() {
|
||||||
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.siteId(UUID.randomUUID())
|
||||||
|
.domain("example.com")
|
||||||
|
.sshHost("host")
|
||||||
|
.sshUser("user")
|
||||||
|
.build();
|
||||||
|
config.onCreate();
|
||||||
|
|
||||||
|
LocalDateTime original = config.getUpdatedAt();
|
||||||
|
|
||||||
|
config.onUpdate();
|
||||||
|
|
||||||
|
assertTrue(config.getUpdatedAt().isAfter(original));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void builderSetsDefaults() {
|
||||||
|
SelfHostedConfig config = SelfHostedConfig.builder()
|
||||||
|
.siteId(UUID.randomUUID())
|
||||||
|
.domain("example.com")
|
||||||
|
.sshHost("host")
|
||||||
|
.sshUser("user")
|
||||||
|
.build();
|
||||||
|
|
||||||
|
assertEquals(22, config.getSshPort());
|
||||||
|
assertEquals("/var/www/{domain}/public", config.getDeployPath());
|
||||||
|
assertEquals("/etc/nginx/sites-available", config.getNginxSitesPath());
|
||||||
|
assertFalse(config.isSslEnabled());
|
||||||
|
}
|
||||||
|
}
|
||||||
16
backend/src/test/java/com/krrishg/model/SiteStatusTest.java
Normal file
16
backend/src/test/java/com/krrishg/model/SiteStatusTest.java
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package com.krrishg.model;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
|
||||||
|
class SiteStatusTest {
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void enumValues() {
|
||||||
|
assertArrayEquals(
|
||||||
|
new SiteStatus[]{SiteStatus.DRAFT, SiteStatus.PUBLISHED},
|
||||||
|
SiteStatus.values()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,76 @@
|
|||||||
|
package com.krrishg.service;
|
||||||
|
|
||||||
|
import com.krrishg.config.JwtConfig;
|
||||||
|
import com.krrishg.model.AuthProvider;
|
||||||
|
import com.krrishg.model.User;
|
||||||
|
import jakarta.servlet.http.HttpServletRequest;
|
||||||
|
import jakarta.servlet.http.HttpServletResponse;
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.security.core.Authentication;
|
||||||
|
import org.springframework.security.web.RedirectStrategy;
|
||||||
|
|
||||||
|
import java.util.UUID;
|
||||||
|
|
||||||
|
import static org.mockito.ArgumentMatchers.anyString;
|
||||||
|
import static org.mockito.Mockito.*;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class OAuth2SuccessHandlerTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private JwtConfig jwtConfig;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpServletRequest request;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private HttpServletResponse response;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private Authentication authentication;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RedirectStrategy redirectStrategy;
|
||||||
|
|
||||||
|
private OAuth2SuccessHandler handler;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
handler = new OAuth2SuccessHandler(jwtConfig);
|
||||||
|
handler.setRedirectStrategy(redirectStrategy);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onAuthenticationSuccessWithOAuth2UserRedirectsWithTokens() throws Exception {
|
||||||
|
CustomOAuth2User oAuth2User = mock(CustomOAuth2User.class);
|
||||||
|
User user = User.builder()
|
||||||
|
.id(UUID.randomUUID())
|
||||||
|
.email("user@example.com")
|
||||||
|
.name("User")
|
||||||
|
.provider(AuthProvider.GOOGLE)
|
||||||
|
.build();
|
||||||
|
when(authentication.getPrincipal()).thenReturn(oAuth2User);
|
||||||
|
when(oAuth2User.getUser()).thenReturn(user);
|
||||||
|
when(jwtConfig.generateAccessToken(user)).thenReturn("access-token-value");
|
||||||
|
when(jwtConfig.generateRefreshToken(user)).thenReturn("refresh-token-value");
|
||||||
|
|
||||||
|
handler.onAuthenticationSuccess(request, response, authentication);
|
||||||
|
|
||||||
|
String expectedRedirect = "http://localhost:4200/oauth2/callback"
|
||||||
|
+ "?accessToken=access-token-value&refreshToken=refresh-token-value";
|
||||||
|
verify(redirectStrategy).sendRedirect(request, response, expectedRedirect);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void onAuthenticationSuccessWithNonOAuth2UserCallsSuper() throws Exception {
|
||||||
|
when(authentication.getPrincipal()).thenReturn("plain principal");
|
||||||
|
|
||||||
|
handler.onAuthenticationSuccess(request, response, authentication);
|
||||||
|
|
||||||
|
verify(redirectStrategy).sendRedirect(eq(request), eq(response), anyString());
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,105 @@
|
|||||||
|
package com.krrishg.service.llm;
|
||||||
|
|
||||||
|
import org.junit.jupiter.api.BeforeEach;
|
||||||
|
import org.junit.jupiter.api.Test;
|
||||||
|
import org.junit.jupiter.api.extension.ExtendWith;
|
||||||
|
import org.mockito.Mock;
|
||||||
|
import org.mockito.junit.jupiter.MockitoExtension;
|
||||||
|
import org.springframework.boot.web.client.RestTemplateBuilder;
|
||||||
|
import org.springframework.web.client.RestTemplate;
|
||||||
|
|
||||||
|
import java.time.Duration;
|
||||||
|
import java.util.List;
|
||||||
|
|
||||||
|
import static org.junit.jupiter.api.Assertions.*;
|
||||||
|
import static org.mockito.ArgumentMatchers.any;
|
||||||
|
import static org.mockito.Mockito.lenient;
|
||||||
|
import static org.mockito.Mockito.when;
|
||||||
|
|
||||||
|
@ExtendWith(MockitoExtension.class)
|
||||||
|
class ProviderFactoryTest {
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RestTemplateBuilder restTemplateBuilder;
|
||||||
|
|
||||||
|
@Mock
|
||||||
|
private RestTemplate restTemplate;
|
||||||
|
|
||||||
|
private ProviderFactory factory;
|
||||||
|
|
||||||
|
@BeforeEach
|
||||||
|
void setUp() {
|
||||||
|
lenient().when(restTemplateBuilder.setConnectTimeout(any(Duration.class))).thenReturn(restTemplateBuilder);
|
||||||
|
lenient().when(restTemplateBuilder.setReadTimeout(any(Duration.class))).thenReturn(restTemplateBuilder);
|
||||||
|
lenient().when(restTemplateBuilder.build()).thenReturn(restTemplate);
|
||||||
|
|
||||||
|
factory = new ProviderFactory(
|
||||||
|
"gemini-2.0-flash",
|
||||||
|
"https://generativelanguage.googleapis.com/v1beta/models",
|
||||||
|
"gpt-4o-mini",
|
||||||
|
"https://api.openai.com/v1/chat/completions",
|
||||||
|
restTemplateBuilder
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderReturnsGeminiProvider() {
|
||||||
|
LLMProvider provider = factory.createProvider("gemini", "test-key");
|
||||||
|
|
||||||
|
assertInstanceOf(GeminiProvider.class, provider);
|
||||||
|
assertEquals("gemini", provider.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderReturnsOpenAIProvider() {
|
||||||
|
LLMProvider provider = factory.createProvider("openai", "sk-test");
|
||||||
|
|
||||||
|
assertInstanceOf(OpenAIProvider.class, provider);
|
||||||
|
assertEquals("openai", provider.getName());
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderWithCustomBaseUrl() {
|
||||||
|
LLMProvider provider = factory.createProvider("gemini", "key", "https://custom.url");
|
||||||
|
|
||||||
|
assertInstanceOf(GeminiProvider.class, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderWithCustomBaseUrlAndModel() {
|
||||||
|
LLMProvider provider = factory.createProvider("openai", "key", "https://custom.openai.com", "gpt-4");
|
||||||
|
|
||||||
|
assertInstanceOf(OpenAIProvider.class, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderWithCustomBaseUrlAppendsChatCompletionsForOpenAI() {
|
||||||
|
LLMProvider provider = factory.createProvider("openai", "key", "https://custom.openai.com");
|
||||||
|
|
||||||
|
assertInstanceOf(OpenAIProvider.class, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderWithCustomBaseUrlHandlesTrailingSlashForOpenAI() {
|
||||||
|
LLMProvider provider = factory.createProvider("openai", "key", "https://custom.openai.com/");
|
||||||
|
|
||||||
|
assertInstanceOf(OpenAIProvider.class, provider);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void createProviderThrowsOnUnknownProvider() {
|
||||||
|
IllegalArgumentException ex = assertThrows(IllegalArgumentException.class,
|
||||||
|
() -> factory.createProvider("unknown", "key"));
|
||||||
|
|
||||||
|
assertTrue(ex.getMessage().contains("unknown"));
|
||||||
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
void getAvailableProvidersReturnsBothProviders() {
|
||||||
|
List<String> providers = factory.getAvailableProviders();
|
||||||
|
|
||||||
|
assertEquals(2, providers.size());
|
||||||
|
assertTrue(providers.contains("gemini"));
|
||||||
|
assertTrue(providers.contains("openai"));
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user