Skip to content

Commit 48cd583

Browse files
committed
Update GRIB support and improve URI handling in FDB integration tests
1 parent 8b555fa commit 48cd583

File tree

3 files changed

+57
-23
lines changed

3 files changed

+57
-23
lines changed

rust/crates/fdb-sys/Cargo.toml

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,10 @@ vendored = ["eckit-sys/vendored", "metkit-sys/vendored", "eccodes-sys/vendored"]
2121
system = ["eckit-sys/system", "metkit-sys/system", "eccodes-sys/system"]
2222

2323
# Core features (CMake default: ON)
24-
grib = ["eccodes-sys/product-grib"] # GRIB support via eccodes
24+
# GRIB support requires both eccodes-sys/product-grib (the eccodes library
25+
# itself) AND metkit-sys/grib (so metkit's grib message splitter is built and
26+
# its static initializers register with eckit::message::Splitter).
27+
grib = ["eccodes-sys/product-grib", "metkit-sys/grib"]
2528
tocfdb = [] # Filesystem TOC support for FDB
2629
fdb-remote = [] # FDB remote access
2730

rust/crates/fdb-sys/cpp/fdb_bridge.cpp

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,13 @@ ListElementData ListIteratorHandle::next() {
309309
has_current_ = false;
310310

311311
ListElementData data;
312-
data.uri = rust::String(current_.location().uri().asRawString());
312+
// Use `fullUri()` (not `uri()`) so the resulting string encodes the
313+
// entry's offset in the URI fragment and its length in the `length` query
314+
// parameter. This matches what `FieldLocation(const eckit::URI&)` parses
315+
// back, so the URI is round-trippable through `read_uri()` without the
316+
// caller having to seek manually. Same pattern as the upstream
317+
// `fdb-url`/`fdb-hammer` tools.
318+
data.uri = rust::String(current_.location().fullUri().asRawString());
313319
data.offset = current_.location().offset();
314320
data.length = current_.location().length();
315321

rust/crates/fdb/tests/fdb_integration.rs

Lines changed: 46 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1410,30 +1410,55 @@ fn test_fdb_archive_raw() {
14101410

14111411
let fdb = Fdb::from_yaml(&config).expect("failed to create FDB from YAML");
14121412

1413-
// Read GRIB data - the template.grib should have embedded metadata
1414-
let grib_path = fixtures_dir().join("template.grib");
1415-
let grib_data = fs::read(&grib_path).expect("failed to read template.grib");
1416-
1417-
// Archive using archive_raw - key is extracted from GRIB metadata
1418-
let result = fdb.archive_raw(&grib_data);
1419-
println!("archive_raw result: {result:?}");
1413+
// Read GRIB data with embedded MARS metadata. `synth11.grib` carries
1414+
// section-1 headers (class=od, expver=0001, stream=oper, date=20230508,
1415+
// time=1200, type=fc, levtype=sfc, param=151130, step=1) which is what
1416+
// `archive_raw` extracts to build the storage key.
1417+
let grib_path = fixtures_dir().join("synth11.grib");
1418+
let grib_data = fs::read(&grib_path).expect("failed to read synth11.grib");
1419+
1420+
// Archive using archive_raw - key is extracted from GRIB metadata.
1421+
fdb.archive_raw(&grib_data).expect("archive_raw failed");
1422+
fdb.flush().expect("flush failed");
14201423

1421-
// Note: This may fail if the GRIB doesn't have complete metadata for the schema,
1422-
// but the method itself should work. Testing the API works without panicking.
1423-
if result.is_ok() {
1424-
fdb.flush().expect("flush failed");
1424+
// Verify the data actually landed in the database by listing it back
1425+
// with the exact key the GRIB embeds, and check the field-level entry
1426+
// matches.
1427+
let request = Request::new().with("class", "od").with("expver", "0001");
1428+
let items: Vec<_> = fdb
1429+
.list(&request, 3, false)
1430+
.expect("failed to list")
1431+
.collect::<Result<_, _>>()
1432+
.expect("list iterator returned an error");
14251433

1426-
// Try to find the archived data
1427-
// Note: We don't know the exact key, so use a broad request
1428-
let request = Request::new().with("class", "rd");
1429-
let items: Vec<_> = fdb
1430-
.list(&request, 3, false)
1431-
.expect("failed to list")
1432-
.filter_map(std::result::Result::ok)
1433-
.collect();
1434+
assert_eq!(
1435+
items.len(),
1436+
1,
1437+
"expected exactly one entry after archive_raw, got {}: {items:#?}",
1438+
items.len()
1439+
);
14341440

1435-
println!("archive_raw: found {} items after archive", items.len());
1436-
}
1441+
let item = &items[0];
1442+
// Spot-check the key parts from each level — these come from the GRIB
1443+
// section-1 headers, so if any drift the test will catch it loudly.
1444+
let db: std::collections::HashMap<_, _> = item.db_key.iter().cloned().collect();
1445+
assert_eq!(db.get("class").map(String::as_str), Some("od"));
1446+
assert_eq!(db.get("expver").map(String::as_str), Some("0001"));
1447+
assert_eq!(db.get("stream").map(String::as_str), Some("oper"));
1448+
assert_eq!(db.get("date").map(String::as_str), Some("20230508"));
1449+
assert_eq!(db.get("time").map(String::as_str), Some("1200"));
1450+
1451+
let index: std::collections::HashMap<_, _> = item.index_key.iter().cloned().collect();
1452+
assert_eq!(index.get("type").map(String::as_str), Some("fc"));
1453+
assert_eq!(index.get("levtype").map(String::as_str), Some("sfc"));
1454+
1455+
let datum: std::collections::HashMap<_, _> = item.datum_key.iter().cloned().collect();
1456+
assert_eq!(datum.get("param").map(String::as_str), Some("151130"));
1457+
assert_eq!(datum.get("step").map(String::as_str), Some("1"));
1458+
1459+
// The byte length recorded in the listing should match the GRIB message
1460+
// we archived (proves it's not a zero-length sentinel).
1461+
assert_eq!(item.length, grib_data.len() as u64);
14371462
}
14381463

14391464
/// Test `read_uri()` - reads data from a specific URI location.

0 commit comments

Comments
 (0)