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: 10 additions & 10 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

16 changes: 14 additions & 2 deletions example_with_targets/src/main.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use std::process;

use shopify_function::prelude::*;
use shopify_function::Result;

Expand All @@ -17,11 +19,16 @@ mod schema {

#[shopify_function]
fn target_a(_input: schema::target_a::Input) -> Result<schema::FunctionTargetAResult> {
log!("In target_a");
let var = 42;
log!("With var: {var}");
log!("With var: {}", var);
Ok(schema::FunctionTargetAResult { status: Some(200) })
}

#[shopify_function]
fn target_b(input: schema::target_b::Input) -> Result<schema::FunctionTargetBResult> {
log!("In target_b");
Ok(schema::FunctionTargetBResult {
name: Some(format!("new name: \"{}\"", input.id())),
operations: vec![
Expand All @@ -33,9 +40,14 @@ fn target_b(input: schema::target_b::Input) -> Result<schema::FunctionTargetBRes
})
}

#[shopify_function]
fn target_panic(_input: schema::target_a::Input) -> Result<schema::FunctionTargetAResult> {
panic!("Something went wrong");
}

fn main() {
eprintln!("Invoke a named import");
std::process::exit(1);
log!("Invoke a named export");
process::abort()
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would it be good to keep a log!("Invoke a named export"); here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll add that. Shouldn't really matter too much given it's an example but no harm in having it.

}

#[cfg(test)]
Expand Down
27 changes: 14 additions & 13 deletions integration_tests/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,8 @@ use std::{
sync::LazyLock,
};

const FUNCTION_RUNNER_VERSION: &str = "9.0.0";
const TRAMPOLINE_VERSION: &str = "1.0.0";
const FUNCTION_RUNNER_VERSION: &str = "9.1.0";
const TRAMPOLINE_VERSION: &str = "2.0.0";

fn workspace_root() -> std::path::PathBuf {
let manifest_dir = env!("CARGO_MANIFEST_DIR");
Expand All @@ -21,7 +21,7 @@ fn build_example(name: &str) -> Result<()> {
"build",
"--release",
"--target",
"wasm32-wasip1",
"wasm32-unknown-unknown",
"-p",
name,
])
Expand Down Expand Up @@ -124,10 +124,10 @@ fn download_from_github(
pub fn prepare_example(name: &str) -> Result<PathBuf> {
build_example(name)?;
let wasm_path = workspace_root()
.join("target/wasm32-wasip1/release")
.join("target/wasm32-unknown-unknown/release")
.join(format!("{name}.wasm"));
let trampolined_path = workspace_root()
.join("target/wasm32-wasip1/release")
.join("target/wasm32-unknown-unknown/release")
.join(format!("{name}-trampolined.wasm"));
let trampoline_path = TRAMPOLINE_PATH
.as_ref()
Expand All @@ -152,7 +152,7 @@ pub fn run_example(
path: PathBuf,
export: &str,
input: serde_json::Value,
) -> Result<serde_json::Value> {
) -> Result<(serde_json::Value, String)> {
let function_runner_path = FUNCTION_RUNNER_PATH
.as_ref()
.map_err(|e| anyhow::anyhow!("Failed to download function runner: {}", e))?;
Expand Down Expand Up @@ -191,13 +191,14 @@ pub fn run_example(

let mut output: serde_json::Value = serde_json::from_slice(&output_bytes)?;

if !status.success() {
let logs = output
.get("logs")
.ok_or_else(|| anyhow::anyhow!("No logs"))?
.as_str()
.ok_or_else(|| anyhow::anyhow!("Logs are not a string"))?;
let logs = output
.get("logs")
.ok_or_else(|| anyhow::anyhow!("No logs"))?
.as_str()
.ok_or_else(|| anyhow::anyhow!("Logs are not a string"))?
.to_string();

if !status.success() {
anyhow::bail!(
"Function runner returned non-zero exit code: {}, logs: {}",
status,
Expand All @@ -209,5 +210,5 @@ pub fn run_example(
.get_mut("output")
.ok_or_else(|| anyhow::anyhow!("No output"))?
.take();
Ok(output_json)
Ok((output_json, logs))
}
27 changes: 25 additions & 2 deletions integration_tests/tests/integration_test.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,13 +16,14 @@ fn test_example_with_targets_target_a() -> Result<()> {
"name": "test",
"country": "CA"
});
let output = run_example(path.clone(), "target_a", input)?;
let (output, logs) = run_example(path.clone(), "target_a", input)?;
assert_eq!(
output,
serde_json::json!({
"status": 200
})
);
assert_eq!(logs, "In target_a\nWith var: 42\nWith var: 42\n");
Ok(())
}

Expand All @@ -35,7 +36,7 @@ fn test_example_with_targets_target_b() -> Result<()> {
"id": "gid://shopify/Order/1234567890",
"targetAResult": 200
});
let output = run_example(path.clone(), "target_b", input)?;
let (output, logs) = run_example(path.clone(), "target_b", input)?;
assert_eq!(
output,
serde_json::json!({
Expand All @@ -54,5 +55,27 @@ fn test_example_with_targets_target_b() -> Result<()> {
]
})
);
assert_eq!(logs, "In target_b\n");
Ok(())
}

#[test]
fn test_example_with_panic() -> Result<()> {
let path = EXAMPLE_WITH_TARGETS_RESULT
.as_ref()
.map_err(|e| anyhow::anyhow!("Failed to prepare example: {}", e))?;
let input = serde_json::json!({
"id": "gid://shopify/Order/1234567890",
"targetAResult": "foo"
});
let err = run_example(path.clone(), "target_panic", input)
.unwrap_err()
.to_string();
let expected_err =
"Function runner returned non-zero exit code: exit status: 1, logs: panicked at example_with_targets/src/main.rs:45:5:\nSomething went wrong\nerror while executing at wasm backtrace:";
assert!(
err.contains(expected_err),
"Expected error message to contain:\n`{expected_err}`\nbut was:\n`{err}`"
);
Ok(())
}
2 changes: 1 addition & 1 deletion rust-toolchain.toml
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
[toolchain]
channel = "stable"
components = ["rustfmt", "clippy"]
targets = ["wasm32-wasip1"]
targets = ["wasm32-unknown-unknown"]
2 changes: 1 addition & 1 deletion shopify_function/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ description = "Crate to write Shopify Functions in Rust."
[dependencies]
serde_json = "1.0"
shopify_function_macro = { version = "1.1.1", path = "../shopify_function_macro" }
shopify_function_wasm_api = "0.2.0"
shopify_function_wasm_api = "0.3.0"

# Use the `small` feature of ryu (transitive dependency through serde_json)
# to shave off ~9kb of the Wasm binary size.
Expand Down
16 changes: 16 additions & 0 deletions shopify_function/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,15 @@
//! }
//! ```

#[cfg(all(target_arch = "wasm32", target_os = "wasi", target_env = "p1"))]
compile_error!("Compiling to wasm32-wasip1 is unsupported, change your target to wasm32-unknown-unknown instead");

pub use shopify_function_macro::{shopify_function, typegen, Deserialize};

pub mod scalars;

pub mod prelude {
pub use crate::log;
pub use crate::scalars::*;
pub use shopify_function_macro::{shopify_function, typegen, Deserialize};
}
Expand All @@ -45,6 +49,18 @@ where
f(input)
}

#[macro_export]
macro_rules! log {
($($args:tt)*) => {
{
use std::fmt::Write;
let mut buf = std::string::String::new();
writeln!(&mut buf, $($args)*).unwrap();
$crate::wasm_api::Context.log(&buf);
}
};
}

pub use shopify_function_wasm_api as wasm_api;

#[cfg(test)]
Expand Down
4 changes: 2 additions & 2 deletions shopify_function_macro/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,12 +99,12 @@ pub fn shopify_function(
quote! {
#[export_name = #function_name_string]
pub extern "C" fn #export_function_name() {
shopify_function::wasm_api::init_panic_handler();
let mut context = shopify_function::wasm_api::Context::new();
let root_value = context.input_get().expect("Failed to get input");
let mut input: #input_type = shopify_function::wasm_api::Deserialize::deserialize(&root_value).expect("Failed to deserialize input");
let result = #function_name(input).expect("Failed to call function");
shopify_function::wasm_api::Serialize::serialize(&result, &mut context).expect("Failed to serialize output");
context.finalize_output().expect("Failed to finalize output");
}

#ast
Expand Down Expand Up @@ -350,7 +350,7 @@ impl CodeGenerator for ShopifyFunctionCodeGenerator {
#description
pub fn #field_name_ident(&self) -> #field_type {
static INTERNED_FIELD_NAME: shopify_function::wasm_api::CachedInternedStringId = shopify_function::wasm_api::CachedInternedStringId::new(#field_name_lit_str, );
let interned_string_id = INTERNED_FIELD_NAME.load_from_value(&self.__wasm_value);
let interned_string_id = INTERNED_FIELD_NAME.load();

let value = self.#field_name_ident.get_or_init(|| {
let value = self.__wasm_value.get_interned_obj_prop(interned_string_id);
Expand Down