496 lines
25 KiB
Java
496 lines
25 KiB
Java
package com.hithomelabs.cftunnels.Controllers;
|
|
|
|
import com.fasterxml.jackson.databind.ObjectMapper;
|
|
import com.hithomelabs.cftunnels.Config.AuthoritiesToGroupMapping;
|
|
import com.hithomelabs.cftunnels.Config.CloudflareConfig;
|
|
import com.hithomelabs.cftunnels.Config.RestTemplateConfig;
|
|
import com.hithomelabs.cftunnels.Headers.AuthKeyEmailHeader;
|
|
import com.hithomelabs.cftunnels.Entity.Request;
|
|
import com.hithomelabs.cftunnels.Entity.Tunnel;
|
|
import com.hithomelabs.cftunnels.Models.Authorities;
|
|
import com.hithomelabs.cftunnels.Models.Config;
|
|
import com.hithomelabs.cftunnels.Models.Groups;
|
|
import com.hithomelabs.cftunnels.Models.TunnelResponse;
|
|
import com.hithomelabs.cftunnels.Models.TunnelResult;
|
|
import com.hithomelabs.cftunnels.Models.TunnelsResponse;
|
|
import com.hithomelabs.cftunnels.Repositories.UserRepository;
|
|
import com.hithomelabs.cftunnels.Services.CloudflareAPIService;
|
|
import com.hithomelabs.cftunnels.Services.MappingRequestService;
|
|
import org.junit.jupiter.api.DisplayName;
|
|
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.http.*;
|
|
import org.springframework.security.core.GrantedAuthority;
|
|
import org.springframework.security.core.authority.SimpleGrantedAuthority;
|
|
import org.springframework.security.oauth2.core.oidc.OidcIdToken;
|
|
import org.springframework.security.oauth2.core.oidc.user.DefaultOidcUser;
|
|
import org.springframework.test.context.bean.override.mockito.MockitoBean;
|
|
import org.springframework.test.web.servlet.MockMvc;
|
|
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
|
|
import org.springframework.web.client.RestTemplate;
|
|
|
|
import java.io.IOException;
|
|
import java.time.Instant;
|
|
import java.util.*;
|
|
|
|
import org.springframework.data.domain.Page;
|
|
import org.springframework.data.domain.PageImpl;
|
|
import org.springframework.data.domain.PageRequest;
|
|
|
|
import static com.hithomelabs.cftunnels.TestUtils.Util.getClassPathDataResource;
|
|
import static org.hamcrest.core.IsIterableContaining.hasItem;
|
|
import static org.mockito.ArgumentMatchers.any;
|
|
import static org.mockito.ArgumentMatchers.eq;
|
|
import static org.mockito.Mockito.when;
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf;
|
|
import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.oauth2Login;
|
|
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
|
|
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
|
|
import static org.hamcrest.Matchers.not;
|
|
|
|
|
|
@WebMvcTest(TunnelController.class)
|
|
class TunnelControllerTest {
|
|
|
|
@Autowired
|
|
MockMvc mockMvc;
|
|
|
|
@MockitoBean
|
|
AuthoritiesToGroupMapping authoritiesToGroupMapping;
|
|
|
|
@MockitoBean
|
|
CloudflareConfig cloudflareConfig;
|
|
|
|
@MockitoBean
|
|
AuthKeyEmailHeader authKeyEmailHeader;
|
|
|
|
@MockitoBean
|
|
RestTemplate restTemplate;
|
|
|
|
@MockitoBean
|
|
CloudflareAPIService cloudflareAPIService;
|
|
|
|
@MockitoBean
|
|
RestTemplateConfig restTemplateConfig;
|
|
|
|
@MockitoBean
|
|
MappingRequestService mappingRequestService;
|
|
|
|
@MockitoBean
|
|
UserRepository userRepository;
|
|
|
|
private static final String tunnelResponseSmallIngressFile = "tunnelResponseSmallIngress.json";
|
|
|
|
private static final String tunnelResponseLargeIngressFile = "tunnelResponseLargeIngress.json";
|
|
|
|
private static final String withAdditionalIngress;
|
|
|
|
static {
|
|
try {
|
|
withAdditionalIngress = getClassPathDataResource(tunnelResponseLargeIngressFile);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
public static final String withoutAdditionalIngress;
|
|
static {
|
|
try {
|
|
withoutAdditionalIngress = getClassPathDataResource(tunnelResponseSmallIngressFile);
|
|
} catch (IOException e) {
|
|
throw new RuntimeException(e);
|
|
}
|
|
}
|
|
|
|
private static final String ingressJson = """
|
|
{
|
|
"service": "http://192.168.0.100:3457",
|
|
"hostname": "random.hithomelabs.com",
|
|
"originRequest": {}
|
|
}
|
|
""";
|
|
|
|
private DefaultOidcUser buildOidcUser(String username, String role) {
|
|
|
|
when(authoritiesToGroupMapping.getAuthorityForGroup()).thenReturn(Map.of(Groups.GITEA_USER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_USER))),
|
|
Groups.POWER_USER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_USER))),
|
|
Groups.HOMELAB_DEVELOPER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_DEVELOPER))),
|
|
Groups.SYSTEM_ADMIN, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_APPROVER), new SimpleGrantedAuthority(Authorities.ROLE_ADMIN)))));
|
|
|
|
Map<String, Set<GrantedAuthority>> roleAuthorityMapping = authoritiesToGroupMapping.getAuthorityForGroup();
|
|
List<GrantedAuthority> authorities = roleAuthorityMapping.get(role).stream().toList();
|
|
|
|
OidcIdToken idToken = new OidcIdToken(
|
|
"mock-token",
|
|
Instant.now(),
|
|
Instant.now().plusSeconds(3600),
|
|
Map.of("preferred_username", username, "sub", username)
|
|
);
|
|
|
|
return new DefaultOidcUser(authorities, idToken, "preferred_username");
|
|
}
|
|
|
|
private DefaultOidcUser buildOidcUserWithEmail(String username, String role, String email) {
|
|
|
|
when(authoritiesToGroupMapping.getAuthorityForGroup()).thenReturn(Map.of(Groups.GITEA_USER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_USER))),
|
|
Groups.POWER_USER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_USER))),
|
|
Groups.HOMELAB_DEVELOPER, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_DEVELOPER))),
|
|
Groups.SYSTEM_ADMIN, new HashSet<>(Set.of(new SimpleGrantedAuthority(Authorities.ROLE_APPROVER), new SimpleGrantedAuthority(Authorities.ROLE_ADMIN)))));
|
|
|
|
Map<String, Set<GrantedAuthority>> roleAuthorityMapping = authoritiesToGroupMapping.getAuthorityForGroup();
|
|
List<GrantedAuthority> authorities = roleAuthorityMapping.get(role).stream().toList();
|
|
|
|
OidcIdToken idToken = new OidcIdToken(
|
|
"mock-token",
|
|
Instant.now(),
|
|
Instant.now().plusSeconds(3600),
|
|
Map.of("preferred_username", username, "sub", username, "email", email)
|
|
);
|
|
|
|
return new DefaultOidcUser(authorities, idToken, "preferred_username");
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return appropriate user roles when use belongs to group GITEA_USER")
|
|
public void testWhoAmI_user() throws Exception {
|
|
mockMvc.perform(get("/cloudflare/whoami")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("username", Groups.GITEA_USER))))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.username").value("username"))
|
|
.andExpect(jsonPath("$.roles", hasItem("ROLE_USER")));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should hit tunnels endpoint successfully with ROLE_USER")
|
|
public void testGetTunnelsForRoleUser() throws Exception {
|
|
|
|
when(cloudflareConfig.getAccountId()).thenReturn("abc123");
|
|
HttpHeaders headers = new HttpHeaders();
|
|
headers.set("X-Auth-Email", "me@example.com");
|
|
when(authKeyEmailHeader.getHttpHeaders()).thenReturn(headers);
|
|
|
|
List<TunnelResult> tunnelResults = List.of(new TunnelResult("50df9101-f625-4618-b7c5-100338a57124", "test-tunnel"));
|
|
TunnelsResponse tunnelsResponse = new TunnelsResponse(tunnelResults, null, null, true);
|
|
ResponseEntity<TunnelsResponse> mockResponse = new ResponseEntity<>(tunnelsResponse, HttpStatus.OK);
|
|
|
|
when(cloudflareAPIService.getCloudflareTunnels()).thenReturn(mockResponse);
|
|
|
|
mockMvc.perform(get("/cloudflare/tunnels")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("username", Groups.GITEA_USER))))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.data.result[0].id").value("50df9101-f625-4618-b7c5-100338a57124"));
|
|
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return list of configured tunnels from database")
|
|
void getConfiguredTunnels() throws Exception {
|
|
List<Tunnel> tunnels = List.of(
|
|
new Tunnel(UUID.fromString("50df9101-f625-4618-b7c5-100338a57124"), "dev", "devtunnel"),
|
|
new Tunnel(UUID.fromString("60df9101-f625-4618-b7c5-100338a57125"), "prod", "prodtunnel")
|
|
);
|
|
when(cloudflareAPIService.getAllConfiguredTunnels()).thenReturn(tunnels);
|
|
|
|
mockMvc.perform(get("/cloudflare/configured/tunnels")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("username", Groups.GITEA_USER))))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.status").value("success"))
|
|
.andExpect(jsonPath("$.data[*].name", hasItem("devtunnel")))
|
|
.andExpect(jsonPath("$.data[*].name", hasItem("prodtunnel")));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return list of requests")
|
|
void getAllRequests_Success() throws Exception {
|
|
List<com.hithomelabs.cftunnels.Entity.Request> requests = Arrays.asList(
|
|
createTestRequest(UUID.randomUUID(), com.hithomelabs.cftunnels.Entity.Request.RequestStatus.PENDING),
|
|
createTestRequest(UUID.randomUUID(), com.hithomelabs.cftunnels.Entity.Request.RequestStatus.APPROVED)
|
|
);
|
|
|
|
when(mappingRequestService.getAllRequests()).thenReturn(requests);
|
|
|
|
mockMvc.perform(get("/cloudflare/requests")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("username", Groups.GITEA_USER))))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.status").value("success"))
|
|
.andExpect(jsonPath("$.data").isArray())
|
|
.andExpect(jsonPath("$.data.length()").value(2));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should create mapping request successfully")
|
|
void createTunnelMappingRequest_Success() throws Exception {
|
|
UUID tunnelId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.Request createdRequest = new com.hithomelabs.cftunnels.Entity.Request();
|
|
createdRequest.setId(UUID.randomUUID());
|
|
createdRequest.setStatus(com.hithomelabs.cftunnels.Entity.Request.RequestStatus.PENDING);
|
|
|
|
when(mappingRequestService.createMappingRequest(any(String.class), any(com.hithomelabs.cftunnels.Models.Ingress.class), any())).thenReturn(createdRequest);
|
|
|
|
mockMvc.perform(post("/cloudflare/tunnels/configure/{tunnelId}/requests", tunnelId.toString())
|
|
.with(oauth2Login().oauth2User(buildOidcUser("developer", Groups.HOMELAB_DEVELOPER)))
|
|
.with(csrf())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content(ingressJson))
|
|
.andExpect(status().isCreated())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.status").value("PENDING"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should approve mapping request successfully")
|
|
void approveMappingRequest_Success() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User approverUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
approverUser.setEmail("approver@example.com");
|
|
approverUser.setName("Approver");
|
|
|
|
com.hithomelabs.cftunnels.Entity.Request approvedRequest = new com.hithomelabs.cftunnels.Entity.Request();
|
|
approvedRequest.setId(requestId);
|
|
approvedRequest.setStatus(com.hithomelabs.cftunnels.Entity.Request.RequestStatus.APPROVED);
|
|
|
|
when(mappingRequestService.approveRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenReturn(approvedRequest);
|
|
when(userRepository.findByEmail("approver@example.com"))
|
|
.thenReturn(java.util.Optional.of(approverUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/approve", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("approver", Groups.SYSTEM_ADMIN, "approver@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.status").value("APPROVED"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 404 when request not found")
|
|
void approveMappingRequest_NotFound() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User approverUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
approverUser.setEmail("approver@example.com");
|
|
approverUser.setName("Approver");
|
|
|
|
when(mappingRequestService.approveRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenThrow(new NoSuchElementException("Request not found"));
|
|
when(userRepository.findByEmail("approver@example.com"))
|
|
.thenReturn(java.util.Optional.of(approverUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/approve", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("approver", Groups.SYSTEM_ADMIN, "approver@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isNotFound());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 500 when mapping creation fails")
|
|
void approveMappingRequest_InternalServerError() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User approverUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
approverUser.setEmail("approver@example.com");
|
|
approverUser.setName("Approver");
|
|
|
|
when(mappingRequestService.approveRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenThrow(new RuntimeException("Failed to add mapping to Cloudflare"));
|
|
when(userRepository.findByEmail("approver@example.com"))
|
|
.thenReturn(java.util.Optional.of(approverUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/approve", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("approver", Groups.SYSTEM_ADMIN, "approver@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isInternalServerError());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should reject mapping request successfully")
|
|
void rejectMappingRequest_Success() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User rejecterUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
rejecterUser.setEmail("rejecter@example.com");
|
|
rejecterUser.setName("Rejecter");
|
|
|
|
com.hithomelabs.cftunnels.Entity.Request rejectedRequest = new com.hithomelabs.cftunnels.Entity.Request();
|
|
rejectedRequest.setId(requestId);
|
|
rejectedRequest.setStatus(com.hithomelabs.cftunnels.Entity.Request.RequestStatus.REJECTED);
|
|
|
|
when(mappingRequestService.rejectRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenReturn(rejectedRequest);
|
|
when(userRepository.findByEmail("rejecter@example.com"))
|
|
.thenReturn(java.util.Optional.of(rejecterUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/reject", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("rejecter", Groups.SYSTEM_ADMIN, "rejecter@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.status").value("REJECTED"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 404 when rejecting non-existent request")
|
|
void rejectMappingRequest_NotFound() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User rejecterUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
rejecterUser.setEmail("rejecter@example.com");
|
|
rejecterUser.setName("Rejecter");
|
|
|
|
when(mappingRequestService.rejectRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenThrow(new NoSuchElementException("Request not found"));
|
|
when(userRepository.findByEmail("rejecter@example.com"))
|
|
.thenReturn(java.util.Optional.of(rejecterUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/reject", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("rejecter", Groups.SYSTEM_ADMIN, "rejecter@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isNotFound());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 409 when rejecting already processed request")
|
|
void rejectMappingRequest_Conflict() throws Exception {
|
|
UUID requestId = UUID.randomUUID();
|
|
com.hithomelabs.cftunnels.Entity.User rejecterUser = new com.hithomelabs.cftunnels.Entity.User();
|
|
rejecterUser.setEmail("rejecter@example.com");
|
|
rejecterUser.setName("Rejecter");
|
|
|
|
when(mappingRequestService.rejectRequest(eq(requestId), any(com.hithomelabs.cftunnels.Entity.User.class)))
|
|
.thenThrow(new IllegalStateException("Request is not in PENDING status"));
|
|
when(userRepository.findByEmail("rejecter@example.com"))
|
|
.thenReturn(java.util.Optional.of(rejecterUser));
|
|
|
|
mockMvc.perform(put("/cloudflare/requests/{requestId}/reject", requestId)
|
|
.with(oauth2Login().oauth2User(buildOidcUserWithEmail("rejecter", Groups.SYSTEM_ADMIN, "rejecter@example.com")))
|
|
.with(csrf()))
|
|
.andExpect(status().isConflict());
|
|
}
|
|
|
|
@Test
|
|
void getTunnelConfigurations() throws Exception {
|
|
|
|
Map<String, Object> tunnelData = Map.of("config", Map.of("result", "success", "ingress", "sample ingress object"));
|
|
ResponseEntity<Map> mockResponse = new ResponseEntity<>(tunnelData, HttpStatus.OK);
|
|
|
|
when(cloudflareAPIService.getCloudflareTunnelConfigurations(eq("sampleTunnelId"), any(RestTemplate.class), eq(Map.class))).thenReturn(mockResponse);
|
|
|
|
mockMvc.perform(get("/cloudflare/tunnels/{tunnelId}/mappings", "sampleTunnelId")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("username", Groups.HOMELAB_DEVELOPER))))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.data.config.ingress").value("sample ingress object"));
|
|
}
|
|
|
|
@Test
|
|
void addTunnelconfiguration() throws Exception {
|
|
|
|
when(restTemplateConfig.restTemplate()).thenReturn(new RestTemplate());
|
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
TunnelResponse tunnelStateBefore = mapper.readValue(withoutAdditionalIngress, TunnelResponse.class);
|
|
ResponseEntity<TunnelResponse> tunnelResponseBefore = new ResponseEntity<>(tunnelStateBefore, HttpStatus.OK);
|
|
|
|
when(cloudflareAPIService.getCloudflareTunnelConfigurations(eq("sampleTunnelId"), any(RestTemplate.class), eq(TunnelResponse.class))).thenReturn(tunnelResponseBefore);
|
|
|
|
TunnelResponse expectedTunnelConfig = mapper.readValue(withAdditionalIngress, TunnelResponse.class);
|
|
ResponseEntity<TunnelResponse> expectedHttpTunnelResponse = new ResponseEntity<>(expectedTunnelConfig, HttpStatus.OK);
|
|
when(cloudflareAPIService.putCloudflareTunnelConfigurations(eq("sampleTunnelId"), any(RestTemplate.class), eq(TunnelResponse.class), any(Config.class))).thenReturn(expectedHttpTunnelResponse);
|
|
|
|
mockMvc.perform(post("/cloudflare/tunnels/{tunnelId}/mappings", "sampleTunnelId")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content(ingressJson))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.data.result.config.ingress[*].hostname", hasItem("random.hithomelabs.com")));
|
|
}
|
|
|
|
private Request createTestRequest(UUID id, Request.RequestStatus status) {
|
|
Request request = new Request();
|
|
request.setId(id);
|
|
request.setStatus(status);
|
|
return request;
|
|
}
|
|
|
|
@Test
|
|
void deleteTunnelConfiguration() throws Exception {
|
|
|
|
when(restTemplateConfig.restTemplate()).thenReturn(new RestTemplate());
|
|
|
|
ObjectMapper mapper = new ObjectMapper();
|
|
TunnelResponse tunnelStateBefore = mapper.readValue(withAdditionalIngress, TunnelResponse.class);
|
|
ResponseEntity<TunnelResponse> tunnelResponseBefore = new ResponseEntity<>(tunnelStateBefore, HttpStatus.OK);
|
|
|
|
when(cloudflareAPIService.getCloudflareTunnelConfigurations(eq("sampleTunnelId"), any(RestTemplate.class), eq(TunnelResponse.class))).thenReturn(tunnelResponseBefore);
|
|
|
|
TunnelResponse expectedTunnelConfig = mapper.readValue(withoutAdditionalIngress, TunnelResponse.class);
|
|
ResponseEntity<TunnelResponse> expectedHttpTunnelResponse = new ResponseEntity<>(expectedTunnelConfig, HttpStatus.OK);
|
|
when(cloudflareAPIService.putCloudflareTunnelConfigurations(eq("sampleTunnelId"), any(RestTemplate.class), eq(TunnelResponse.class), any(Config.class))).thenReturn(expectedHttpTunnelResponse);
|
|
|
|
mockMvc.perform(delete("/cloudflare/tunnels/{tunnelId}/mappings", "sampleTunnelId")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf())
|
|
.contentType(MediaType.APPLICATION_JSON)
|
|
.content(ingressJson))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.data.result.config.ingress[*].hostname", not(hasItem("random.hithomelabs.com"))));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 200 OK with tunnel when tunnel is successfully updated")
|
|
void configureTunnelForEnvironment_Success() throws Exception {
|
|
Tunnel tunnel = new Tunnel(UUID.randomUUID(), "dev", "test-tunnel");
|
|
when(cloudflareAPIService.createOrUpdateTunnel(eq("test-tunnel-id"), any(String.class))).thenReturn(tunnel);
|
|
|
|
mockMvc.perform(put("/cloudflare/tunnels/configure/{tunnelId}", "test-tunnel-id")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf()))
|
|
.andExpect(status().isOk())
|
|
.andExpect(MockMvcResultMatchers.content().contentType(MediaType.APPLICATION_JSON))
|
|
.andExpect(jsonPath("$.name").value("test-tunnel"))
|
|
.andExpect(jsonPath("$.environment").value("dev"));
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 204 NO_CONTENT when tunnel does not need changes")
|
|
void configureTunnelForEnvironment_NoContent() throws Exception {
|
|
when(cloudflareAPIService.createOrUpdateTunnel(eq("test-tunnel-id"), any(String.class))).thenReturn(null);
|
|
|
|
mockMvc.perform(put("/cloudflare/tunnels/configure/{tunnelId}", "test-tunnel-id")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf()))
|
|
.andExpect(status().isNoContent());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 404 NOT_FOUND when tunnelId is not valid")
|
|
void configureTunnelForEnvironment_NotFound() throws Exception {
|
|
when(cloudflareAPIService.createOrUpdateTunnel(eq("invalid-tunnel-id"), any(String.class)))
|
|
.thenThrow(new NoSuchElementException("Tunnel not found"));
|
|
|
|
mockMvc.perform(put("/cloudflare/tunnels/configure/{tunnelId}", "invalid-tunnel-id")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf()))
|
|
.andExpect(status().isNotFound());
|
|
}
|
|
|
|
@Test
|
|
@DisplayName("should return 500 INTERNAL_SERVER_ERROR when runtime exception occurs")
|
|
void configureTunnelForEnvironment_InternalServerError() throws Exception {
|
|
when(cloudflareAPIService.createOrUpdateTunnel(eq("test-tunnel-id"), any(String.class)))
|
|
.thenThrow(new RuntimeException("Internal error"));
|
|
|
|
mockMvc.perform(put("/cloudflare/tunnels/configure/{tunnelId}", "test-tunnel-id")
|
|
.with(oauth2Login().oauth2User(buildOidcUser("admin", Groups.SYSTEM_ADMIN)))
|
|
.with(csrf()))
|
|
.andExpect(status().isInternalServerError());
|
|
}
|
|
|
|
|
|
}
|