|
8 | 8 | import static org.junit.jupiter.api.Assertions.assertEquals;
|
9 | 9 | import static org.junit.jupiter.api.Assertions.assertFalse;
|
10 | 10 | import static org.junit.jupiter.api.Assertions.assertNotEquals;
|
| 11 | +import static org.junit.jupiter.api.Assertions.assertNotNull; |
| 12 | +import static org.junit.jupiter.api.Assertions.assertNull; |
11 | 13 | import static org.junit.jupiter.api.Assertions.assertTrue;
|
12 | 14 | import static org.mockito.ArgumentMatchers.any;
|
13 | 15 | import static org.mockito.ArgumentMatchers.eq;
|
|
23 | 25 | import com.fasterxml.jackson.databind.node.ObjectNode;
|
24 | 26 | import com.google.common.collect.Lists;
|
25 | 27 | import io.airbyte.api.model.generated.ActorDefinitionVersionRead;
|
| 28 | +import io.airbyte.api.model.generated.ActorStatus; |
26 | 29 | import io.airbyte.api.model.generated.AirbyteCatalog;
|
27 | 30 | import io.airbyte.api.model.generated.AirbyteStream;
|
28 | 31 | import io.airbyte.api.model.generated.AirbyteStreamAndConfiguration;
|
|
67 | 70 | import io.airbyte.api.model.generated.SynchronousJobRead;
|
68 | 71 | import io.airbyte.api.model.generated.Tag;
|
69 | 72 | import io.airbyte.api.model.generated.WebBackendConnectionCreate;
|
| 73 | +import io.airbyte.api.model.generated.WebBackendConnectionListFilters; |
70 | 74 | import io.airbyte.api.model.generated.WebBackendConnectionListItem;
|
71 | 75 | import io.airbyte.api.model.generated.WebBackendConnectionListRequestBody;
|
| 76 | +import io.airbyte.api.model.generated.WebBackendConnectionListSortKey; |
72 | 77 | import io.airbyte.api.model.generated.WebBackendConnectionRead;
|
73 | 78 | import io.airbyte.api.model.generated.WebBackendConnectionReadList;
|
74 | 79 | import io.airbyte.api.model.generated.WebBackendConnectionRequestBody;
|
|
119 | 124 | import io.airbyte.data.services.PartialUserConfigService;
|
120 | 125 | import io.airbyte.data.services.SourceService;
|
121 | 126 | import io.airbyte.data.services.WorkspaceService;
|
| 127 | +import io.airbyte.data.services.shared.ConnectionFilters; |
| 128 | +import io.airbyte.data.services.shared.ConnectionSortKey; |
122 | 129 | import io.airbyte.data.services.shared.DestinationAndDefinition;
|
123 | 130 | import io.airbyte.data.services.shared.SourceAndDefinition;
|
124 | 131 | import io.airbyte.data.services.shared.StandardSyncQuery;
|
|
150 | 157 | import org.junit.jupiter.api.BeforeEach;
|
151 | 158 | import org.junit.jupiter.api.Test;
|
152 | 159 | import org.junit.jupiter.params.ParameterizedTest;
|
| 160 | +import org.junit.jupiter.params.provider.MethodSource; |
153 | 161 | import org.junit.jupiter.params.provider.ValueSource;
|
154 | 162 | import org.mockito.ArgumentCaptor;
|
155 | 163 | import org.mockito.InOrder;
|
@@ -331,8 +339,10 @@ void setup() throws IOException, JsonValidationException, ConfigNotFoundExceptio
|
331 | 339 | final StandardSync brokenStandardSync =
|
332 | 340 | ConnectionHelpers.generateSyncWithSourceAndDestinationId(source.getSourceId(), destination.getDestinationId(), true, Status.INACTIVE);
|
333 | 341 |
|
334 |
| - when(connectionService.listWorkspaceStandardSyncs(new StandardSyncQuery(sourceRead.getWorkspaceId(), List.of(), List.of(), false))) |
| 342 | + when(connectionService.listWorkspaceStandardSyncs(any(StandardSyncQuery.class))) |
335 | 343 | .thenReturn(Collections.singletonList(standardSync));
|
| 344 | + when(connectionService.countWorkspaceStandardSyncs(any(StandardSyncQuery.class), any())) |
| 345 | + .thenReturn(1); |
336 | 346 | when(sourceService.getSourceAndDefinitionsFromSourceIds(Collections.singletonList(source.getSourceId())))
|
337 | 347 | .thenReturn(Collections.singletonList(new SourceAndDefinition(source, sourceDefinition)));
|
338 | 348 | when(destinationService.getDestinationAndDefinitionsFromDestinationIds(Collections.singletonList(destination.getDestinationId())))
|
@@ -375,6 +385,17 @@ void setup() throws IOException, JsonValidationException, ConfigNotFoundExceptio
|
375 | 385 | .name("Test Operation")));
|
376 | 386 |
|
377 | 387 | final Instant now = Instant.now();
|
| 388 | + |
| 389 | + // Mock cursor pagination with job info using the fixed timestamp |
| 390 | + when(connectionService.listWorkspaceStandardSyncsCursorPaginated(any(StandardSyncQuery.class), any())) |
| 391 | + .thenReturn(Collections.singletonList( |
| 392 | + new io.airbyte.data.services.shared.ConnectionWithJobInfo( |
| 393 | + standardSync, |
| 394 | + "source", |
| 395 | + "destination", |
| 396 | + Optional.of(io.airbyte.db.instance.jobs.jooq.generated.enums.JobStatus.succeeded), |
| 397 | + Optional.of(java.time.OffsetDateTime.ofInstant(now, java.time.ZoneOffset.UTC))))); |
| 398 | + |
378 | 399 | final JobWithAttemptsRead jobRead = new JobWithAttemptsRead()
|
379 | 400 | .job(new JobRead()
|
380 | 401 | .configId(connectionRead.getConnectionId().toString())
|
@@ -1672,4 +1693,135 @@ void testGetSchemaChangeNotBreaking() {
|
1672 | 1693 | Optional.of(catalogId), Optional.of(new ActorCatalogFetchEvent().withActorCatalogId(differentCatalogId))));
|
1673 | 1694 | }
|
1674 | 1695 |
|
| 1696 | + @Test |
| 1697 | + void testParseSortKeyAllValues() { |
| 1698 | + // Test null sort key defaults to CONNECTION_NAME ascending |
| 1699 | + final WebBackendConnectionsHandler.SortKeyInfo result = wbHandler.parseSortKey(null); |
| 1700 | + assertEquals(ConnectionSortKey.CONNECTION_NAME, result.sortKey()); |
| 1701 | + assertTrue(result.ascending()); |
| 1702 | + |
| 1703 | + // Test all sort key enum values |
| 1704 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.CONNECTION_NAME, true), |
| 1705 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.CONNECTION_NAME_ASC)); |
| 1706 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.CONNECTION_NAME, false), |
| 1707 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.CONNECTION_NAME_DESC)); |
| 1708 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.SOURCE_NAME, true), |
| 1709 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.SOURCE_NAME_ASC)); |
| 1710 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.SOURCE_NAME, false), |
| 1711 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.SOURCE_NAME_DESC)); |
| 1712 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.DESTINATION_NAME, true), |
| 1713 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.DESTINATION_NAME_ASC)); |
| 1714 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.DESTINATION_NAME, false), |
| 1715 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.DESTINATION_NAME_DESC)); |
| 1716 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.LAST_SYNC, true), |
| 1717 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.LAST_SYNC_ASC)); |
| 1718 | + assertEquals(new WebBackendConnectionsHandler.SortKeyInfo(ConnectionSortKey.LAST_SYNC, false), |
| 1719 | + wbHandler.parseSortKey(WebBackendConnectionListSortKey.LAST_SYNC_DESC)); |
| 1720 | + } |
| 1721 | + |
| 1722 | + @Test |
| 1723 | + void testBuildConnectionFiltersNull() { |
| 1724 | + assertNull(wbHandler.buildConnectionFilters(null)); |
| 1725 | + } |
| 1726 | + |
| 1727 | + @Test |
| 1728 | + void testBuildConnectionFiltersEmpty() { |
| 1729 | + final WebBackendConnectionListFilters filters = new WebBackendConnectionListFilters(); |
| 1730 | + final ConnectionFilters result = wbHandler.buildConnectionFilters(filters); |
| 1731 | + |
| 1732 | + assertNotNull(result); |
| 1733 | + assertNull(result.getSearchTerm()); |
| 1734 | + |
| 1735 | + // Empty lists are returned instead of null for collection fields |
| 1736 | + assertTrue(result.getSourceDefinitionIds().isEmpty()); |
| 1737 | + assertTrue(result.getDestinationDefinitionIds().isEmpty()); |
| 1738 | + assertTrue(result.getStatuses().isEmpty()); |
| 1739 | + assertTrue(result.getStates().isEmpty()); |
| 1740 | + assertTrue(result.getTagIds().isEmpty()); |
| 1741 | + } |
| 1742 | + |
| 1743 | + @ParameterizedTest |
| 1744 | + @MethodSource("provideFilterTestCases") |
| 1745 | + void testBuildConnectionFiltersWithAllFields(String testName, |
| 1746 | + WebBackendConnectionListFilters filters, |
| 1747 | + String expectedSearchTerm, |
| 1748 | + int expectedSourceDefIds, |
| 1749 | + int expectedDestDefIds, |
| 1750 | + int expectedStatuses, |
| 1751 | + int expectedStates, |
| 1752 | + int expectedTagIds) { |
| 1753 | + final ConnectionFilters result = wbHandler.buildConnectionFilters(filters); |
| 1754 | + |
| 1755 | + assertNotNull(result); |
| 1756 | + assertEquals(expectedSearchTerm, result.getSearchTerm()); |
| 1757 | + assertEquals(expectedSourceDefIds, result.getSourceDefinitionIds().size()); |
| 1758 | + assertEquals(expectedDestDefIds, result.getDestinationDefinitionIds().size()); |
| 1759 | + assertEquals(expectedStatuses, result.getStatuses().size()); |
| 1760 | + assertEquals(expectedStates, result.getStates().size()); |
| 1761 | + assertEquals(expectedTagIds, result.getTagIds().size()); |
| 1762 | + } |
| 1763 | + |
| 1764 | + static Object[][] provideFilterTestCases() { |
| 1765 | + final UUID sourceDefId1 = UUID.randomUUID(); |
| 1766 | + final UUID sourceDefId2 = UUID.randomUUID(); |
| 1767 | + final UUID destDefId = UUID.randomUUID(); |
| 1768 | + final UUID tagId1 = UUID.randomUUID(); |
| 1769 | + final UUID tagId2 = UUID.randomUUID(); |
| 1770 | + |
| 1771 | + return new Object[][] { |
| 1772 | + // Search term only |
| 1773 | + { |
| 1774 | + "Search term only", |
| 1775 | + new WebBackendConnectionListFilters().searchTerm("test search"), |
| 1776 | + "test search", 0, 0, 0, 0, 0 |
| 1777 | + }, |
| 1778 | + // Source definition IDs only |
| 1779 | + { |
| 1780 | + "Source definition IDs only", |
| 1781 | + new WebBackendConnectionListFilters().sourceDefinitionIds(List.of(sourceDefId1, sourceDefId2)), |
| 1782 | + null, 2, 0, 0, 0, 0 |
| 1783 | + }, |
| 1784 | + // Destination definition IDs only |
| 1785 | + { |
| 1786 | + "Destination definition IDs only", |
| 1787 | + new WebBackendConnectionListFilters().destinationDefinitionIds(List.of(destDefId)), |
| 1788 | + null, 0, 1, 0, 0, 0 |
| 1789 | + }, |
| 1790 | + // Tag IDs only |
| 1791 | + { |
| 1792 | + "Tag IDs only", |
| 1793 | + new WebBackendConnectionListFilters().tagIds(List.of(tagId1, tagId2)), |
| 1794 | + null, 0, 0, 0, 0, 2 |
| 1795 | + }, |
| 1796 | + // Statuses only |
| 1797 | + { |
| 1798 | + "Statuses only", |
| 1799 | + new WebBackendConnectionListFilters().statuses(List.of( |
| 1800 | + WebBackendConnectionListFilters.StatusesEnum.HEALTHY, |
| 1801 | + WebBackendConnectionListFilters.StatusesEnum.FAILED)), |
| 1802 | + null, 0, 0, 2, 0, 0 |
| 1803 | + }, |
| 1804 | + // States only |
| 1805 | + { |
| 1806 | + "States only", |
| 1807 | + new WebBackendConnectionListFilters().states(List.of( |
| 1808 | + ActorStatus.ACTIVE, |
| 1809 | + ActorStatus.INACTIVE)), |
| 1810 | + null, 0, 0, 0, 2, 0 |
| 1811 | + }, |
| 1812 | + // Multiple filters combined |
| 1813 | + { |
| 1814 | + "Multiple filters combined", |
| 1815 | + new WebBackendConnectionListFilters() |
| 1816 | + .searchTerm("production") |
| 1817 | + .sourceDefinitionIds(List.of(sourceDefId1)) |
| 1818 | + .destinationDefinitionIds(List.of(destDefId)) |
| 1819 | + .statuses(List.of(WebBackendConnectionListFilters.StatusesEnum.HEALTHY)) |
| 1820 | + .states(List.of(ActorStatus.ACTIVE)) |
| 1821 | + .tagIds(List.of(tagId1)), |
| 1822 | + "production", 1, 1, 1, 1, 1 |
| 1823 | + } |
| 1824 | + }; |
| 1825 | + } |
| 1826 | + |
1675 | 1827 | }
|
0 commit comments