feat: add host particle field submission contract
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
Some checks failed
validate-scripts / validate-scripts (push) Has been cancelled
This commit is contained in:
@@ -346,6 +346,160 @@ TEST(Source, LocalProductionFeedRejectsMissingGeneration) {
|
||||
EXPECT_EQ(result.error, particle::ParticleFieldAdapterError::InvalidTimestampOrIdentity);
|
||||
}
|
||||
|
||||
TEST(Source, CanonicalFieldUsesEastwardUAndNorthwardV) {
|
||||
const auto east = fixtureBytes("uniform-east", "field.f32");
|
||||
const auto north = fixtureBytes("uniform-north", "field.f32");
|
||||
const auto vortex = fixtureBytes("vortex", "field.f32");
|
||||
const auto eastResult = particle::LocalParticleFieldFeed::load(localMetadata(0),
|
||||
std::vector<char>(east.begin(), east.end()));
|
||||
const auto northResult = particle::LocalParticleFieldFeed::load(localMetadata(1),
|
||||
std::vector<char>(north.begin(), north.end()));
|
||||
const auto vortexResult = particle::LocalParticleFieldFeed::load(localMetadata(2),
|
||||
std::vector<char>(vortex.begin(), vortex.end()));
|
||||
ASSERT_TRUE(eastResult);
|
||||
ASSERT_TRUE(northResult);
|
||||
ASSERT_TRUE(vortexResult);
|
||||
ASSERT_TRUE(eastResult.snapshot);
|
||||
ASSERT_TRUE(northResult.snapshot);
|
||||
ASSERT_GE(eastResult.snapshot->velocity.size(), 2u);
|
||||
ASSERT_GE(northResult.snapshot->velocity.size(), 2u);
|
||||
EXPECT_FLOAT_EQ(eastResult.snapshot->velocity[0], 1.0f);
|
||||
EXPECT_FLOAT_EQ(eastResult.snapshot->velocity[1], 0.0f);
|
||||
EXPECT_FLOAT_EQ(northResult.snapshot->velocity[0], 0.0f);
|
||||
EXPECT_FLOAT_EQ(northResult.snapshot->velocity[1], 1.0f);
|
||||
ASSERT_TRUE(vortexResult.snapshot);
|
||||
EXPECT_FLOAT_EQ(vortexResult.snapshot->velocity[0], 0.9375f);
|
||||
EXPECT_FLOAT_EQ(vortexResult.snapshot->velocity[1], -0.9375f);
|
||||
EXPECT_FLOAT_EQ(vortexResult.snapshot->velocity[vortexResult.snapshot->velocity.size() - 2], -0.9375f);
|
||||
EXPECT_FLOAT_EQ(vortexResult.snapshot->velocity.back(), 0.9375f);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldSubmissionBuildsOneCoreOwnedTimeline) {
|
||||
SourceTest test;
|
||||
style::RasterArraySource source{"host-submission"};
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
EXPECT_TRUE(source.loaded);
|
||||
EXPECT_TRUE(source.impl().hostFieldSubmission);
|
||||
EXPECT_FALSE(source.impl().field);
|
||||
|
||||
const auto east = fixtureBytes("uniform-east", "field.f32");
|
||||
const auto north = fixtureBytes("uniform-north", "field.f32");
|
||||
const auto vortex = fixtureBytes("vortex", "field.f32");
|
||||
const std::vector<char> eastPayload(east.begin(), east.end());
|
||||
const std::vector<char> northPayload(north.begin(), north.end());
|
||||
const std::vector<char> vortexPayload(vortex.begin(), vortex.end());
|
||||
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(0), eastPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_FALSE(source.impl().field);
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(1), northPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
ASSERT_TRUE(source.impl().field);
|
||||
ASSERT_TRUE(source.impl().nextField);
|
||||
ASSERT_TRUE(source.impl().timeline);
|
||||
EXPECT_EQ(source.impl().field->fieldID, "production-t0");
|
||||
EXPECT_EQ(source.impl().nextField->fieldID, "production-t1");
|
||||
EXPECT_EQ(source.impl().timeline->frame().state, style::RasterArrayPlaybackState::Ready);
|
||||
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(2), vortexPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedNextSnapshot);
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(3), eastPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedNextSnapshot);
|
||||
EXPECT_EQ(source.impl().timeline->size(), 4u);
|
||||
EXPECT_EQ(source.impl().timeline->lastEntry().field->fieldID, "production-t3");
|
||||
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(3), eastPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::Duplicate);
|
||||
EXPECT_EQ(source.impl().timeline->size(), 4u);
|
||||
EXPECT_TRUE(source.controlRuntimeTimeline(4));
|
||||
EXPECT_EQ(source.impl().timeline->frame().t0Index, 1u);
|
||||
EXPECT_TRUE(source.controlRuntimeTimeline(4));
|
||||
EXPECT_EQ(source.impl().timeline->frame().t0Index, 2u);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldSubmissionStyleContractCreatesEmptyIngress) {
|
||||
SourceTest test;
|
||||
test.style.loadJSON(R"STYLE({
|
||||
"version": 8,
|
||||
"sources": {
|
||||
"host-submission": {"type": "raster-array", "host-field-submission": true}
|
||||
},
|
||||
"layers": []
|
||||
})STYLE");
|
||||
auto* baseSource = test.style.getSource("host-submission");
|
||||
ASSERT_NE(baseSource, nullptr);
|
||||
auto* source = baseSource->as<style::RasterArraySource>();
|
||||
ASSERT_NE(source, nullptr);
|
||||
EXPECT_TRUE(source->impl().hostFieldSubmission);
|
||||
EXPECT_FALSE(source->impl().field);
|
||||
EXPECT_FALSE(source->impl().timeline);
|
||||
}
|
||||
|
||||
TEST(Source, HostFieldSubmissionRejectsInvalidWithoutChangingLastValidField) {
|
||||
SourceTest test;
|
||||
style::RasterArraySource source{"host-submission"};
|
||||
source.setObserver(&test.styleObserver);
|
||||
source.loadDescription(*test.fileSource);
|
||||
const auto field = fixtureBytes("uniform-east", "field.f32");
|
||||
const std::vector<char> payload(field.begin(), field.end());
|
||||
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(0), payload),
|
||||
style::RasterArrayHostFieldSubmitResult::AcceptedPendingInitialWindow);
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(1), payload),
|
||||
style::RasterArrayHostFieldSubmitResult::InitialWindowReady);
|
||||
ASSERT_TRUE(source.impl().timeline);
|
||||
const auto lastValid = source.impl().timeline->lastEntry().field;
|
||||
|
||||
auto invalidIdentity = localMetadata(2);
|
||||
const auto fieldID = invalidIdentity.find("production-t2");
|
||||
ASSERT_NE(fieldID, std::string::npos);
|
||||
invalidIdentity.replace(fieldID, std::string("production-t2").size(), "");
|
||||
EXPECT_EQ(source.submitHostField(invalidIdentity, payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
|
||||
auto unsupportedLayout = localMetadata(2);
|
||||
const auto layout = unsupportedLayout.find("interleaved-uv");
|
||||
ASSERT_NE(layout, std::string::npos);
|
||||
unsupportedLayout.replace(layout, std::string("interleaved-uv").size(), "planar-uv");
|
||||
EXPECT_EQ(source.submitHostField(unsupportedLayout, payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
|
||||
auto unsupportedEncoding = localMetadata(2);
|
||||
const auto encoding = unsupportedEncoding.find("float32-le");
|
||||
ASSERT_NE(encoding, std::string::npos);
|
||||
unsupportedEncoding.replace(encoding, std::string("float32-le").size(), "float64-le");
|
||||
EXPECT_EQ(source.submitHostField(unsupportedEncoding, payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
|
||||
auto invalidDimensions = localMetadata(2);
|
||||
const auto width = invalidDimensions.find("\"width\":16");
|
||||
ASSERT_NE(width, std::string::npos);
|
||||
invalidDimensions.replace(width, std::string("\"width\":16").size(), "\"width\":0");
|
||||
EXPECT_EQ(source.submitHostField(invalidDimensions, payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
|
||||
auto shortPayload = payload;
|
||||
shortPayload.pop_back();
|
||||
EXPECT_EQ(source.submitHostField(localMetadata(2), shortPayload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedAdapter);
|
||||
|
||||
auto nonMonotonic = localMetadata(2);
|
||||
const auto validTime = nonMonotonic.find("202609040200");
|
||||
ASSERT_NE(validTime, std::string::npos);
|
||||
nonMonotonic.replace(validTime, std::string("202609040200").size(), "202609040050");
|
||||
EXPECT_EQ(source.submitHostField(nonMonotonic, payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedNonMonotonicSnapshot);
|
||||
|
||||
EXPECT_EQ(source.impl().timeline->size(), 2u);
|
||||
EXPECT_EQ(source.impl().timeline->lastEntry().field, lastValid);
|
||||
EXPECT_EQ(source.impl().timeline->frame().state, style::RasterArrayPlaybackState::Ready);
|
||||
|
||||
style::RasterArraySource fixtureSource{"fixture", "uniform-east", "metadata", "field"};
|
||||
EXPECT_EQ(fixtureSource.submitHostField(localMetadata(2), payload),
|
||||
style::RasterArrayHostFieldSubmitResult::RejectedSourceMode);
|
||||
}
|
||||
|
||||
TEST(Source, RasterArrayTimelineCandidatesReachReadyThroughFieldAdapter) {
|
||||
SourceTest test;
|
||||
const auto eastMetadata = fixtureBytes("uniform-east", "metadata.json");
|
||||
|
||||
Reference in New Issue
Block a user