Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add first draft of a spin-test SIP #2462

Open
wants to merge 3 commits into
base: main
Choose a base branch
from
Open

Add first draft of a spin-test SIP #2462

wants to merge 3 commits into from

Conversation

rylev
Copy link
Collaborator

@rylev rylev commented Apr 18, 2024

This SIP describes the spin-test tool that allows running unmodified Spin applications in WebAssembly component based testing environment where all potential imports to the Spin app are virtualized and can be configured by the user in a language independent way.

Implementation of this SIP has already begun here.

docs/content/sips/000-spin-test.md Outdated Show resolved Hide resolved

## Open Questions

- Should `spin-test` be a stand alone CLI experience, a plugin for `spin` CLI, or both?
Copy link
Collaborator

Choose a reason for hiding this comment

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

I would say plugin is probably best - at least as a starting point - as it would benefit from the plugin update framework.

Copy link
Member

Choose a reason for hiding this comment

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

+1 on the plugin route for delivering the functionality to users.

## Open Questions

- Should `spin-test` be a stand alone CLI experience, a plugin for `spin` CLI, or both?
- How do we handle Spin applications with more than component?
Copy link
Collaborator

Choose a reason for hiding this comment

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

Ignoring service chaining (?), presumably you could create a test composition per Spin component? That might even be ideal if you could compose multiple components as you wouldn't have to build anything you aren't currently testing.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

But which test composition do we end up actually calling? The spin-test host calls the run function to kick off the test. This run function is exported by the user-written test runner component. This test runner component is ultimately what calls the router (one or more times) as part of the test. If we create N test compositions, N - 1 of those compositions are not meant to receive that request (and calling their run function would just fail). At the core of the issue is that we don't really known which component needs to called before hand - the router is what makes that decision, but the router cannot compose with an arbitrary number of components to route to.

The only way I can see see to work around this are the two proposed solutions: moving routing into the host or synthesizing a router component.

Copy link
Collaborator

@lann lann Apr 19, 2024

Choose a reason for hiding this comment

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

Ohhh I was thinking that the developer would explicitly map tests to components, but you are looking at doing that via regular URL path routing. Yeah I would think in the short term that would require the host to do the routing.

Copy link
Member

Choose a reason for hiding this comment

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

I think this is a scenario that would become (at least for me) much clearer with an example of the (proposed/desired/currently possible/default) developer experience for writing tests. I think there are a few decisions that might impact the decisions here:

  • does each Spin component come with its own sets of tests, or is there a single test "project" for the entire Spin application?
  • depending on ^^, there could be a scenario where the test is linked to a single component, which means the question is no longer difficult to answer.

- Should `spin-test` be a stand alone CLI experience, a plugin for `spin` CLI, or both?
- How do we handle Spin applications with more than component?
- There’s no way to compose a statically defined component with N number of components. This means the router component must know how many components it will be composed with ahead of time, and so the reasonable number of 1 is picked.
- We could work around this by moving the router out of a component and into the host, but this makes the host smarter which would like to avoid. We could also potentially synthesize a router component based on the `spin.toml` manifest instead of relying on a statically defined one, but this is certainly not trivial.
Copy link
Collaborator

Choose a reason for hiding this comment

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

You could also (statically/macro-ly) generate a family of routers (router1, router2, ...). Annoying, but probably fine as a medium-term hack.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

This wouldn't work either (without changing the host to be smarter) as something needs to split one request into a call to one of N possible components. Composing N components with 1 component (where N is not known ahead of time) is not possible.

Copy link
Collaborator

Choose a reason for hiding this comment

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

What about 1 router with many identical component instance imports? It would be a little fiddly but you should be able to derive one consistent ordering of spin components from a manifest which would let the composition step fill the imports in the same order that the router then expects them. You would also need some way to fill all the unused import slots, either a static dummy component that always traps or some Linker jiggery-pokery.

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

So you're suggesting a single router component with some arbitrary amount of imports that components can plug into and we either plug those with actual Spin app components or with a dummy trapping component once we run out of Spin app components?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yep

docs/content/sips/000-spin-test.md Show resolved Hide resolved
- How exactly should the various worlds look like?
- The proposal above is enough to get things working, but there is plenty of room for bike-shedding the exact shape of the worlds.
- Which triggers should we support?
- Can we support an arbitrary number of triggers through some sort of plugin system? How would that work?
Copy link
Collaborator

Choose a reason for hiding this comment

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

This feels like something that may become dramatically easier with CM async (to the extent that magically fixes all our nested composition woes).

Copy link
Collaborator Author

Choose a reason for hiding this comment

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

Hmm... I'm not sure I follow - none of the triggers (with the exception of wasi:http/incoming-handler which we already support) are necessarily built to try to accommodate async. I don't see how CM async improves the situation here. Could you explain more about what you mean?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Ah yeah sorry the train of consciousness left the station early there...

I think each trigger type could have a test driver adapter to wrap the component-under-test and test driver to implement the runner world; this is impossible today because the host has to provide resource factories to glue everything together.

- How should test discovery work?
- The most straightforward way would be for `spin-test` to require the user to specify the path to a `spin-test` compliant test component binary.
- Another way would be for there to be a convention around a `tests` directory. This `tests` directory could include both built `spin-test` compliant test component binaries as well as directories with source code and a `spin-test.toml` configuration file that specifies how the source code is built into a `spin-test` compliant test component binary. `spin-test` would then build all the tests that need to be built and run each test binary.
- We could also carve away space in the `spin.toml` manifest (e.g., by using the `[component.<id>.tool]` section). Such a solution might be more appropriate if we determine that users will normally want very few test component binaries. If, however, it proves to be useful to potentially have many test binaries, splitting the configuration out to each test binary in the form of a bespoke `spin-test.toml` per test binary might be the better solution.
Copy link
Collaborator

@lann lann Apr 19, 2024

Choose a reason for hiding this comment

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

I suppose we could also do both (eventually), with a compatible schema reused between spin.toml [component.<id>.tool] for one-test-per-component and tests/spin-test.toml for more complex scenarios.

Copy link
Collaborator

@lann lann Apr 19, 2024

Choose a reason for hiding this comment

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

Another option to consider might be the application.tool section in spin.toml, e.g. [application.tool.spin-test.test-a]. I'm not sure I would actually like that but it would avoid having another config file.

Copy link
Member

@radu-matei radu-matei left a comment

Choose a reason for hiding this comment

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

I'm really excited to see this into a tool developers can use test applications!

Left a couple of comments on the doc, but generally this is great!

Thank you!


At the core of `spin-test` is component composition. The user’s Spin app is composed together with other components to ultimately produce a component (referred to as “the composition” below) that has none of the original Spin or WASI imports. The composition has the following components internal to it:

- A single component from the Spin app (see the *Open Questions* section for why only one component from a Spin app can be supported)
Copy link
Member

Choose a reason for hiding this comment

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

This refers to "a single component" from the perspective of the Spin application manifest I assume — if my Spin component build process generates a statically linked component, I would expect testing to continue to work as expected.

Is that accurate?


- A single component from the Spin app (see the *Open Questions* section for why only one component from a Spin app can be supported)
- A Spin virtualization component that virtualizes all `fermyon:spin/platform` interfaces.
- A WASI virtualization component that virtualizes all the `wasi:cli/imports` interfaces.
Copy link
Member

Choose a reason for hiding this comment

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

As I was going through the test examples from the implementation repository, I was thinking about the wasi:cli/imports imports — will this contain a programmatic API to set the behavior of all WASI functionality?
Will there be a subset available to begin with?

I'm curious what the API through which we expose that to users in tests will look like.

*Note*:

> **A few notes:**
* We may still wish to have the composition import `wasi:cli/stdout` and `wasi:cli/stderr` so that it can easily log things.
Copy link
Member

Choose a reason for hiding this comment

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

The example test I ran from the implementation repo did log to stdout -- is this already supported?

* It might be possible to statically configure the virtualized Spin runtime component given a manifest file by synthesizing the component on the file (in much the way that WASI-virt works). This would make it possible to no longer require that the manifest is passed to the composition component at runtime since it has already been statically configured to run correctly with that Spin manifest. This has its downsides though as composition components for the same app but different manifests cannot be shared between tests.
* The `wasi:http` work around imports may hopefully eventually overcome with changes to the `wasi:http` package.
* If this and the manifest import are eliminated, tests could potentially be run by an component runtime with no imports whatsoever.
>
Copy link
Member

Choose a reason for hiding this comment

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

nit: leftover >

/// The ability to call the Spin app
import wasi:http/[email protected];

/// Actually call the test
Copy link
Member

Choose a reason for hiding this comment

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

nit: formatting for WIT source and comments seems off in parts of this file.


## Open Questions

- Should `spin-test` be a stand alone CLI experience, a plugin for `spin` CLI, or both?
Copy link
Member

Choose a reason for hiding this comment

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

+1 on the plugin route for delivering the functionality to users.

## Open Questions

- Should `spin-test` be a stand alone CLI experience, a plugin for `spin` CLI, or both?
- How do we handle Spin applications with more than component?
Copy link
Member

Choose a reason for hiding this comment

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

I think this is a scenario that would become (at least for me) much clearer with an example of the (proposed/desired/currently possible/default) developer experience for writing tests. I think there are a few decisions that might impact the decisions here:

  • does each Spin component come with its own sets of tests, or is there a single test "project" for the entire Spin application?
  • depending on ^^, there could be a scenario where the test is linked to a single component, which means the question is no longer difficult to answer.

@radu-matei
Copy link
Member

What is the status of the SIP wrt the actual implementation from https://github.com/fermyon/spin-test?

@rylev
Copy link
Collaborator Author

rylev commented Aug 21, 2024

@radu-matei There haven't been any fundamental objections to the approach and we're far enough along in the implementation that I think this could be merged. I would just need to update the document to reflect the true state of the proposal.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants