package com.mosquito.project.sdk; import com.fasterxml.jackson.databind.ObjectMapper; import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule; import com.mosquito.project.dto.ApiResponse; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import java.lang.reflect.Field; import java.net.http.HttpClient; import java.time.ZonedDateTime; import java.util.List; import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertFalse; import static org.junit.jupiter.api.Assertions.assertTrue; class MosquitoClientTest { private TestHttpClient httpClient; private MosquitoClient client; private ObjectMapper objectMapper; @BeforeEach void setUp() { httpClient = new TestHttpClient(); client = new MosquitoClient("http://localhost", "test-key"); setHttpClient(client, httpClient.client()); objectMapper = new ObjectMapper().registerModule(new JavaTimeModule()); } @Test void client_shouldCallEndpointsAndParseResponses() throws Exception { ZonedDateTime start = ZonedDateTime.parse("2025-01-01T00:00:00Z"); ZonedDateTime end = ZonedDateTime.parse("2025-01-02T00:00:00Z"); MosquitoClient.Activity activity = new MosquitoClient.Activity(); activity.setId(1L); activity.setName("Activity A"); activity.setStartTime(start); activity.setEndTime(end); MosquitoClient.Activity updated = new MosquitoClient.Activity(); updated.setId(1L); updated.setName("Activity B"); updated.setStartTime(start); updated.setEndTime(end); MosquitoClient.DailyStats daily = new MosquitoClient.DailyStats(); daily.setDate("2025-01-01"); daily.setParticipants(5); daily.setShares(3); MosquitoClient.ActivityStats stats = new MosquitoClient.ActivityStats(); stats.setTotalParticipants(5); stats.setTotalShares(3); stats.setDaily(List.of(daily)); MosquitoClient.ShortenResponse shorten = new MosquitoClient.ShortenResponse(); shorten.setCode("abc"); shorten.setPath("/r/abc"); shorten.setOriginalUrl("https://example.com"); MosquitoClient.ShareMeta shareMeta = new MosquitoClient.ShareMeta(); shareMeta.setTitle("title"); shareMeta.setDescription("desc"); shareMeta.setImage("img"); shareMeta.setUrl("url"); MosquitoClient.PosterConfig posterConfig = new MosquitoClient.PosterConfig(); posterConfig.setTemplate("default"); posterConfig.setImageUrl("/poster.png"); posterConfig.setHtmlUrl("/poster.html"); MosquitoClient.LeaderboardEntry entry = new MosquitoClient.LeaderboardEntry(); entry.setUserId(7L); entry.setUserName("user"); entry.setScore(100); MosquitoClient.RewardInfo reward = new MosquitoClient.RewardInfo(); reward.setType("points"); reward.setPoints(10); reward.setCreatedAt("2025-01-01T00:00:00Z"); MosquitoClient.CreateApiKeyResponse createApiKeyResponse = new MosquitoClient.CreateApiKeyResponse(); createApiKeyResponse.setApiKey("raw-key"); MosquitoClient.RevealApiKeyResponse revealApiKeyResponse = new MosquitoClient.RevealApiKeyResponse(); revealApiKeyResponse.setApiKey("revealed-key"); revealApiKeyResponse.setMessage("one-time"); httpClient.register("POST", "/api/v1/activities", 200, objectMapper.writeValueAsString(ApiResponse.success(activity))); httpClient.register("GET", "/api/v1/activities/1", 200, objectMapper.writeValueAsString(ApiResponse.success(activity))); httpClient.register("PUT", "/api/v1/activities/1", 200, objectMapper.writeValueAsString(ApiResponse.success(updated))); httpClient.register("GET", "/api/v1/activities/1/stats", 200, objectMapper.writeValueAsString(ApiResponse.success(stats))); httpClient.register("GET", "/api/v1/me/invitation-info", 200, objectMapper.writeValueAsString(ApiResponse.success(shorten))); httpClient.register("GET", "/api/v1/me/share-meta", 200, objectMapper.writeValueAsString(ApiResponse.success(shareMeta))); httpClient.register("GET", "/api/v1/me/poster/image", 200, new byte[]{9, 8, 7}); httpClient.register("GET", "/api/v1/me/poster/html", 200, "ok"); httpClient.register("GET", "/api/v1/me/poster/config", 200, objectMapper.writeValueAsString(ApiResponse.success(posterConfig))); httpClient.register("GET", "/api/v1/activities/1/leaderboard", 200, objectMapper.writeValueAsString(ApiResponse.success(List.of(entry)))); httpClient.register("GET", "/api/v1/activities/1/leaderboard/export", 200, "csv-data"); httpClient.register("GET", "/api/v1/me/rewards", 200, objectMapper.writeValueAsString(ApiResponse.success(List.of(reward)))); httpClient.register("POST", "/api/v1/api-keys", 200, objectMapper.writeValueAsString(ApiResponse.success(createApiKeyResponse))); httpClient.register("GET", "/api/v1/api-keys/1/reveal", 200, objectMapper.writeValueAsString(ApiResponse.success(revealApiKeyResponse))); httpClient.register("DELETE", "/api/v1/api-keys/1", 204, ""); httpClient.register("GET", "/actuator/health", 200, "ok"); MosquitoClient.Activity created = client.createActivity("Activity A", start, end); MosquitoClient.Activity fetched = client.getActivity(1L); MosquitoClient.Activity changed = client.updateActivity(1L, "Activity B", end); MosquitoClient.ActivityStats fetchedStats = client.getActivityStats(1L); String shareUrl = client.getShareUrl(1L, 2L); MosquitoClient.ShareMeta meta = client.getShareMeta(1L, 2L); byte[] posterImage = client.getPosterImage(1L, 2L); String posterHtml = client.getPosterHtml(1L, 2L); MosquitoClient.PosterConfig config = client.getPosterConfig("default"); List leaderboard = client.getLeaderboard(1L); List leaderboardPaged = client.getLeaderboard(1L, 1, 2); String csv = client.exportLeaderboardCsv(1L); String csvTop = client.exportLeaderboardCsv(1L, 5); List rewards = client.getUserRewards(1L, 2L); String apiKey = client.createApiKey(1L, "key"); client.revokeApiKey(1L); String revealed = client.revealApiKey(1L); boolean healthy = client.isHealthy(); assertEquals("Activity A", created.getName()); assertEquals("Activity A", fetched.getName()); assertEquals("Activity B", changed.getName()); assertEquals(5, fetchedStats.getTotalParticipants()); assertTrue(shareUrl.endsWith("/r/abc")); assertEquals("title", meta.getTitle()); assertArrayEquals(new byte[]{9, 8, 7}, posterImage); assertEquals("ok", posterHtml); assertEquals("default", config.getTemplate()); assertEquals(1, leaderboard.size()); assertEquals(1, leaderboardPaged.size()); assertEquals("csv-data", csv); assertEquals("csv-data", csvTop); assertEquals(1, rewards.size()); assertEquals("raw-key", apiKey); assertEquals("revealed-key", revealed); assertTrue(healthy); } @Test void isHealthy_shouldReturnFalse_whenEndpointFails() { MosquitoClient unreachable = new MosquitoClient("http://localhost:1", "test-key"); assertFalse(unreachable.isHealthy()); } private static void setHttpClient(MosquitoClient mosquitoClient, HttpClient httpClient) { try { Field apiClientField = MosquitoClient.class.getDeclaredField("apiClient"); apiClientField.setAccessible(true); ApiClient apiClient = (ApiClient) apiClientField.get(mosquitoClient); Field httpClientField = ApiClient.class.getDeclaredField("httpClient"); httpClientField.setAccessible(true); httpClientField.set(apiClient, httpClient); } catch (Exception e) { throw new RuntimeException("Failed to set HttpClient", e); } } }