Skip to content

Commit

Permalink
Merge pull request #51 from golemcloud/test-instructions
Browse files Browse the repository at this point in the history
Test instructions
  • Loading branch information
vigoo authored Aug 17, 2024
2 parents 69f0e55 + d7b2d70 commit b5ddefa
Show file tree
Hide file tree
Showing 10 changed files with 114 additions and 83 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,15 +48,15 @@ The following occurrences get replaced to the provided component name, applying
- `PackName`

### Testing the examples
The example generation and building can be tested with a test [cli app](/src/test/main.rs).
The example generation and instructions can be tested with a test [cli app](/src/test/main.rs).
The app also accepts a filter argument, which matches for the example name, eg. to test the go examples use:

```shell
cargo run --bin golem-examples-test-cli test-examples -f go
cargo run --bin golem-examples-test-cli -- -f go
```

The necessary tooling for the specific language is expected to be available.

Currently building is implemented only for the TypeScript, Rust and Go examples, the others will be generated, but building will fail.
The test app will instantiate examples and then execute the instructions (all lines starting with ` `).

The examples are generated in the `/examples-test` directory.
2 changes: 1 addition & 1 deletion examples/c/INSTRUCTIONS
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ See the documentation about installing tooling: https://learn.golem.cloud/docs/c
Generate bindings from WIT:
wit-bindgen c --autodrop-borrows yes --out-dir component_name ./wit
Compile the C code with WASI SDK:
~/wasi-sdk-23.0/bin/clang --sysroot ~/wasi-sdk-23.0/share/wasi-sysroot main.c component_name.c component_name_component_type.o -o component_name.module.wasm
~/wasi-sdk-23.0/bin/clang --sysroot ~/wasi-sdk-23.0/share/wasi-sysroot main.c component_name/component_name.c component_name/component_name_component_type.o -o component_name.module.wasm
Convert the result into a Component:
wasm-tools component new component_name.module.wasm -o component_name.wasm --adapt adapters/tier1/wasi_snapshot_preview1.wasm

Expand Down
2 changes: 2 additions & 0 deletions examples/c/c-default-minimal/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.PHONY: build bindings compile clean

build: compile
wasm-tools component new component_name.module.wasm -o component_name.wasm --adapt adapters/tier1/wasi_snapshot_preview1.wasm

Expand Down
2 changes: 2 additions & 0 deletions examples/c/c-default/Makefile
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
.PHONY: build bindings compile clean

build: compile
wasm-tools component new component_name.module.wasm -o component_name.wasm --adapt adapters/tier1/wasi_snapshot_preview1.wasm

Expand Down
2 changes: 1 addition & 1 deletion examples/js/INSTRUCTIONS
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/experimental-languages/js-ts/setup
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/js-language-guide/setup

Compile the JavaScript project with npm:
npm install
Expand Down
20 changes: 14 additions & 6 deletions examples/ts/INSTRUCTIONS
Original file line number Diff line number Diff line change
@@ -1,13 +1,21 @@
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/js-ts/setup
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/ts-language-guide/setup

Compile the TypeScript project with npm:
npm install
npm run componentize

The `out/component_name.wasm` file is ready to be uploaded to Golem Cloud!

All npm run commands:
- stub: generates TypeScript mappings from the wit files
- build: compiles and bundles the TypeScript sources
- componentize: runs stub and build, then creates the wasm file for the component
- clean: "rm -rf out src/interfaces src/main.d.ts"
Other available npm scripts:

- Generating TypeScript mappings from the wit files:
npm run stub

- Compile and bundle the TypeScript sources:
npm run build

- Clean the project:
npm run clean

- Componentizing (includes stub and build steps too):
npm run componentize
2 changes: 1 addition & 1 deletion examples/zig/INSTRUCTIONS
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/zig/setup
See the documentation about installing tooling: https://learn.golem.cloud/docs/experimental-languages/zig-langauge-guide/setup

Compile the Zig code:
zig build
13 changes: 9 additions & 4 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,8 @@ pub mod model;

pub trait Examples {
fn list_all_examples() -> Vec<Example>;
fn instantiate(example: &Example, parameters: ExampleParameters) -> io::Result<String>;
fn instantiate(example: &Example, parameters: &ExampleParameters) -> io::Result<String>;
fn instructions(example: &Example, parameters: &ExampleParameters) -> String;
}

pub struct GolemExamples {}
Expand Down Expand Up @@ -57,14 +58,14 @@ impl Examples for GolemExamples {
result
}

fn instantiate(example: &Example, parameters: ExampleParameters) -> io::Result<String> {
fn instantiate(example: &Example, parameters: &ExampleParameters) -> io::Result<String> {
instantiate_directory(
&EXAMPLES,
&example.example_path,
&parameters
.target_path
.join(parameters.component_name.as_string()),
&parameters,
parameters,
&example.exclude,
true,
)?;
Expand Down Expand Up @@ -92,7 +93,11 @@ impl Examples for GolemExamples {
.join(wit_dep.file_name().unwrap().to_str().unwrap()),
)?;
}
Ok(transform(&example.instructions, &parameters))
Ok(Self::instructions(example, parameters))
}

fn instructions(example: &Example, parameters: &ExampleParameters) -> String {
transform(&example.instructions, parameters)
}
}

Expand Down
2 changes: 1 addition & 1 deletion src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,7 +22,7 @@ pub fn main() {
let cwd = env::current_dir().expect("Failed to get current working directory");
match GolemExamples::instantiate(
example,
ExampleParameters {
&ExampleParameters {
component_name: component_name.clone(),
package_name: package_name
.clone()
Expand Down
146 changes: 80 additions & 66 deletions src/test/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,64 +4,62 @@ use std::process::exit;
use clap::Parser;
use colored::{ColoredString, Colorize};

use golem_examples::model::{
ComponentName, Example, ExampleParameters, GuestLanguage, PackageName,
};
use golem_examples::model::{ComponentName, Example, ExampleParameters, PackageName};
use golem_examples::{Examples, GolemExamples};

#[derive(Parser, Debug)]
#[command()]
pub enum Command {
// Generates and builds the examples components
#[command()]
TestExamples {
// Filter examples by name, checks if the example name contains the filter string
#[arg(short, long)]
filter: Option<String>,
},
pub struct Command {
// Filter examples by name, checks if the example name contains the filter string
#[arg(short, long)]
filter: Option<String>,

// Skip running instructions
#[arg(long)]
skip_instructions: bool,

// Skip instantiating projects
#[arg(long)]
skip_instantiate: bool,
}

pub fn main() {
let command = Command::parse();
match &command {
Command::TestExamples { filter } => {
let results: Vec<(Example, Result<(), String>)> = GolemExamples::list_all_examples()
.iter()
.filter(|example| match filter {
Some(filter) => example.name.as_string().contains(filter),
None => true,
})
.map(|example| {
let result = test_example(example);
if let Err(err) = &result {
println!("{}", err.bright_red())
}
(example.clone(), result)
})
.collect();

println!();
for result in &results {
println!(
"{}: {}",
result.0.name.to_string().bold(),
match &result.1 {
Ok(_) => "OK".bright_green(),
Err(err) =>
ColoredString::from(format!("{}\n{}", "Failed".bright_red(), err.red())),
}
)
let results: Vec<(Example, Result<(), String>)> = GolemExamples::list_all_examples()
.iter()
.filter(|example| match &command.filter {
Some(filter) => example.name.as_string().contains(filter),
None => true,
})
.map(|example| {
let result = test_example(&command, example);
if let Err(err) = &result {
println!("{}", err.bright_red())
}
println!();
(example.clone(), result)
})
.collect();

if results.iter().any(|r| r.1.is_err()) {
exit(1)
println!();
for result in &results {
println!(
"{}: {}",
result.0.name.to_string().bold(),
match &result.1 {
Ok(_) => "OK".bright_green(),
Err(err) =>
ColoredString::from(format!("{}\n{}", "Failed".bright_red(), err.red())),
}
}
)
}
println!();

if results.iter().any(|r| r.1.is_err()) {
exit(1)
}
}

fn test_example(example: &Example) -> Result<(), String> {
fn test_example(command: &Command, example: &Example) -> Result<(), String> {
println!();
println!(
"{} {}",
Expand All @@ -83,6 +81,12 @@ fn test_example(example: &Example) -> Result<(), String> {
component_path.display().to_string().blue()
);

let example_parameters = ExampleParameters {
component_name,
package_name,
target_path,
};

let run = |command: &str, args: Vec<&str>| -> Result<(), String> {
let command_formatted = format!("{} {}", command, args.join(" "));
let run_failed = |e| format!("{} failed: {}", command_formatted, e);
Expand All @@ -105,30 +109,40 @@ fn test_example(example: &Example) -> Result<(), String> {
}
};

if component_path.exists() {
println!("Deleting {}", component_path.display().to_string().blue());
std::fs::remove_dir_all(&component_path)
.map_err(|e| format!("remove dir all failed: {}", e))?;
if command.skip_instantiate {
println!("Skipping instantiate")
} else {
println!("Instantiating");

if component_path.exists() {
println!("Deleting {}", component_path.display().to_string().blue());
std::fs::remove_dir_all(&component_path)
.map_err(|e| format!("remove dir all failed: {}", e))?;
}

let _ = GolemExamples::instantiate(example, &example_parameters)
.map_err(|e| format!("instantiate failed: {}", e))?;

println!("Successfully instantiated the example");
}

println!("Instantiating");
let _ = GolemExamples::instantiate(
example,
ExampleParameters {
component_name,
package_name,
target_path,
},
)
.map_err(|e| format!("instantiate failed: {}", e))?;

match &example.language {
GuestLanguage::Rust => run("cargo", vec!["component", "build", "--release"]),
GuestLanguage::Go => run("make", vec!["build"]),
GuestLanguage::TypeScript => {
run("npm", vec!["install"])?;
run("npm", vec!["run", "componentize"])
if command.skip_instructions {
println!("Skipping instructions\n");
} else {
println!("Executing instructions\n");
let instructions = GolemExamples::instructions(example, &example_parameters);
for line in instructions.lines() {
if line.starts_with(" ") {
match run("bash", vec!["-c", line]) {
Ok(_) => {}
Err(err) => return Err(err.to_string()),
}
} else {
println!("> {}", line.magenta())
}
}
other => Err(format!("build not implemented for {}", other.name())),
println!("Successfully executed instructions\n");
}

Ok(())
}

0 comments on commit b5ddefa

Please sign in to comment.