pulumi/sdk/python/lib/test/langhost
Pat Gavlin e1a52693dc
Add support for importing existing resources. (#2893)
A resource can be imported by setting the `import` property in the
resource options bag when instantiating a resource. In order to
successfully import a resource, its desired configuration (i.e. its
inputs) must not differ from its actual configuration (i.e. its state)
as calculated by the resource's provider.

There are a few interesting state transitions hiding here when importing
a resource:
1. No prior resource exists in the checkpoint file. In this case, the
   resource is simply imported.
2. An external resource exists in the checkpoint file. In this case, the
   resource is imported and the old external state is discarded.
3. A non-external resource exists in the checkpoint file and its ID is
   different from the ID to import. In this case, the new resource is
   imported and the old resource is deleted.
4. A non-external resource exists in the checkpoint file, but the ID is
   the same as the ID to import. In this case, the import ID is ignored
   and the resource is treated as it would be in all cases except for
   changes that would replace the resource. In that case, the step
   generator issues an error that indicates that the import ID should be
   removed: were we to move forward with the replace, the new state of
   the stack would fall under case (3), which is almost certainly not
   what the user intends.

Fixes #1662.
2019-07-12 11:12:01 -07:00
..
asset Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
chained_failure Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
component_resource_list_of_providers Simplify API for passing providers to a ComponentResource. (#2609) 2019-06-06 16:20:12 -07:00
component_resource_single_provider Simplify API for passing providers to a ComponentResource. (#2609) 2019-06-06 16:20:12 -07:00
config Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
delete_before_replace Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
empty Python Language Host Tests (#1577) 2018-06-29 14:08:58 -07:00
first_class_provider Store information about a CustomResource's provider in __providers. (#2816) 2019-06-11 16:57:37 -07:00
first_class_provider_invoke Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
first_class_provider_unknown Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
future_input Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
ignore_changes Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
inherit_defaults Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
invalid_property_dependency Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
invoke Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
one_complex_resource Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
one_resource Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
output_all Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
output_nested Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
outputs_future Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
preview Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
property_dependencies Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
property_renaming Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
protect Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
read Implementation of Read for Python (#2752) 2019-05-30 11:04:47 -07:00
resource_op_fail Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
resource_thens Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
runtime_settings Python Language Host Tests (#1577) 2018-06-29 14:08:58 -07:00
stack_output Fix, formalize and add tests for property rewrites (#2187) 2018-11-12 09:26:31 -08:00
ten_resources Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
versions Plumb provider version through language hosts to engine (#2656) 2019-04-23 11:02:51 -07:00
__init__.py Python Language Host Tests (#1577) 2018-06-29 14:08:58 -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
util.py Add support for importing existing resources. (#2893) 2019-07-12 11:12:01 -07:00

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.