add tests

This commit is contained in:
Krrish Ghimire
2026-07-06 22:55:21 +05:45
parent 25db5b2970
commit ad15ff8f2e
16 changed files with 1148 additions and 0 deletions

View File

@@ -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);
}
}

View 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);
}
}
}

View File

@@ -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}"));
}
}

View File

@@ -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());
}
}

View 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());
}
}

View File

@@ -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());
}
}

View 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());
}
}

View 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()
);
}
}

View File

@@ -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());
}
}

View 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());
}
}

View File

@@ -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()
);
}
}

View File

@@ -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());
}
}

View File

@@ -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());
}
}

View 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()
);
}
}

View File

@@ -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());
}
}

View File

@@ -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"));
}
}