Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 20 additions & 0 deletions .github/workflows/integration-test.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,26 @@ jobs:
--network-id devkit \
--openapi ../../api/src/main/resources/rosetta-specifications-1.4.15/api.yaml

- name: "Wait for indexer data to be ready (stage: LIVE)"
run: |
echo "Waiting for Rosetta API network status stage to be LIVE..."
for i in {1..60}; do
STAGE=$(curl -s -X POST http://localhost:8082/network/status \
-H 'Content-Type: application/json' \
-d '{"network_identifier": {"blockchain": "cardano", "network": "devkit"}}' | \
jq -r '.sync_status.stage' 2>/dev/null || echo "UNKNOWN")

if [ "$STAGE" = "LIVE" ]; then
echo "✓ Indexer is ready and stage is LIVE!"
exit 0
fi

echo "Waiting for stage to be LIVE... Current stage: $STAGE ($i/60)"
sleep 5
done
echo "❌ Indexer failed to reach LIVE stage within 5 minutes"
exit 1

- name: "Run rosetta check:data tests"
run: ./bin/rosetta-cli check:data --configuration-file ./rosetta-cli-tests/data/byron_sample.json

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,26 @@ public void init() {
*/
@Nullable
public Optional<SyncStatus> calculateSyncStatus(BlockIdentifierExtended latestBlock) {
return offlineSlotService.getCurrentSlotBasedOnTime().map(slotBasedOnTime -> {
Optional<Long> currentSlotBasedOnTimeOpt = offlineSlotService.getCurrentSlotBasedOnTime();

if (currentSlotBasedOnTimeOpt.isEmpty()) {
// When current slot cannot be determined based on time (e.g. on DevKit where slot converters are null),
// we assume the tip is reached and we check if the required database indexes are ready.
boolean indexesNotReady = indexCreationMonitor.isCreatingIndexes();
SyncStage stage = indexesNotReady ? SyncStage.APPLYING_INDEXES : SyncStage.LIVE;
boolean isSynced = !indexesNotReady;

log.info("[SyncStatus] Converters unavailable (devkit). Returning status based on index readiness. Stage: {}, Synced: {}", stage, isSynced);

return Optional.of(SyncStatus.builder()
.targetIndex(latestBlock.getSlot())
.currentIndex(latestBlock.getSlot())
.synced(isSynced)
.stage(stage.getValue())
.build());
}

return currentSlotBasedOnTimeOpt.map(slotBasedOnTime -> {
long slotBasedOnLatestBlock = latestBlock.getSlot();

// Check if node has reached the tip
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -128,20 +128,36 @@ void shouldReturnNotSyncedWhenNotReachedTip() {
}

@Test
@DisplayName("Should return empty when current slot cannot be determined")
void shouldReturnEmptyWhenCurrentSlotUnavailable() {
@DisplayName("Should return status based on index readiness when current slot cannot be determined (e.g. devkit)")
void shouldReturnStatusBasedOnIndexesWhenCurrentSlotUnavailable() {
// Given
BlockIdentifierExtended latestBlock = BlockIdentifierExtended.builder()
.slot(1000L)
.build();

when(offlineSlotService.getCurrentSlotBasedOnTime()).thenReturn(Optional.empty());
when(indexCreationMonitor.isCreatingIndexes()).thenReturn(false);

// When
Optional<SyncStatus> result = syncStatusService.calculateSyncStatus(latestBlock);

// Then
assertThat(result).isEmpty();
assertThat(result).isPresent();
assertThat(result.get().getSynced()).isTrue();
assertThat(result.get().getStage()).isEqualTo(SyncStage.LIVE.getValue());
assertThat(result.get().getTargetIndex()).isEqualTo(1000L);
assertThat(result.get().getCurrentIndex()).isEqualTo(1000L);

// And given indexes are not ready
when(indexCreationMonitor.isCreatingIndexes()).thenReturn(true);

// When
result = syncStatusService.calculateSyncStatus(latestBlock);

// Then
assertThat(result).isPresent();
assertThat(result.get().getSynced()).isFalse();
assertThat(result.get().getStage()).isEqualTo(SyncStage.APPLYING_INDEXES.getValue());
}

@Test
Expand Down
Loading