add missed files
Some checks failed
CD / build-and-push (push) Successful in 4m11s
CD / deploy (push) Failing after 2s

This commit is contained in:
RM
2026-10-15 00:58:44 +03:00
parent 5e77a63aff
commit a4067202ec
11 changed files with 2134 additions and 0 deletions

View File

@@ -0,0 +1,18 @@
package com.pledge.torgi.config;
import org.springframework.context.annotation.Configuration;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurer;
@Configuration
public class WebConfig implements WebMvcConfigurer {
@Override
public void addCorsMappings(CorsRegistry registry) {
registry.addMapping("/api/**")
.allowedOrigins("http://localhost:5173", "http://localhost:3000")
.allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS")
.allowCredentials(false)
.maxAge(3600);
}
}

View File

@@ -0,0 +1,48 @@
package com.pledge.torgi.controller.api;
import com.pledge.torgi.model.TorgiEvent;
import com.pledge.torgi.repositories.TorgiEventRepository;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.ExampleMatcher;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.http.HttpStatus;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.server.ResponseStatusException;
@RestController
@RequestMapping("/api/events")
public class EventController {
private final TorgiEventRepository repository;
public EventController(TorgiEventRepository repository) {
this.repository = repository;
}
@GetMapping
public Page<TorgiEvent> list(@RequestParam(required = false) String cadastral,
@RequestParam(required = false) String status,
@PageableDefault(size = 20, sort = "createdAt", direction = Sort.Direction.DESC) Pageable pageable) {
TorgiEvent probe = new TorgiEvent();
probe.setCadastral(cadastral);
probe.setStatus(status);
ExampleMatcher matcher = ExampleMatcher.matchingAll()
.withIgnoreNullValues()
.withIgnoreCase()
.withStringMatcher(ExampleMatcher.StringMatcher.CONTAINING);
return repository.findAll(Example.of(probe, matcher), pageable);
}
@GetMapping("/{id}")
public TorgiEvent get(@PathVariable Long id) {
return repository.findById(id)
.orElseThrow(() -> new ResponseStatusException(HttpStatus.NOT_FOUND, "Event not found: " + id));
}
}

View File

@@ -0,0 +1,27 @@
package com.pledge.torgi.controller.api;
import com.pledge.torgi.model.MissedData;
import com.pledge.torgi.repositories.MissedDataRepository;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.data.domain.Sort;
import org.springframework.data.web.PageableDefault;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
@RestController
@RequestMapping("/api/missed")
public class MissedDataController {
private final MissedDataRepository repository;
public MissedDataController(MissedDataRepository repository) {
this.repository = repository;
}
@GetMapping
public Page<MissedData> list(@PageableDefault(size = 20, sort = "id", direction = Sort.Direction.DESC) Pageable pageable) {
return repository.findAll(pageable);
}
}

View File

@@ -0,0 +1,81 @@
package com.pledge.torgi.controller.api;
import com.pledge.torgi.model.TorgiEvent;
import com.pledge.torgi.repositories.TorgiEventRepository;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.ArgumentCaptor;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.data.domain.Example;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.PageImpl;
import org.springframework.data.domain.PageRequest;
import org.springframework.data.domain.Pageable;
import org.springframework.web.server.ResponseStatusException;
import java.util.List;
import java.util.Optional;
import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.mockito.ArgumentMatchers.any;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;
@ExtendWith(MockitoExtension.class)
class EventControllerTest {
@Mock
private TorgiEventRepository repository;
@InjectMocks
private EventController controller;
@Test
void list_shouldPassFiltersAndPageableToRepository() {
// given
TorgiEvent event = new TorgiEvent();
event.setKey("key-1");
Page<TorgiEvent> page = new PageImpl<>(List.of(event));
when(repository.findAll(any(Example.class), any(Pageable.class))).thenReturn(page);
Pageable pageable = PageRequest.of(0, 20);
// when
Page<TorgiEvent> result = controller.list("77:01", "PUBLISHED", pageable);
// then
assertThat(result.getContent()).containsExactly(event);
ArgumentCaptor<Example<TorgiEvent>> exampleCaptor = ArgumentCaptor.forClass(Example.class);
verify(repository).findAll(exampleCaptor.capture(), eq(pageable));
assertThat(exampleCaptor.getValue().getProbe().getCadastral()).isEqualTo("77:01");
assertThat(exampleCaptor.getValue().getProbe().getStatus()).isEqualTo("PUBLISHED");
}
@Test
void get_shouldReturnEvent() {
// given
TorgiEvent event = new TorgiEvent();
event.setKey("key-1");
when(repository.findById(1L)).thenReturn(Optional.of(event));
// when
TorgiEvent result = controller.get(1L);
// then
assertThat(result).isSameAs(event);
}
@Test
void get_shouldThrow404WhenMissing() {
// given
when(repository.findById(42L)).thenReturn(Optional.empty());
// when / then
assertThatThrownBy(() -> controller.get(42L))
.isInstanceOf(ResponseStatusException.class)
.hasMessageContaining("404");
}
}

View File

@@ -0,0 +1,61 @@
package com.pledge.torgi.service;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.retry.annotation.Backoff;
import org.springframework.retry.annotation.EnableRetry;
import org.springframework.retry.annotation.Retryable;
import org.springframework.test.context.ContextConfiguration;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import java.io.UncheckedIOException;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Map;
import static org.assertj.core.api.Assertions.assertThat;
@ExtendWith(SpringExtension.class)
@ContextConfiguration(classes = DownloadHeadlessRetryTest.RetryConfig.class)
class DownloadHeadlessRetryTest {
@Configuration
@EnableRetry
static class RetryConfig {
@Bean
DownloadHeadlessService downloadHeadlessService() {
return new DownloadHeadlessService();
}
}
@Autowired
private DownloadHeadlessService service;
@Test
void downloadExcel_shouldBeRetryable() throws Exception {
Method method = DownloadHeadlessService.class.getMethod("downloadExcel", String.class);
Retryable retryable = method.getAnnotation(Retryable.class);
assertThat(retryable).isNotNull();
assertThat(retryable.maxAttempts()).isEqualTo(11);
assertThat(Arrays.asList(retryable.retryFor())).contains(UncheckedIOException.class);
Backoff backoff = retryable.backoff();
assertThat(backoff.delay()).isEqualTo(1000);
}
@Test
void downloadExcelFallback_shouldReturnEmptyMap() {
Map<String, Lot> result = new DownloadHeadlessService()
.downloadExcelFallback(new RuntimeException("boom"), "http://example.com/file.xlsx");
assertThat(result).isEmpty();
}
@Test
void downloadExcel_shouldRetryAndRecoverToEmptyMap() {
// connection refused -> UncheckedIOException on every attempt -> @Recover fallback
Map<String, Lot> result = service.downloadExcel("http://127.0.0.1:1/missing.xlsx");
assertThat(result).isEmpty();
}
}