Skip to content

Commit 044b9e1

Browse files
[ci] unit test for re-ingest via store descriptor user version
Signed-off-by: Raymond Roestenburg <raymond.roestenburg@digitalasset.com>
1 parent b1f693f commit 044b9e1

File tree

1 file changed

+214
-123
lines changed

1 file changed

+214
-123
lines changed

apps/scan/src/test/scala/org/lfdecentralizedtrust/splice/store/db/ScanStoreTest.scala

Lines changed: 214 additions & 123 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import com.digitalasset.canton.concurrent.FutureSupervisor
66
import com.digitalasset.canton.crypto.Fingerprint
77
import com.digitalasset.canton.data.CantonTimestamp
88
import com.digitalasset.canton.lifecycle.FutureUnlessShutdown
9+
import com.digitalasset.canton.logging.SuppressionRule
910
import com.digitalasset.canton.resource.DbStorage
1011
import com.digitalasset.canton.topology.*
1112
import com.digitalasset.canton.tracing.TraceContext
@@ -58,6 +59,7 @@ import scala.jdk.OptionConverters.*
5859
import scala.math.BigDecimal.javaBigDecimal2bigDecimal
5960
import scala.reflect.ClassTag
6061
import org.lfdecentralizedtrust.splice.config.IngestionConfig
62+
import org.slf4j.event.Level
6163

6264
abstract class ScanStoreTest
6365
extends StoreTest
@@ -812,125 +814,8 @@ abstract class ScanStoreTest
812814
"listVoteRequestResults" should {
813815

814816
"list all past VoteRequestResult" in {
815-
for {
816-
store <- mkStore()
817-
voteRequestContract1 = voteRequest(
818-
requester = userParty(1),
819-
votes = (1 to 4)
820-
.map(n =>
821-
new Vote(
822-
userParty(n).toProtoPrimitive,
823-
true,
824-
new Reason("", ""),
825-
Optional.empty(),
826-
)
827-
),
828-
)
829-
_ <- dummyDomain.create(voteRequestContract1)(store.multiDomainAcsStore)
830-
result1 = mkVoteRequestResult(
831-
voteRequestContract1
832-
)
833-
_ <- dummyDomain.exercise(
834-
contract = dsoRules(dsoParty),
835-
interfaceId = Some(DsoRules.TEMPLATE_ID_WITH_PACKAGE_ID),
836-
choiceName = DsoRulesCloseVoteRequest.choice.name,
837-
mkCloseVoteRequest(
838-
voteRequestContract1.contractId
839-
),
840-
result1.toValue,
841-
)(
842-
store.multiDomainAcsStore
843-
)
844-
voteRequestContract2 = voteRequest(
845-
requester = userParty(2),
846-
votes = (1 to 4)
847-
.map(n =>
848-
new Vote(
849-
userParty(n).toProtoPrimitive,
850-
true,
851-
new Reason("", ""),
852-
Optional.empty(),
853-
)
854-
),
855-
)
856-
_ <- dummyDomain.create(voteRequestContract2)(store.multiDomainAcsStore)
857-
result2 = mkVoteRequestResult(
858-
voteRequestContract2,
859-
effectiveAt = Instant.now().plusSeconds(1).truncatedTo(ChronoUnit.MICROS),
860-
)
861-
_ <- dummyDomain.exercise(
862-
contract = dsoRules(dsoParty),
863-
interfaceId = Some(DsoRules.TEMPLATE_ID_WITH_PACKAGE_ID),
864-
choiceName = DsoRulesCloseVoteRequest.choice.name,
865-
mkCloseVoteRequest(
866-
voteRequestContract2.contractId
867-
),
868-
result2.toValue,
869-
)(
870-
store.multiDomainAcsStore
871-
)
872-
} yield {
873-
store
874-
.listVoteRequestResults(
875-
Some("AddSv"),
876-
Some(true),
877-
None,
878-
None,
879-
None,
880-
PageLimit.tryCreate(1),
881-
)
882-
.futureValue
883-
.toList
884-
.loneElement shouldBe result2
885-
store
886-
.listVoteRequestResults(
887-
Some("SRARC_AddSv"),
888-
Some(false),
889-
None,
890-
None,
891-
None,
892-
PageLimit.tryCreate(1),
893-
)
894-
.futureValue
895-
.toList
896-
.size shouldBe (0)
897-
store
898-
.listVoteRequestResults(
899-
None,
900-
None,
901-
None,
902-
None,
903-
None,
904-
PageLimit.tryCreate(1),
905-
)
906-
.futureValue
907-
.toList
908-
.size shouldBe (1)
909-
store
910-
.listVoteRequestResults(
911-
None,
912-
None,
913-
None,
914-
Some(Instant.now().truncatedTo(ChronoUnit.MICROS).plusSeconds(3600).toString),
915-
None,
916-
PageLimit.tryCreate(1),
917-
)
918-
.futureValue
919-
.toList
920-
.size shouldBe (0)
921-
store
922-
.listVoteRequestResults(
923-
None,
924-
None,
925-
None,
926-
Some(Instant.now().truncatedTo(ChronoUnit.MICROS).minusSeconds(3600).toString),
927-
None,
928-
PageLimit.tryCreate(1),
929-
)
930-
.futureValue
931-
.toList
932-
.size shouldBe (1)
933-
}
817+
val store = mkStore().futureValue
818+
assertListOfAllPastVoteRequestResults(store)
934819
}
935820
}
936821

@@ -1497,8 +1382,133 @@ abstract class ScanStoreTest
14971382
}
14981383
}
14991384

1385+
def assertListOfAllPastVoteRequestResults(store: ScanStore) = {
1386+
val voteRequestContract1 = voteRequest(
1387+
requester = userParty(1),
1388+
votes = (1 to 4)
1389+
.map(n =>
1390+
new Vote(
1391+
userParty(n).toProtoPrimitive,
1392+
true,
1393+
new Reason("", ""),
1394+
Optional.empty(),
1395+
)
1396+
),
1397+
)
1398+
1399+
for {
1400+
_ <- dummyDomain.create(voteRequestContract1)(store.multiDomainAcsStore)
1401+
result1 = mkVoteRequestResult(
1402+
voteRequestContract1
1403+
)
1404+
_ <- dummyDomain.exercise(
1405+
contract = dsoRules(dsoParty),
1406+
interfaceId = Some(DsoRules.TEMPLATE_ID_WITH_PACKAGE_ID),
1407+
choiceName = DsoRulesCloseVoteRequest.choice.name,
1408+
mkCloseVoteRequest(
1409+
voteRequestContract1.contractId
1410+
),
1411+
result1.toValue,
1412+
)(
1413+
store.multiDomainAcsStore
1414+
)
1415+
voteRequestContract2 = voteRequest(
1416+
requester = userParty(2),
1417+
votes = (1 to 4)
1418+
.map(n =>
1419+
new Vote(
1420+
userParty(n).toProtoPrimitive,
1421+
true,
1422+
new Reason("", ""),
1423+
Optional.empty(),
1424+
)
1425+
),
1426+
)
1427+
_ <- dummyDomain.create(voteRequestContract2)(store.multiDomainAcsStore)
1428+
result2 = mkVoteRequestResult(
1429+
voteRequestContract2,
1430+
effectiveAt = Instant.now().plusSeconds(1).truncatedTo(ChronoUnit.MICROS),
1431+
)
1432+
_ <- dummyDomain.exercise(
1433+
contract = dsoRules(dsoParty),
1434+
interfaceId = Some(DsoRules.TEMPLATE_ID_WITH_PACKAGE_ID),
1435+
choiceName = DsoRulesCloseVoteRequest.choice.name,
1436+
mkCloseVoteRequest(
1437+
voteRequestContract2.contractId
1438+
),
1439+
result2.toValue,
1440+
)(
1441+
store.multiDomainAcsStore
1442+
)
1443+
} yield {
1444+
store
1445+
.listVoteRequestResults(
1446+
Some("AddSv"),
1447+
Some(true),
1448+
None,
1449+
None,
1450+
None,
1451+
PageLimit.tryCreate(1),
1452+
)
1453+
.futureValue
1454+
.toList
1455+
.loneElement shouldBe result2
1456+
store
1457+
.listVoteRequestResults(
1458+
Some("SRARC_AddSv"),
1459+
Some(false),
1460+
None,
1461+
None,
1462+
None,
1463+
PageLimit.tryCreate(1),
1464+
)
1465+
.futureValue
1466+
.toList
1467+
.size shouldBe (0)
1468+
store
1469+
.listVoteRequestResults(
1470+
None,
1471+
None,
1472+
None,
1473+
None,
1474+
None,
1475+
PageLimit.tryCreate(1),
1476+
)
1477+
.futureValue
1478+
.toList
1479+
.size shouldBe (1)
1480+
store
1481+
.listVoteRequestResults(
1482+
None,
1483+
None,
1484+
None,
1485+
Some(Instant.now().truncatedTo(ChronoUnit.MICROS).plusSeconds(3600).toString),
1486+
None,
1487+
PageLimit.tryCreate(1),
1488+
)
1489+
.futureValue
1490+
.toList
1491+
.size shouldBe (0)
1492+
store
1493+
.listVoteRequestResults(
1494+
None,
1495+
None,
1496+
None,
1497+
Some(Instant.now().truncatedTo(ChronoUnit.MICROS).minusSeconds(3600).toString),
1498+
None,
1499+
PageLimit.tryCreate(1),
1500+
)
1501+
.futureValue
1502+
.toList
1503+
.size shouldBe (1)
1504+
}
1505+
}
1506+
15001507
protected def mkStore(
1501-
dsoParty: PartyId = dsoParty
1508+
dsoParty: PartyId = dsoParty,
1509+
acsStoreDescriptorUserVersion: Option[Long] = None,
1510+
txLogStoreDescriptorUserVersion: Option[Long] = None,
1511+
skipIngestAcs: Boolean = false,
15021512
): Future[ScanStore]
15031513

15041514
protected def mkUpdateHistory(
@@ -1923,7 +1933,10 @@ class DbScanStoreTest
19231933
with AcsTables {
19241934

19251935
override protected def mkStore(
1926-
dsoParty: PartyId
1936+
dsoParty: PartyId,
1937+
acsStoreDescriptorUserVersion: Option[Long] = None,
1938+
txLogStoreDescriptorUserVersion: Option[Long] = None,
1939+
skipIngestAcs: Boolean = false,
19271940
): Future[ScanStore] = {
19281941
val packageSignatures =
19291942
ResourceTemplateDecoder.loadPackageSignaturesFromResources(
@@ -1958,12 +1971,17 @@ class DbScanStoreTest
19581971
IngestionConfig(),
19591972
new DbScanStoreMetrics(new NoOpMetricsFactory(), loggerFactory, timeouts),
19601973
initialRound = 0,
1974+
acsStoreDescriptorUserVersion,
1975+
txLogStoreDescriptorUserVersion,
19611976
)(parallelExecutionContext, implicitly, implicitly)
19621977

19631978
for {
19641979
_ <- store.multiDomainAcsStore.testIngestionSink.initialize()
1965-
_ <- store.multiDomainAcsStore.testIngestionSink
1966-
.ingestAcs(nextOffset(), Seq.empty, Seq.empty, Seq.empty)
1980+
_ <-
1981+
if (!skipIngestAcs) {
1982+
store.multiDomainAcsStore.testIngestionSink
1983+
.ingestAcs(nextOffset(), Seq.empty, Seq.empty, Seq.empty)
1984+
} else Future.unit
19671985
_ <- store.domains.ingestionSink.ingestConnectedDomains(
19681986
Map(SynchronizerAlias.tryCreate(domain) -> dummyDomain)
19691987
)
@@ -2069,4 +2087,77 @@ class DbScanStoreTest
20692087
}
20702088
}
20712089
}
2090+
"Changing the acsStoreDescriptorUserVersion" should {
2091+
val alice = userParty(443)
2092+
val aliceValidatorLicense = validatorLicense(
2093+
alice,
2094+
dsoParty,
2095+
Some(new FaucetState(new Round(0), new Round(1000), 0L)),
2096+
)
2097+
2098+
"force re-ingestion of acs" in {
2099+
for {
2100+
// create store, ingest an update with aliceValidatorLicense
2101+
store <- mkStore()
2102+
_ <- dummyDomain.create(aliceValidatorLicense)(store.multiDomainAcsStore)
2103+
result <- store.getValidatorLicenseByValidator(
2104+
Vector(alice)
2105+
)
2106+
// create store again but now with new storeDescriptor userVersion, ingest an update with aliceValidatorLicense again
2107+
storeReingest <- mkStore(dsoParty = dsoParty, acsStoreDescriptorUserVersion = Some(1L))
2108+
// ingestUpdate would fail on the same storeId for aliceValidatorLicense without a new user version.
2109+
_ <- dummyDomain.create(aliceValidatorLicense)(storeReingest.multiDomainAcsStore)
2110+
resultAfter <- storeReingest.getValidatorLicenseByValidator(
2111+
Vector(alice)
2112+
)
2113+
} yield {
2114+
result should contain(aliceValidatorLicense)
2115+
resultAfter should contain(aliceValidatorLicense)
2116+
}
2117+
}
2118+
}
2119+
2120+
"Changing the txLogStoreDescriptorUserVersion" should {
2121+
"force re-ingestion of txLog" in {
2122+
for {
2123+
store <- mkStore()
2124+
_ <- assertListOfAllPastVoteRequestResults(store)
2125+
// create the store with a new txLogStoreDescriptorUserVersion and check that it logs that TxLog backfilling will start restoring previous entries
2126+
storeReingest <- loggerFactory.assertLogsSeq(SuppressionRule.Level(Level.INFO))(
2127+
{
2128+
mkStore(
2129+
dsoParty = dsoParty,
2130+
txLogStoreDescriptorUserVersion = Some(1L),
2131+
// not calling ingestAcs in this test code cause that fails because finishedAcsIngestion completing when it identifies
2132+
// that StoreHasData(acsStoreId, acsOffset) and StoreHasNoData(txLogStoreId)
2133+
skipIngestAcs = true,
2134+
)
2135+
},
2136+
lines => {
2137+
forAll(lines) { line =>
2138+
line.message should include(
2139+
s"has not ingested any data, presumably because it was reset."
2140+
)
2141+
line.message should include(
2142+
"TxLog backfilling will start restoring previous entries."
2143+
)
2144+
}
2145+
},
2146+
)
2147+
} yield {
2148+
// new store should not have txLog entry from previous store
2149+
storeReingest
2150+
.listVoteRequestResults(
2151+
Some("AddSv"),
2152+
Some(true),
2153+
None,
2154+
None,
2155+
None,
2156+
PageLimit.tryCreate(1),
2157+
)
2158+
.futureValue
2159+
.toList should have size 0
2160+
}
2161+
}
2162+
}
20722163
}

0 commit comments

Comments
 (0)