Skip to content

Commit

Permalink
Add New Endpoint/Scheduler to Clean Up Empty Collections (#4)
Browse files Browse the repository at this point in the history
  • Loading branch information
bibekaryal86 authored Oct 18, 2024
1 parent b7483dc commit f1a4d33
Show file tree
Hide file tree
Showing 4 changed files with 104 additions and 6 deletions.
3 changes: 0 additions & 3 deletions .github/workflows/gradle.yml
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,3 @@ jobs:

- name: Build with Gradle
run: ./gradlew clean build

- name: Test with Gradle
run: ./gradlew clean test
2 changes: 2 additions & 0 deletions app/src/main/java/env/service/App.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,11 @@
import lombok.extern.slf4j.Slf4j;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import org.springframework.scheduling.annotation.EnableScheduling;

@Slf4j
@SpringBootApplication
@EnableScheduling
public class App {

public static void main(final String[] args) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;
import org.springframework.web.bind.annotation.DeleteMapping;
Expand All @@ -32,6 +33,20 @@ public class EnvDetailsController {

private final MongoTemplate mongoTemplate;

@Scheduled(cron = "0 0 22 * * *")
void cleanupEmptyCollections() {
try {
for (String collectionName : mongoTemplate.getCollectionNames()) {
if (mongoTemplate.getCollection(collectionName).countDocuments() == 0) {
mongoTemplate.dropCollection(collectionName);
log.info("Cleaned Up Empty Collection: [{}]", collectionName);
}
}
} catch (Exception ex) {
log.error("Cleanup Empty Collections Exception", ex);
}
}

@GetMapping("/appNames")
public ResponseEntity<EnvDetailsResponse> getAllAppNames() {
try {
Expand All @@ -53,6 +68,26 @@ public ResponseEntity<EnvDetailsResponse> getAllAppNames() {
}
}

@DeleteMapping("/appNames")
public ResponseEntity<EnvDetailsResponse> deleteEmptyAppNames() {
try {
for (String collectionName : mongoTemplate.getCollectionNames()) {
if (mongoTemplate.getCollection(collectionName).countDocuments() == 0) {
mongoTemplate.dropCollection(collectionName);
log.info("Dropped Empty Collection: [{}]", collectionName);
}
}
return ResponseEntity.ok().build();
} catch (Exception ex) {
log.error("Delete Empty App Names Exception", ex);
return ResponseEntity.internalServerError()
.body(
EnvDetailsResponse.builder()
.errMsg("Delete Empty App Names Exception: " + ex.getMessage())
.build());
}
}

@PostMapping("/{appName}")
public ResponseEntity<EnvDetailsResponse> create(
@PathVariable final String appName, @RequestBody final EnvDetails envDetails) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
import static org.junit.jupiter.api.Assertions.assertTrue;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.never;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
Expand All @@ -16,6 +19,7 @@

import com.fasterxml.jackson.databind.ObjectMapper;
import com.mongodb.MongoInternalException;
import com.mongodb.client.MongoCollection;
import com.mongodb.client.result.DeleteResult;
import env.service.app.config.TestSecurityConfig;
import env.service.app.model.EnvDetails;
Expand All @@ -29,9 +33,7 @@
import java.util.Set;
import org.bson.types.ObjectId;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.MethodOrderer;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
import org.mockito.Mockito;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.autoconfigure.EnableAutoConfiguration;
Expand All @@ -52,7 +54,6 @@
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ActiveProfiles("springboottest")
@Import({TestSecurityConfig.class})
@TestMethodOrder(MethodOrderer.OrderAnnotation.class)
@EnableAutoConfiguration(exclude = MongoAutoConfiguration.class)
@AutoConfigureMockMvc
public class EnvDetailsControllerTest {
Expand Down Expand Up @@ -161,6 +162,69 @@ void test_GetAllAppNames_Failure_Exception() throws Exception {
"Look App Names Exception: Mongo Internal Exception", envDetailsResponse.getErrMsg());
}

@Test
void test_DeleteEmptyAppNames_Success() throws Exception {
when(mongoTemplate.getCollectionNames()).thenReturn(Set.of("app_one", "app_two", "app_three"));
when(mongoTemplate.getCollection("app_one")).thenReturn(mock(MongoCollection.class));
when(mongoTemplate.getCollection("app_two")).thenReturn(mock(MongoCollection.class));
when(mongoTemplate.getCollection("app_three")).thenReturn(mock(MongoCollection.class));
when(mongoTemplate.getCollection("app_one").countDocuments()).thenReturn(0L);
when(mongoTemplate.getCollection("app_two").countDocuments()).thenReturn(1L);
when(mongoTemplate.getCollection("app_three").countDocuments()).thenReturn(2L);

mockMvc
.perform(
delete("/api/v1/appNames")
.with(
SecurityMockMvcRequestPostProcessors.httpBasic(
ConstantUtils.AUTH_USR, ConstantUtils.AUTH_PWD)))
.andExpect(status().isOk())
.andReturn();

verify(mongoTemplate).dropCollection("app_one");
verify(mongoTemplate, never()).dropCollection("app_two");
verify(mongoTemplate, never()).dropCollection("app_three");
}

@Test
void test_DeleteEmptyAppNames_Failure_Unauthorized() throws Exception {
mockMvc
.perform(
delete("/api/v1/appNames")
.with(
SecurityMockMvcRequestPostProcessors.httpBasic(
ConstantUtils.AUTH_USR, "invalid_password")))
.andExpect(status().isUnauthorized())
.andReturn();
}

@Test
void test_DeleteEmptyAppNames_Failure_Exception() throws Exception {
when(mongoTemplate.getCollectionNames())
.thenThrow(new MongoInternalException("Mongo Internal Exception"));

MvcResult mvcResult =
mockMvc
.perform(
delete("/api/v1/appNames")
.with(
SecurityMockMvcRequestPostProcessors.httpBasic(
ConstantUtils.AUTH_USR, ConstantUtils.AUTH_PWD)))
.andExpect(status().isInternalServerError())
.andReturn();

EnvDetailsResponse envDetailsResponse =
objectMapper()
.readValue(mvcResult.getResponse().getContentAsString(), EnvDetailsResponse.class);

assertNotNull(envDetailsResponse);
assertNull(envDetailsResponse.getEnvDetails());
assertNotNull(envDetailsResponse.getErrMsg());
assertEquals(
"Delete Empty App Names Exception: Mongo Internal Exception",
envDetailsResponse.getErrMsg());
}

@Test
void test_Create_Success() throws Exception {
when(mongoTemplate.save(any(EnvDetails.class), eq("app_" + TEST_COLLECTION_NAME)))
Expand Down

0 comments on commit f1a4d33

Please sign in to comment.