Skip to content

Commit 95dd175

Browse files
committed
Smoke test for blobstore API
Signed-off-by: itowlson <[email protected]>
1 parent e4bfdde commit 95dd175

File tree

8 files changed

+127
-8
lines changed

8 files changed

+127
-8
lines changed

crates/blobstore-fs/src/lib.rs

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,17 @@ struct BlobContent {
228228
end: u64,
229229
}
230230

231+
impl BlobContent {
232+
fn len(&self) -> u64 {
233+
let excl_end = if self.end == u64::MAX {
234+
self.end
235+
} else {
236+
self.end + 1
237+
};
238+
excl_end - self.start
239+
}
240+
}
241+
231242
#[async_trait]
232243
impl spin_factor_blobstore::IncomingData for BlobContent {
233244
async fn consume_sync(&mut self) -> anyhow::Result<Vec<u8>> {
@@ -238,9 +249,7 @@ impl spin_factor_blobstore::IncomingData for BlobContent {
238249
let mut buf = Vec::with_capacity(1000);
239250

240251
file.seek(std::io::SeekFrom::Start(self.start)).await?;
241-
file.take(self.end - self.start)
242-
.read_to_end(&mut buf)
243-
.await?;
252+
file.take(self.len()).read_to_end(&mut buf).await?;
244253

245254
Ok(buf)
246255
}
@@ -253,7 +262,7 @@ impl spin_factor_blobstore::IncomingData for BlobContent {
253262
let file = self.file.take().unwrap();
254263
let stm = tokio_util::io::ReaderStream::new(file)
255264
.skip(self.start.try_into().unwrap())
256-
.take((self.end - self.start).try_into().unwrap());
265+
.take(self.len().try_into().unwrap());
257266

258267
let ar = stm.into_async_read().compat();
259268
wasmtime_wasi::p2::pipe::AsyncReadStream::new(ar)

crates/factor-blobstore/src/runtime_config/spin.rs

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -64,10 +64,7 @@ impl RuntimeConfigResolver {
6464
.insert(T::RUNTIME_CONFIG_TYPE, store_from_toml_fn(store_type))
6565
.is_some()
6666
{
67-
anyhow::bail!(
68-
"duplicate key value store type {:?}",
69-
T::RUNTIME_CONFIG_TYPE
70-
);
67+
anyhow::bail!("duplicate blob store type {:?}", T::RUNTIME_CONFIG_TYPE);
7168
}
7269
Ok(())
7370
}

tests/integration.rs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,38 @@ mod integration_tests {
9696
Ok(())
9797
}
9898

99+
#[test]
100+
fn blobstore_smoke_test() -> anyhow::Result<()> {
101+
let temp_dir = tempfile::tempdir()?;
102+
103+
let rt_file = temp_dir.path().join("rt.toml");
104+
std::fs::write(
105+
&rt_file,
106+
format!(
107+
"[blob_store.default]\ntype = \"file_system\"\npath = \"{}\"",
108+
temp_dir.path().display()
109+
),
110+
)?;
111+
112+
run_test(
113+
"blobstore",
114+
SpinConfig {
115+
binary_path: spin_binary(),
116+
spin_up_args: vec![
117+
"--runtime-config-file".into(),
118+
rt_file.display().to_string(),
119+
],
120+
app_type: SpinAppType::Http,
121+
},
122+
ServicesConfig::none(),
123+
move |env| {
124+
let spin = env.runtime_mut();
125+
assert_spin_request(spin, Request::new(Method::Get, "/"), Response::new(200))
126+
},
127+
)?;
128+
Ok(())
129+
}
130+
99131
#[test]
100132
#[cfg(feature = "extern-dependencies-tests")]
101133
#[allow(dependency_on_unit_never_type_fallback)]

tests/test-components/components/Cargo.lock

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "blobstore"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
[lib]
7+
crate-type = ["cdylib"]
8+
9+
[dependencies]
10+
helper = { path = "../../helper" }
11+
wit-bindgen = { workspace = true }
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
# Key Value
2+
3+
Tests the blobstore interface.
4+
5+
## Expectations
6+
7+
This test component expects the following to be true:
8+
* It is given permission to open a connection to the "default" store.
9+
* It does not have permission to access a store named "forbidden".
10+
* It is empty
Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,37 @@
1+
use helper::{ensure_eq, ensure_ok};
2+
3+
use helper::http_trigger_bindings::wasi::blobstore::blobstore::get_container;
4+
use helper::http_trigger_bindings::wasi::blobstore::types::{IncomingValue, OutgoingValue};
5+
6+
helper::define_component!(Component);
7+
8+
impl Component {
9+
fn main() -> Result<(), String> {
10+
let container = ensure_ok!(get_container(&"default".into()));
11+
12+
let blob_name = "my-blob".to_string();
13+
14+
let outgoing = OutgoingValue::new_outgoing_value();
15+
ensure_ok!(container.write_data(&blob_name, &outgoing));
16+
17+
let stm = ensure_ok!(outgoing.outgoing_value_write_body().map_err(|_| "failed to write outgoing body"));
18+
19+
ensure_ok!(stm.blocking_write_and_flush(b"Hello world"));
20+
21+
ensure_ok!(OutgoingValue::finish(outgoing));
22+
23+
let incoming = ensure_ok!(container.get_data(&blob_name, 0, u64::MAX));
24+
let content = ensure_ok!(IncomingValue::incoming_value_consume_sync(incoming));
25+
ensure_eq!(content, b"Hello world");
26+
27+
let incoming = ensure_ok!(container.get_data(&blob_name, 0, 4));
28+
let content = ensure_ok!(IncomingValue::incoming_value_consume_sync(incoming));
29+
ensure_eq!(content, b"Hello");
30+
31+
let incoming = ensure_ok!(container.get_data(&blob_name, 2, 4));
32+
let content = ensure_ok!(IncomingValue::incoming_value_consume_sync(incoming));
33+
ensure_eq!(content, b"llo");
34+
35+
Ok(())
36+
}
37+
}
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
spin_manifest_version = 2
2+
3+
[application]
4+
authors = ["Fermyon Engineering <[email protected]>"]
5+
description = "A simple application that exercises blob storage."
6+
name = "blobstore"
7+
version = "1.0.0"
8+
9+
[[trigger.http]]
10+
route = "/..."
11+
component = "hello"
12+
13+
[component.hello]
14+
source = "%{source=blobstore}"
15+
blob_containers = ["default"]

0 commit comments

Comments
 (0)