pulumi/sdk/python/lib/test/langhost
Fraser Waters 6e986f90af
Pass root and main info to language host methods (#14654)
<!--- 
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->

# Description

<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->

This is two changes rolled together in a way.

Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.

Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3;     // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.

`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).

These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).

The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).

## Checklist

- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
  - [ ] I have formatted my code using `gofumpt`

<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!--- 
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
..
aliases [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
asset [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
chained_failure [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
component_dependencies [sdk/python] Adds a default exception when dependency cycles are created (#14597) 2023-11-21 16:26:02 +00:00
component_provider_resolution [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
component_resource_list_of_providers [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
component_resource_single_provider [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
config [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
delete_before_replace [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
empty Pass root and main info to language host methods (#14654) 2023-12-10 17:30:51 +00:00
first_class_provider [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
first_class_provider_invoke [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
first_class_provider_unknown [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
future_failure [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
future_input [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
ignore_changes [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
inherit_defaults [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
inheritance_translation [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
inheritance_types [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
input_type_mismatch [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
input_values_for_outputs [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
invalid_property_dependency [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
invoke [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
invoke_empty_return [sdk/python] Fix error on empty invoke returns (#14470) 2023-11-01 17:47:23 +00:00
invoke_future Fix a reentrancy issue in _sync_await. (#3056) 2019-08-08 19:51:11 -07:00
invoke_types [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
large_resource [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
marshal_failure [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
one_complex_resource [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
one_resource [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
output_all [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
output_nested [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
output_property_dependencies [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
outputs_future Make `pulumi.runtime.invoke` synchronous. (#3019) 2019-08-02 14:19:56 -07:00
preview [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
property_dependencies [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
property_renaming [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
protect [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
read [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
remote_component_dependencies [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
remote_component_providers [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
replace_on_changes [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
resource_op_bad_inputs Add the ability to verify an expected log message was written 2023-07-17 13:18:57 +01:00
resource_op_fail [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
resource_thens [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
runtime_settings Add getOrganization to nodejs and python (#10504) 2022-08-31 10:33:29 +01:00
source_position [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
stack_output fix(sdk/python): Allow for duplicate output values in python programs 2022-12-07 11:59:09 -05:00
ten_resources [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
types [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
versions [sdk/*] Add support for resource source positions 2023-07-13 16:46:04 -07:00
README.md Fix an issue where we fail to rethrow exceptions arising from failed resource operations 2018-06-29 16:32:39 -07:00
__init__.py Python Language Host Tests (#1577) 2018-06-29 14:08:58 -07:00
util.py Pass root and main info to language host methods (#14654) 2023-12-10 17:30:51 +00:00

README.md

Python Language Host Tests

The tests in this directory test the language host directly by posing as the engine and running programs in the same context that they would be run by the CLI. Programs run by these tests can create resources, read resource, invoke data sources, and generally do anything that a Pulumi program can do.

Language host tests provide a program to be run and an implementation of the LanghostTest class, which provides implementations for the four resource monitor endpoints that the language host speaks to:

  • invoke, for invoking data sources,
  • read_resource, for reading existing resources,
  • register_resource, for creating new resources,
  • register_resource_outputs, for registering outputs on component resources

Classes deriving from LanghostTest can override any of these methods to provide custom test functionality. This is commonly used to perform assertions or place the language host in unexpected situations.

Adding a new test

To add a new language host test, you can:

  1. Create a new directory in this directory with the name of your test
  2. Place an __init__.py and __main__.py in this directory. __init__.py convinces Python that this directory is a module, while __main__.py indicates to Python that this module is runnable.
  3. Write your Pulumi program in __main__.py. If you want to do assertions, use the assert keyword to do so.
  4. Add a test file, which can have any name. In this test file you'll want to provide a subclass of LanghostTest that drives your test. An example minimal test would be something like this:
from os import path
from ..util import LanghostTest


class EmptyTests(LanghostTest):
    def test_empty(self):
        self.run_test(
            program=path.join(self.base_path(), "empty"), # If your test is in the empty/ subdirectory
            expected_resource_count=0)                    # Assert there are 0 resource registrations

Your class can have any number of test_* methods in them. Language host tests are launched by invoking the run_test method inherited from LanghostTest. run_test accepts the following keyword arguments:

  • project - The name of the project that will be exposed to the running program
  • stack - The name of the stack that will be exposed to the running program
  • program - A path to the program to be run, relative to the working directory.
  • pwd - The working directory to use.
  • args - Command-line arguments to pass to the program.
  • config - A dict of configuration keys and values to pass to the program.
  • expected_resource_count - The number of resources this test is expected to register.
  • expected_error - If non-None, the exact error text that is expected to be received.
  • expected_stderr_contains - If non-None, asserts that the given substring exists in stderr

If expected_error is None, the expected error is asserted to be the empty string.

Note that your test method must begin with test_*, since this is how Python discovers what tests to run.

One additional thing to note is that this test harness explicitly ignores the registration of the top-level Stack resource, pulumi:pulumi:Stack, because it is annoying to write tests around. All expected resource counts do not count this resource as a registration and overridden resource monitor methods will never see a registration for pulumi:pulumi:Stack.