package com.dalab.discovery.crawler.callable; import static org.junit.jupiter.api.Assertions.*; import static org.mockito.ArgumentMatchers.*; import static org.mockito.Mockito.*; import java.util.List; import java.util.Map; import java.util.UUID; import org.junit.jupiter.api.AfterEach; 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.MockitoAnnotations; import org.mockito.junit.jupiter.MockitoExtension; import com.dalab.discovery.catalog.persistence.IResourceCrawlerRegistry; import com.dalab.discovery.catalog.service.ICatalogService; import com.dalab.discovery.common.model.CloudResource; import com.dalab.discovery.common.model.DiscoveryJob; import com.dalab.discovery.common.model.enums.CloudProvider; import com.dalab.discovery.crawler.service.IResourceCrawler; import com.dalab.discovery.job.JobType; import com.dalab.discovery.job.callable.ResourceCrawlerCallable; /** * Unit tests for ResourceCrawlerCallable. */ @ExtendWith(MockitoExtension.class) public class ResourceCrawlerCallableTest { @Mock private IResourceCrawlerRegistry crawlerRegistry; @Mock private IResourceCrawler crawler1; @Mock private IResourceCrawler crawler2; @Mock private ICatalogService catalogService; private DiscoveryJob job; private ResourceCrawlerCallable callable; private AutoCloseable closeable; @BeforeEach void setUp() { closeable = MockitoAnnotations.openMocks(this); job = new DiscoveryJob(UUID.randomUUID()); job.setJobType(JobType.RESOURCE_CRAWLER); job.setCloudProvider(CloudProvider.GCP); job.setAccountId("test-account"); callable = new ResourceCrawlerCallable(job, crawlerRegistry, catalogService); } @AfterEach void tearDown() throws Exception { closeable.close(); } @Test void call_NoCrawlersFound_ReturnsFalse() throws Exception { when(crawlerRegistry.getCrawlersForProvider(CloudProvider.GCP)).thenReturn(List.of()); Boolean result = callable.call(); assertFalse(result); verify(crawlerRegistry).getCrawlersForProvider(CloudProvider.GCP); verifyNoInteractions(crawler1, crawler2, catalogService); } @Test void call_CrawlersFound_TriggersCrawlersAndReturnsTrue() throws Exception { when(crawlerRegistry.getCrawlersForProvider(CloudProvider.GCP)).thenReturn(List.of(crawler1, crawler2)); doNothing().when(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); doNothing().when(crawler2).discoverResourcesAsync(eq("test-account"), anyMap()); Boolean result = callable.call(); assertTrue(result); verify(crawlerRegistry).getCrawlersForProvider(CloudProvider.GCP); verify(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); verify(crawler2).discoverResourcesAsync(eq("test-account"), anyMap()); } @Test void call_WithSpecificResourceTypes_UsesGetCrawlersForTypes() throws Exception { List typeNames = List.of("type1", "type2"); job.setParameters(Map.of("resourceTypesToCrawl", typeNames)); callable = new ResourceCrawlerCallable(job, crawlerRegistry, catalogService); when(crawlerRegistry.getCrawlersForTypes(eq(CloudProvider.GCP), anyList())).thenReturn(List.of(crawler1)); doNothing().when(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); Boolean result = callable.call(); assertTrue(result); verify(crawlerRegistry).getCrawlersForTypes(eq(CloudProvider.GCP), anyList()); verify(crawlerRegistry, never()).getCrawlersForProvider(any()); verify(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); } @Test void call_CrawlerTriggerFails_ContinuesAndReturnsTrueIfAnySucceed() throws Exception { when(crawlerRegistry.getCrawlersForProvider(CloudProvider.GCP)).thenReturn(List.of(crawler1, crawler2)); doThrow(new RuntimeException("Trigger failed!")).when(crawler1).discoverResourcesAsync(anyString(), anyMap()); doNothing().when(crawler2).discoverResourcesAsync(eq("test-account"), anyMap()); Boolean result = callable.call(); assertTrue(result); verify(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); verify(crawler2).discoverResourcesAsync(eq("test-account"), anyMap()); } @Test void call_AllCrawlerTriggersFail_ReturnsFalse() throws Exception { when(crawlerRegistry.getCrawlersForProvider(CloudProvider.GCP)).thenReturn(List.of(crawler1, crawler2)); doThrow(new RuntimeException("Trigger failed!")).when(crawler1).discoverResourcesAsync(anyString(), anyMap()); doThrow(new RuntimeException("Trigger failed too!")).when(crawler2).discoverResourcesAsync(anyString(), anyMap()); Boolean result = callable.call(); assertFalse(result); verify(crawler1).discoverResourcesAsync(eq("test-account"), anyMap()); verify(crawler2).discoverResourcesAsync(eq("test-account"), anyMap()); } }