How to Test Infrastructure as Code

IaC testing means validating your infrastructure code the same way you test application software—unit tests with mocked cloud providers that run in milliseconds, integration tests that deploy and inspect real resources, and policy checks that enforce compliance rules on every preview and deploy. Together, these layers catch misconfigurations before they reach production.
Untested infrastructure code is a liability. A missing tag in a security group rule, an S3 bucket with public read access, a misconfigured IAM policy—any of these can slip through code review and land in production. Infrastructure bugs are often harder to debug than application bugs, because the feedback loop is slow (deploy, observe, destroy) and the blast radius is large (an outage, a security incident, a surprise AWS bill).
The good news: Pulumi is built on general-purpose programming languages, which means you can test infrastructure code with the exact same tools and frameworks you already use to test application code. No new language to learn. No separate toolchain. Just pytest, Mocha, or go test—pointing at your infrastructure program.
This guide walks through all three testing layers with complete, runnable examples.
Why should you test infrastructure as code?
The case for testing application code is well-established. The case for testing IaC is just as strong—arguably stronger, because the consequences of an undetected bug are more severe.
Catch misconfigurations before they deploy. A unit test that checks whether a security group allows SSH from 0.0.0.0/0 will catch that misconfiguration in milliseconds, before any cloud API call is made. The same test in CI catches it before the code is merged.
Prevent drift and outages. Integration tests that deploy to a staging environment and validate runtime behavior—does the HTTP endpoint return 200? does the database accept connections?—give you confidence that an infrastructure change doesn’t silently break a dependent service.
Refactor safely. Well-tested infrastructure code can be restructured, modularized, and upgraded without fear. When all your properties, tags, and security rules are asserted in tests, you know immediately if a refactor breaks a constraint.
Enforce security and compliance automatically. Policy as code lets you encode your organization’s security rules as executable tests. Mandatory policies block non-compliant deployments entirely; advisory policies surface warnings for human review. These rules run on every pulumi preview and pulumi up—not just at audit time.
Ship infrastructure at software speed. Teams that test IaC ship changes faster, with less fear. The CI pipeline becomes a confidence engine rather than a deployment gate.
The annual DORA State of DevOps research is consistently associated with a pattern among elite-performing engineering teams—those that deploy frequently and recover quickly from failures: comprehensive automated testing across the stack. Infrastructure is no longer exempt from that standard.
What types of IaC tests are there?
IaC testing mirrors the classic software test pyramid: a wide base of fast, cheap unit tests, a smaller layer of integration tests against real infrastructure, and policy checks that enforce rules throughout.
Layer
What it tests
Speed
Cost
Cloud credentials?
Unit tests
Resource properties, tags, security rules, naming conventions
Milliseconds
Free
No
Integration tests
Full stack lifecycle, runtime behavior, cross-resource dependencies
Minutes
Real cloud spend
Yes
Policy as code
Compliance rules, security baselines, organizational standards
Milliseconds
Free
No (runs at preview time)
graph TD
A["🔒 Policy as Code<br/>Compliance & guardrails<br/>Runs at preview time<br/>Milliseconds · Free"] --> B
B["🧪 Integration Tests<br/>Real cloud deployments<br/>Full lifecycle validation<br/>Minutes · Cloud spend"] --> C
C["⚡ Unit Tests<br/>Mocked providers<br/>Property assertions<br/>Milliseconds · Free"]
style A fill:#8A3FFC,color:#fff,stroke:#6B2FD4
style B fill:#0EA5E9,color:#fff,stroke:#0284C7
style C fill:#10B981,color:#fff,stroke:#059669
Start with unit tests—they’re free, fast, and catch the most common mistakes. Add integration tests for critical paths (the deployment pipeline, data infrastructure, security-sensitive resources). Layer in policy as code for compliance requirements that must never regress.
How do you write unit tests for Pulumi?
Pulumi unit tests replace the communication channel between the Pulumi program and the cloud provider with mocks. When the program registers a resource (e.g., aws.ec2.SecurityGroup(...)), the mock intercepts the call, returns dummy state, and never makes a real cloud API call. Tests run in the same process, in the same language, using the same test runner you already use.
Setting up mocks
The import-order rule: You must set up mocks before importing your Pulumi program. If you import the program first, the Pulumi runtime initializes without mocks and will attempt real cloud calls.
<span class="line"><span class="cl"><span class="c1"># test_infra.py</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">unittest</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pulumi</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">MyMocks</span><span class="p">(</span><span class="n">pulumi</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">Mocks</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">new_resource</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">pulumi</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">MockResourceArgs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="c1"># Return [id, state]. State keys must be camelCase.</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">[</span><span class="n">args</span><span class="o">.</span><span class="n">name</span> <span class="o">+</span> <span class="s2">"_id"</span><span class="p">,</span> <span class="n">args</span><span class="o">.</span><span class="n">inputs</span><span class="p">]</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">call</span><span class="p">(</span><span class="bp">self</span><span class="p">,</span> <span class="n">args</span><span class="p">:</span> <span class="n">pulumi</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">MockCallArgs</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Set mocks BEFORE importing the program</span>
</span></span><span class="line"><span class="cl"><span class="n">pulumi</span><span class="o">.</span><span class="n">runtime</span><span class="o">.</span><span class="n">set_mocks</span><span class="p">(</span><span class="n">MyMocks</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">infra</span> <span class="c1"># import program AFTER setting mocks</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">class</span> <span class="nc">TestInfra</span><span class="p">(</span><span class="n">unittest</span><span class="o">.</span><span class="n">TestCase</span><span class="p">):</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nd">@pulumi.runtime.test</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">test_no_public_ssh</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Security group must not expose SSH to the public internet."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">check_security_group</span><span class="p">(</span><span class="n">args</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">ingress_rules</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">rule</span> <span class="ow">in</span> <span class="p">(</span><span class="n">ingress_rules</span> <span class="ow">or</span> <span class="p">[]):</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="n">cidr</span> <span class="ow">in</span> <span class="p">(</span><span class="n">rule</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"cidrBlocks"</span><span class="p">)</span> <span class="ow">or</span> <span class="p">[]):</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">assertNotEqual</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">cidr</span><span class="p">,</span> <span class="s2">"0.0.0.0/0"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"Security group must not expose port 22 to the internet."</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">pulumi</span><span class="o">.</span><span class="n">Output</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">infra</span><span class="o">.</span><span class="n">group</span><span class="o">.</span><span class="n">ingress</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">check_security_group</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nd">@pulumi.runtime.test</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">test_server_has_tags</span><span class="p">(</span><span class="bp">self</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""EC2 instance must have required tags."""</span>
</span></span><span class="line"><span class="cl"> <span class="k">def</span> <span class="nf">check_tags</span><span class="p">(</span><span class="n">args</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">tags</span> <span class="o">=</span> <span class="n">args</span><span class="p">[</span><span class="mi">0</span><span class="p">]</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">assertIn</span><span class="p">(</span><span class="s2">"Environment"</span><span class="p">,</span> <span class="n">tags</span><span class="p">,</span> <span class="s2">"Missing 'Environment' tag"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="bp">self</span><span class="o">.</span><span class="n">assertIn</span><span class="p">(</span><span class="s2">"Name"</span><span class="p">,</span> <span class="n">tags</span><span class="p">,</span> <span class="s2">"Missing 'Name' tag"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">pulumi</span><span class="o">.</span><span class="n">Output</span><span class="o">.</span><span class="n">all</span><span class="p">(</span><span class="n">infra</span><span class="o">.</span><span class="n">server</span><span class="o">.</span><span class="n">tags</span><span class="p">)</span><span class="o">.</span><span class="n">apply</span><span class="p">(</span><span class="n">check_tags</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">if</span> <span class="vm">__name__</span> <span class="o">==</span> <span class="s2">"__main__"</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">unittest</span><span class="o">.</span><span class="n">main</span><span class="p">()</span>
</span></span>
Run with: python -m unittest discover -v
<span class="line"><span class="cl"><span class="c1">// infra.test.ts
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">pulumi</span> <span class="kr">from</span> <span class="s2">"@pulumi/pulumi"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">expect</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">"chai"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1">// Set mocks BEFORE dynamic import of the program
</span></span></span><span class="line"><span class="cl"><span class="nx">pulumi</span><span class="p">.</span><span class="nx">runtime</span><span class="p">.</span><span class="nx">setMocks</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">newResource</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span>: <span class="kt">pulumi.runtime.MockResourceArgs</span><span class="p">)</span><span class="o">:</span> <span class="p">{</span> <span class="nx">id</span>: <span class="kt">string</span><span class="p">;</span> <span class="nx">state</span>: <span class="kt">any</span> <span class="p">}</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// State keys must be camelCase
</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span> <span class="nx">id</span><span class="o">:</span> <span class="sb">`</span><span class="si">${</span><span class="nx">args</span><span class="p">.</span><span class="nx">name</span><span class="si">}</span><span class="sb">-id`</span><span class="p">,</span> <span class="nx">state</span>: <span class="kt">args.inputs</span> <span class="p">};</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="nx">call</span><span class="o">:</span> <span class="p">(</span><span class="nx">args</span>: <span class="kt">pulumi.runtime.MockCallArgs</span><span class="p">)</span> <span class="o">=></span> <span class="p">({</span> <span class="p">...</span><span class="nx">args</span><span class="p">.</span><span class="nx">inputs</span> <span class="p">}),</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"my-project"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="kc">false</span> <span class="c1">// preview = false
</span></span></span><span class="line"><span class="cl"><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">describe</span><span class="p">(</span><span class="s2">"Infrastructure"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">let</span> <span class="nx">infra</span>: <span class="kt">typeof</span> <span class="kr">import</span><span class="p">(</span><span class="s2">"./index"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">before</span><span class="p">(</span><span class="kr">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="c1">// Dynamic import AFTER setting mocks
</span></span></span><span class="line"><span class="cl"> <span class="nx">infra</span> <span class="o">=</span> <span class="k">await</span> <span class="kr">import</span><span class="p">(</span><span class="s2">"./index"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">it</span><span class="p">(</span><span class="s2">"must not expose SSH to the internet"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">pulumi</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span><span class="nx">infra</span><span class="p">.</span><span class="nx">group</span><span class="p">.</span><span class="nx">ingress</span><span class="p">]).</span><span class="nx">apply</span><span class="p">(([</span><span class="nx">ingress</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">rule</span> <span class="k">of</span> <span class="nx">ingress</span> <span class="o">??</span> <span class="p">[])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">cidr</span> <span class="k">of</span> <span class="nx">rule</span><span class="p">.</span><span class="nx">cidrBlocks</span> <span class="o">??</span> <span class="p">[])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">expect</span><span class="p">(</span><span class="nx">cidr</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">not</span><span class="p">.</span><span class="nx">equal</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"0.0.0.0/0"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"Security group must not expose port 22 to the internet"</span>
</span></span><span class="line"><span class="cl"> <span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="nx">done</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">it</span><span class="p">(</span><span class="s2">"must have required tags"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">(</span><span class="nx">done</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">pulumi</span><span class="p">.</span><span class="nx">all</span><span class="p">([</span><span class="nx">infra</span><span class="p">.</span><span class="nx">server</span><span class="p">.</span><span class="nx">tags</span><span class="p">]).</span><span class="nx">apply</span><span class="p">(([</span><span class="nx">tags</span><span class="p">])</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">expect</span><span class="p">(</span><span class="nx">tags</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">include</span><span class="p">.</span><span class="nx">keys</span><span class="p">(</span><span class="s2">"Environment"</span><span class="p">,</span> <span class="s2">"Name"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="nx">done</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span>
Run with: mocha -r ts-node/register infra.test.ts
<span class="line"><span class="cl"><span class="c1">// infra_test.go</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">infra_test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"testing"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi/sdk/v3/go/pulumi"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/stretchr/testify/assert"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="c1">// MockResourceMonitor implements pulumi.ResourceMonitor for unit tests.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">TestNoPublicSSH</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">RunErr</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="o">*</span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">infra</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nf">NewInfra</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">NoError</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">infra</span><span class="p">.</span><span class="nx">Group</span><span class="p">.</span><span class="nx">Ingress</span><span class="p">.</span><span class="nf">ApplyT</span><span class="p">(</span><span class="kd">func</span><span class="p">(</span><span class="nx">rules</span><span class="w"> </span><span class="p">[]</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroupIngress</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">rule</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">rules</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">cidr</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="k">range</span><span class="w"> </span><span class="nx">rule</span><span class="p">.</span><span class="nx">CidrBlocks</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">NotEqual</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="s">"0.0.0.0/0"</span><span class="p">,</span><span class="w"> </span><span class="nx">cidr</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"Security group must not expose port 22 to the internet"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">WithMocks</span><span class="p">(</span><span class="s">"my-project"</span><span class="p">,</span><span class="w"> </span><span class="s">"test"</span><span class="p">,</span><span class="w"> </span><span class="nx">mocks</span><span class="p">{}))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">NoError</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">mocks</span><span class="w"> </span><span class="kd">struct</span><span class="p">{}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">mocks</span><span class="p">)</span><span class="w"> </span><span class="nf">NewResource</span><span class="p">(</span><span class="nx">args</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">MockResourceArgs</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kt">string</span><span class="p">,</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kd">interface</span><span class="p">{},</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">args</span><span class="p">.</span><span class="nx">Name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">"_id"</span><span class="p">,</span><span class="w"> </span><span class="nx">args</span><span class="p">.</span><span class="nx">Inputs</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="p">(</span><span class="nx">mocks</span><span class="p">)</span><span class="w"> </span><span class="nf">Call</span><span class="p">(</span><span class="nx">args</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">MockCallArgs</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kd">interface</span><span class="p">{},</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">args</span><span class="p">.</span><span class="nx">Args</span><span class="p">,</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Run with: go test ./... -v
<span class="line"><span class="cl"><span class="c1">// InfraTests.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Collections.Generic</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Linq</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi.Testing</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Xunit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">InfraTests</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="na"> [Fact]</span>
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="kd">async</span> <span class="n">Task</span> <span class="n">NoPublicSSH</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">resources</span> <span class="p">=</span> <span class="k">await</span> <span class="n">Testing</span><span class="p">.</span><span class="n">RunAsync</span><span class="p"><</span><span class="n">MyStack</span><span class="p">>();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">sg</span> <span class="p">=</span> <span class="n">resources</span><span class="p">.</span><span class="n">OfType</span><span class="p"><</span><span class="n">Pulumi</span><span class="p">.</span><span class="n">Aws</span><span class="p">.</span><span class="n">Ec2</span><span class="p">.</span><span class="n">SecurityGroup</span><span class="p">>().</span><span class="n">First</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">ingress</span> <span class="p">=</span> <span class="k">await</span> <span class="n">sg</span><span class="p">.</span><span class="n">Ingress</span><span class="p">.</span><span class="n">GetValueAsync</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">rule</span> <span class="k">in</span> <span class="n">ingress</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">foreach</span> <span class="p">(</span><span class="kt">var</span> <span class="n">cidr</span> <span class="k">in</span> <span class="n">rule</span><span class="p">.</span><span class="n">CidrBlocks</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Assert</span><span class="p">.</span><span class="n">NotEqual</span><span class="p">(</span><span class="s">"0.0.0.0/0"</span><span class="p">,</span> <span class="n">cidr</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na"> [Fact]</span>
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="kd">async</span> <span class="n">Task</span> <span class="n">ServerHasRequiredTags</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">resources</span> <span class="p">=</span> <span class="k">await</span> <span class="n">Testing</span><span class="p">.</span><span class="n">RunAsync</span><span class="p"><</span><span class="n">MyStack</span><span class="p">>();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">server</span> <span class="p">=</span> <span class="n">resources</span><span class="p">.</span><span class="n">OfType</span><span class="p"><</span><span class="n">Pulumi</span><span class="p">.</span><span class="n">Aws</span><span class="p">.</span><span class="n">Ec2</span><span class="p">.</span><span class="n">Instance</span><span class="p">>().</span><span class="n">First</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">tags</span> <span class="p">=</span> <span class="k">await</span> <span class="n">server</span><span class="p">.</span><span class="n">Tags</span><span class="p">.</span><span class="n">GetValueAsync</span><span class="p">();</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">Assert</span><span class="p">.</span><span class="n">True</span><span class="p">(</span><span class="n">tags</span><span class="p">.</span><span class="n">ContainsKey</span><span class="p">(</span><span class="s">"Environment"</span><span class="p">),</span> <span class="s">"Missing 'Environment' tag"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="n">Assert</span><span class="p">.</span><span class="n">True</span><span class="p">(</span><span class="n">tags</span><span class="p">.</span><span class="n">ContainsKey</span><span class="p">(</span><span class="s">"Name"</span><span class="p">),</span> <span class="s">"Missing 'Name' tag"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span>
Run with: dotnet test
<span class="line"><span class="cl"><span class="c1">// InfraTest.java</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nn">myproject</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.Instance</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.SecurityGroup</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.Mocks</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.Mocks.CallArgs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.Mocks.ResourceArgs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.Mocks.ResourceResult</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.PulumiTest</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.test.TestOptions</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">org.junit.jupiter.api.AfterEach</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">org.junit.jupiter.api.Test</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.HashMap</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Map</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Optional</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.concurrent.CompletableFuture</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import static</span><span class="w"> </span><span class="nn">org.junit.jupiter.api.Assertions.*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">InfraTest</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// Implement Mocks to intercept resource creation. State keys must be camelCase.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">class</span> <span class="nc">MyMocks</span><span class="w"> </span><span class="kd">implements</span><span class="w"> </span><span class="n">Mocks</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">CompletableFuture</span><span class="o"><</span><span class="n">ResourceResult</span><span class="o">></span><span class="w"> </span><span class="nf">newResourceAsync</span><span class="p">(</span><span class="n">ResourceArgs</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">state</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">HashMap</span><span class="o"><></span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="na">inputs</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">completedFuture</span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">ResourceResult</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="n">Optional</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="n">args</span><span class="p">.</span><span class="na">name</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="s">"_id"</span><span class="p">),</span><span class="w"> </span><span class="n">state</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Override</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="n">CompletableFuture</span><span class="o"><</span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">Object</span><span class="o">>></span><span class="w"> </span><span class="nf">callAsync</span><span class="p">(</span><span class="n">CallArgs</span><span class="w"> </span><span class="n">args</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="n">CompletableFuture</span><span class="p">.</span><span class="na">completedFuture</span><span class="p">(</span><span class="n">Map</span><span class="p">.</span><span class="na">of</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="c1">// PulumiTest.cleanup() must run after every test to reset the runtime state.</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@AfterEach</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">cleanup</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">PulumiTest</span><span class="p">.</span><span class="na">cleanup</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">serverHasRequiredTags</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PulumiTest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">withMocks</span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">MyMocks</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">withOptions</span><span class="p">(</span><span class="n">TestOptions</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">projectName</span><span class="p">(</span><span class="s">"project"</span><span class="p">).</span><span class="na">stackName</span><span class="p">(</span><span class="s">"stack"</span><span class="p">).</span><span class="na">preview</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">runTest</span><span class="p">(</span><span class="n">ctx</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Infra</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">instance</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="na">resources</span><span class="p">().</span><span class="na">stream</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">filter</span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="k">instanceof</span><span class="w"> </span><span class="n">Instance</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">map</span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p">(</span><span class="n">Instance</span><span class="p">)</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">findFirst</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">AssertionError</span><span class="p">(</span><span class="s">"EC2 instance not found"</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">tags</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PulumiTest</span><span class="p">.</span><span class="na">extractValue</span><span class="p">(</span><span class="n">instance</span><span class="p">.</span><span class="na">tags</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">AssertionError</span><span class="p">(</span><span class="s">"Tags must not be null"</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">assertTrue</span><span class="p">(</span><span class="n">tags</span><span class="p">.</span><span class="na">containsKey</span><span class="p">(</span><span class="s">"Environment"</span><span class="p">),</span><span class="w"> </span><span class="s">"Missing 'Environment' tag"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">assertTrue</span><span class="p">(</span><span class="n">tags</span><span class="p">.</span><span class="na">containsKey</span><span class="p">(</span><span class="s">"Name"</span><span class="p">),</span><span class="w"> </span><span class="s">"Missing 'Name' tag"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">noPublicSshExposed</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">result</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PulumiTest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">withMocks</span><span class="p">(</span><span class="k">new</span><span class="w"> </span><span class="n">MyMocks</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">withOptions</span><span class="p">(</span><span class="n">TestOptions</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">projectName</span><span class="p">(</span><span class="s">"project"</span><span class="p">).</span><span class="na">stackName</span><span class="p">(</span><span class="s">"stack"</span><span class="p">).</span><span class="na">preview</span><span class="p">(</span><span class="kc">false</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">runTest</span><span class="p">(</span><span class="n">ctx</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Infra</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">group</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">result</span><span class="p">.</span><span class="na">resources</span><span class="p">().</span><span class="na">stream</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">filter</span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="n">r</span><span class="w"> </span><span class="k">instanceof</span><span class="w"> </span><span class="n">SecurityGroup</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">map</span><span class="p">(</span><span class="n">r</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p">(</span><span class="n">SecurityGroup</span><span class="p">)</span><span class="w"> </span><span class="n">r</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">findFirst</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">orElseThrow</span><span class="p">(()</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">AssertionError</span><span class="p">(</span><span class="s">"Security group not found"</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">rules</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">PulumiTest</span><span class="p">.</span><span class="na">extractValue</span><span class="p">(</span><span class="n">group</span><span class="p">.</span><span class="na">ingress</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">var</span><span class="w"> </span><span class="n">rule</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">rules</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">for</span><span class="w"> </span><span class="p">(</span><span class="kd">var</span><span class="w"> </span><span class="n">cidr</span><span class="w"> </span><span class="p">:</span><span class="w"> </span><span class="n">rule</span><span class="p">.</span><span class="na">cidrBlocks</span><span class="p">())</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">assertNotEquals</span><span class="p">(</span><span class="s">"0.0.0.0/0"</span><span class="p">,</span><span class="w"> </span><span class="n">cidr</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"Security group must not expose SSH to the internet"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Run with: mvn test (JUnit 5)
The program under test
Both examples above test this program:
<span class="line"><span class="cl"><span class="c1"># infra.py</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pulumi</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pulumi_aws</span> <span class="kn">import</span> <span class="n">ec2</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">group</span> <span class="o">=</span> <span class="n">ec2</span><span class="o">.</span><span class="n">SecurityGroup</span><span class="p">(</span><span class="s2">"web-secgrp"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">ingress</span><span class="o">=</span><span class="p">[{</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"protocol"</span><span class="p">:</span> <span class="s2">"tcp"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"from_port"</span><span class="p">:</span> <span class="mi">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"to_port"</span><span class="p">:</span> <span class="mi">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"cidrBlocks"</span><span class="p">:</span> <span class="p">[</span><span class="s2">"0.0.0.0/0"</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">}],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">server</span> <span class="o">=</span> <span class="n">ec2</span><span class="o">.</span><span class="n">Instance</span><span class="p">(</span><span class="s2">"web-server"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">instance_type</span><span class="o">=</span><span class="s2">"t2.micro"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">ami</span><span class="o">=</span><span class="s2">"ami-0b0ea68c435eb488d"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">vpc_security_group_ids</span><span class="o">=</span><span class="p">[</span><span class="n">group</span><span class="o">.</span><span class="n">id</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="n">tags</span><span class="o">=</span><span class="p">{</span><span class="s2">"Name"</span><span class="p">:</span> <span class="s2">"web-server"</span><span class="p">,</span> <span class="s2">"Environment"</span><span class="p">:</span> <span class="s2">"dev"</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span>
<span class="line"><span class="cl"><span class="c1">// index.ts
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">pulumi</span> <span class="kr">from</span> <span class="s2">"@pulumi/pulumi"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">aws</span> <span class="kr">from</span> <span class="s2">"@pulumi/aws"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">group</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">aws</span><span class="p">.</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroup</span><span class="p">(</span><span class="s2">"web-secgrp"</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ingress</span><span class="o">:</span> <span class="p">[{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">protocol</span><span class="o">:</span> <span class="s2">"tcp"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">fromPort</span>: <span class="kt">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">toPort</span>: <span class="kt">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">cidrBlocks</span><span class="o">:</span> <span class="p">[</span><span class="s2">"0.0.0.0/0"</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="p">}],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kr">export</span> <span class="kr">const</span> <span class="nx">server</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">aws</span><span class="p">.</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">Instance</span><span class="p">(</span><span class="s2">"web-server"</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">instanceType</span><span class="o">:</span> <span class="s2">"t2.micro"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">ami</span><span class="o">:</span> <span class="s2">"ami-0b0ea68c435eb488d"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">vpcSecurityGroupIds</span><span class="o">:</span> <span class="p">[</span><span class="nx">group</span><span class="p">.</span><span class="nx">id</span><span class="p">],</span>
</span></span><span class="line"><span class="cl"> <span class="nx">tags</span><span class="o">:</span> <span class="p">{</span> <span class="nx">Name</span><span class="o">:</span> <span class="s2">"web-server"</span><span class="p">,</span> <span class="nx">Environment</span><span class="o">:</span> <span class="s2">"dev"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span>
<span class="line"><span class="cl"><span class="c1">// main.go</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">infra_test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/ec2"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi/sdk/v3/go/pulumi"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">type</span><span class="w"> </span><span class="nx">Infra</span><span class="w"> </span><span class="kd">struct</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Group</span><span class="w"> </span><span class="o">*</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroup</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Server</span><span class="w"> </span><span class="o">*</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">Instance</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">NewInfra</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="o">*</span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="p">(</span><span class="o">*</span><span class="nx">Infra</span><span class="p">,</span><span class="w"> </span><span class="kt">error</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">group</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">ec2</span><span class="p">.</span><span class="nf">NewSecurityGroup</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"web-secgrp"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroupArgs</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Ingress</span><span class="p">:</span><span class="w"> </span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroupIngressArray</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">ec2</span><span class="p">.</span><span class="nx">SecurityGroupIngressArgs</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Protocol</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"tcp"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">FromPort</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">Int</span><span class="p">(</span><span class="mi">80</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">ToPort</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">Int</span><span class="p">(</span><span class="mi">80</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">CidrBlocks</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">StringArray</span><span class="p">{</span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"0.0.0.0/0"</span><span class="p">)},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">server</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">ec2</span><span class="p">.</span><span class="nf">NewInstance</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"web-server"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">InstanceArgs</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">InstanceType</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"t2.micro"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Ami</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"ami-0b0ea68c435eb488d"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">VpcSecurityGroupIds</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">StringArray</span><span class="p">{</span><span class="nx">group</span><span class="p">.</span><span class="nf">ID</span><span class="p">()},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Tags</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">StringMap</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"Name"</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"web-server"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"Environment"</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"dev"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="o">&</span><span class="nx">Infra</span><span class="p">{</span><span class="nx">Group</span><span class="p">:</span><span class="w"> </span><span class="nx">group</span><span class="p">,</span><span class="w"> </span><span class="nx">Server</span><span class="p">:</span><span class="w"> </span><span class="nx">server</span><span class="p">},</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
<span class="line"><span class="cl"><span class="c1">// MyStack.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi.Aws.Ec2</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi.Aws.Ec2.Inputs</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">MyStack</span> <span class="p">:</span> <span class="n">Stack</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="n">MyStack</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="k">group</span> <span class="p">=</span> <span class="k">new</span> <span class="n">SecurityGroup</span><span class="p">(</span><span class="s">"web-secgrp"</span><span class="p">,</span> <span class="k">new</span> <span class="n">SecurityGroupArgs</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Ingress</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">new</span> <span class="n">SecurityGroupIngressArgs</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Protocol</span> <span class="p">=</span> <span class="s">"tcp"</span><span class="p">,</span> <span class="n">FromPort</span> <span class="p">=</span> <span class="m">80</span><span class="p">,</span> <span class="n">ToPort</span> <span class="p">=</span> <span class="m">80</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">CidrBlocks</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="s">"0.0.0.0/0"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">server</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Instance</span><span class="p">(</span><span class="s">"web-server"</span><span class="p">,</span> <span class="k">new</span> <span class="n">InstanceArgs</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">InstanceType</span> <span class="p">=</span> <span class="s">"t2.micro"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">Ami</span> <span class="p">=</span> <span class="s">"ami-0b0ea68c435eb488d"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">VpcSecurityGroupIds</span> <span class="p">=</span> <span class="k">new</span><span class="p">[]</span> <span class="p">{</span> <span class="k">group</span><span class="p">.</span><span class="n">Id</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span> <span class="n">InputMap</span><span class="p"><</span><span class="kt">string</span><span class="p">></span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="s">"Name"</span><span class="p">,</span> <span class="s">"web-server"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span> <span class="s">"Environment"</span><span class="p">,</span> <span class="s">"dev"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span>
<span class="line"><span class="cl"><span class="c1">// Infra.java</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nn">myproject</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.Context</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.Pulumi</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.SecurityGroup</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.SecurityGroupArgs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.Instance</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.InstanceArgs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.aws.ec2.inputs.SecurityGroupIngressArgs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.List</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Map</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">public</span><span class="w"> </span><span class="kd">class</span> <span class="nc">Infra</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">SecurityGroup</span><span class="w"> </span><span class="n">group</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">Instance</span><span class="w"> </span><span class="n">server</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">public</span><span class="w"> </span><span class="nf">Infra</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">group</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">SecurityGroup</span><span class="p">(</span><span class="s">"web-secgrp"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">SecurityGroupArgs</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">ingress</span><span class="p">(</span><span class="n">SecurityGroupIngressArgs</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">protocol</span><span class="p">(</span><span class="s">"tcp"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">fromPort</span><span class="p">(</span><span class="n">80</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">toPort</span><span class="p">(</span><span class="n">80</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">cidrBlocks</span><span class="p">(</span><span class="s">"0.0.0.0/0"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">this</span><span class="p">.</span><span class="na">server</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">Instance</span><span class="p">(</span><span class="s">"web-server"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">InstanceArgs</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">instanceType</span><span class="p">(</span><span class="s">"t2.micro"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">ami</span><span class="p">(</span><span class="s">"ami-0b0ea68c435eb488d"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">vpcSecurityGroupIds</span><span class="p">(</span><span class="n">group</span><span class="p">.</span><span class="na">id</span><span class="p">().</span><span class="na">applyValue</span><span class="p">(</span><span class="n">List</span><span class="p">::</span><span class="n">of</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">tags</span><span class="p">(</span><span class="n">Map</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="s">"Name"</span><span class="p">,</span><span class="w"> </span><span class="s">"web-server"</span><span class="p">,</span><span class="w"> </span><span class="s">"Environment"</span><span class="p">,</span><span class="w"> </span><span class="s">"dev"</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Key detail: State property keys in the mock’s
new_resource/newResourcereturn value must be camelCase (cidrBlocks, notcidr_blocks), regardless of the language you’re writing in. This is how Pulumi serializes properties internally.
How do you run integration tests against real cloud resources?
Unit tests tell you whether your resource definitions are correct. Integration tests tell you whether your infrastructure actually works. Integration tests deploy real cloud resources, run assertions against them, and then destroy everything—giving you end-to-end confidence at the cost of actual cloud spend and time.
Using the Automation API
The Pulumi Automation API lets you drive pulumi up, pulumi destroy, and every other Pulumi CLI operation programmatically, from within a test. You define the stack inline (using a function that runs your Pulumi program) or point it at an existing project directory.
<span class="line"><span class="cl"><span class="c1"># test_integration.py</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pytest</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pulumi</span>
</span></span><span class="line"><span class="cl"><span class="kn">import</span> <span class="nn">pulumi_aws</span> <span class="k">as</span> <span class="nn">aws</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pulumi</span> <span class="kn">import</span> <span class="n">automation</span> <span class="k">as</span> <span class="n">auto</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">create_bucket_program</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""The Pulumi program to deploy during the test."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">bucket</span> <span class="o">=</span> <span class="n">aws</span><span class="o">.</span><span class="n">s3</span><span class="o">.</span><span class="n">Bucket</span><span class="p">(</span><span class="s2">"test-bucket"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">tags</span><span class="o">=</span><span class="p">{</span><span class="s2">"Environment"</span><span class="p">:</span> <span class="s2">"test"</span><span class="p">,</span> <span class="s2">"ManagedBy"</span><span class="p">:</span> <span class="s2">"pulumi"</span><span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">pulumi</span><span class="o">.</span><span class="n">export</span><span class="p">(</span><span class="s2">"bucket_name"</span><span class="p">,</span> <span class="n">bucket</span><span class="o">.</span><span class="n">id</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">pulumi</span><span class="o">.</span><span class="n">export</span><span class="p">(</span><span class="s2">"bucket_arn"</span><span class="p">,</span> <span class="n">bucket</span><span class="o">.</span><span class="n">arn</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nd">@pytest.fixture</span><span class="p">(</span><span class="n">scope</span><span class="o">=</span><span class="s2">"module"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">deployed_stack</span><span class="p">():</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Deploy the stack for the test module and destroy it when done."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack</span> <span class="o">=</span> <span class="n">auto</span><span class="o">.</span><span class="n">create_or_select_stack</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack_name</span><span class="o">=</span><span class="s2">"integration-test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">project_name</span><span class="o">=</span><span class="s2">"bucket-test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">program</span><span class="o">=</span><span class="n">create_bucket_program</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack</span><span class="o">.</span><span class="n">set_config</span><span class="p">(</span><span class="s2">"aws:region"</span><span class="p">,</span> <span class="n">auto</span><span class="o">.</span><span class="n">ConfigValue</span><span class="p">(</span><span class="n">value</span><span class="o">=</span><span class="s2">"us-west-2"</span><span class="p">))</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Install provider plugins</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack</span><span class="o">.</span><span class="n">workspace</span><span class="o">.</span><span class="n">install_plugin</span><span class="p">(</span><span class="s2">"aws"</span><span class="p">,</span> <span class="s2">"v7.34.0"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Deploy</span>
</span></span><span class="line"><span class="cl"> <span class="n">up_result</span> <span class="o">=</span> <span class="n">stack</span><span class="o">.</span><span class="n">up</span><span class="p">(</span><span class="n">on_output</span><span class="o">=</span><span class="nb">print</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">yield</span> <span class="n">up_result</span><span class="o">.</span><span class="n">outputs</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="c1"># Teardown: destroy everything after the test module completes</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack</span><span class="o">.</span><span class="n">destroy</span><span class="p">(</span><span class="n">on_output</span><span class="o">=</span><span class="nb">print</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">stack</span><span class="o">.</span><span class="n">workspace</span><span class="o">.</span><span class="n">remove_stack</span><span class="p">(</span><span class="s2">"integration-test"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_bucket_was_created</span><span class="p">(</span><span class="n">deployed_stack</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""The S3 bucket should have been created with the expected name prefix."""</span>
</span></span><span class="line"><span class="cl"> <span class="n">bucket_name</span> <span class="o">=</span> <span class="n">deployed_stack</span><span class="p">[</span><span class="s2">"bucket_name"</span><span class="p">]</span><span class="o">.</span><span class="n">value</span>
</span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="n">bucket_name</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"test-bucket"</span><span class="p">),</span> <span class="sa">f</span><span class="s2">"Unexpected bucket name: </span><span class="si">{</span><span class="n">bucket_name</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">test_bucket_has_tags</span><span class="p">(</span><span class="n">deployed_stack</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="s2">"""Verify the bucket was created with required tags (via AWS SDK)."""</span>
</span></span><span class="line"><span class="cl"> <span class="kn">import</span> <span class="nn">boto3</span>
</span></span><span class="line"><span class="cl"> <span class="n">s3</span> <span class="o">=</span> <span class="n">boto3</span><span class="o">.</span><span class="n">client</span><span class="p">(</span><span class="s2">"s3"</span><span class="p">,</span> <span class="n">region_name</span><span class="o">=</span><span class="s2">"us-west-2"</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">bucket_name</span> <span class="o">=</span> <span class="n">deployed_stack</span><span class="p">[</span><span class="s2">"bucket_name"</span><span class="p">]</span><span class="o">.</span><span class="n">value</span>
</span></span><span class="line"><span class="cl"> <span class="n">tagging</span> <span class="o">=</span> <span class="n">s3</span><span class="o">.</span><span class="n">get_bucket_tagging</span><span class="p">(</span><span class="n">Bucket</span><span class="o">=</span><span class="n">bucket_name</span><span class="p">)</span>
</span></span><span class="line"><span class="cl"> <span class="n">tag_map</span> <span class="o">=</span> <span class="p">{</span><span class="n">t</span><span class="p">[</span><span class="s2">"Key"</span><span class="p">]:</span> <span class="n">t</span><span class="p">[</span><span class="s2">"Value"</span><span class="p">]</span> <span class="k">for</span> <span class="n">t</span> <span class="ow">in</span> <span class="n">tagging</span><span class="p">[</span><span class="s2">"TagSet"</span><span class="p">]}</span>
</span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="n">tag_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"Environment"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"test"</span>
</span></span><span class="line"><span class="cl"> <span class="k">assert</span> <span class="n">tag_map</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"ManagedBy"</span><span class="p">)</span> <span class="o">==</span> <span class="s2">"pulumi"</span>
</span></span>
Run with: pytest test_integration.py -v
<span class="line"><span class="cl"><span class="c1">// integration.test.ts
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">LocalWorkspace</span><span class="p">,</span> <span class="nx">ConfigValue</span><span class="p">,</span> <span class="nx">UpResult</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">"@pulumi/pulumi/automation"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">aws</span> <span class="kr">from</span> <span class="s2">"@pulumi/aws"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">pulumi</span> <span class="kr">from</span> <span class="s2">"@pulumi/pulumi"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">expect</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">"chai"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="nx">describe</span><span class="p">(</span><span class="s2">"S3 Bucket Integration"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">this</span><span class="p">.</span><span class="nx">timeout</span><span class="p">(</span><span class="mi">300</span><span class="nx">_000</span><span class="p">);</span> <span class="c1">// 5 min — real deploys take time
</span></span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kd">let</span> <span class="nx">outputs</span>: <span class="kt">UpResult</span><span class="p">[</span><span class="s2">"outputs"</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"> <span class="kd">let</span> <span class="nx">stackName</span> <span class="o">=</span> <span class="s2">"integration-test-ts"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">before</span><span class="p">(</span><span class="kr">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">stack</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">LocalWorkspace</span><span class="p">.</span><span class="nx">createOrSelectStack</span><span class="p">({</span>
</span></span><span class="line"><span class="cl"> <span class="nx">stackName</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">projectName</span><span class="o">:</span> <span class="s2">"bucket-test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">program</span>: <span class="kt">async</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">bucket</span> <span class="o">=</span> <span class="k">new</span> <span class="nx">aws</span><span class="p">.</span><span class="nx">s3</span><span class="p">.</span><span class="nx">Bucket</span><span class="p">(</span><span class="s2">"test-bucket"</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">tags</span><span class="o">:</span> <span class="p">{</span> <span class="nx">Environment</span><span class="o">:</span> <span class="s2">"test"</span><span class="p">,</span> <span class="nx">ManagedBy</span><span class="o">:</span> <span class="s2">"pulumi"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">bucketName</span>: <span class="kt">bucket.id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">bucketArn</span>: <span class="kt">bucket.arn</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">};</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">setConfig</span><span class="p">(</span><span class="s2">"aws:region"</span><span class="p">,</span> <span class="p">{</span> <span class="nx">value</span><span class="o">:</span> <span class="s2">"us-west-2"</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">workspace</span><span class="p">.</span><span class="nx">installPlugin</span><span class="p">(</span><span class="s2">"aws"</span><span class="p">,</span> <span class="s2">"v7.34.0"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">upResult</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">up</span><span class="p">({</span> <span class="nx">onOutput</span>: <span class="kt">console.log</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="nx">outputs</span> <span class="o">=</span> <span class="nx">upResult</span><span class="p">.</span><span class="nx">outputs</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">after</span><span class="p">(</span><span class="kr">async</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">stack</span> <span class="o">=</span> <span class="k">await</span> <span class="nx">LocalWorkspace</span><span class="p">.</span><span class="nx">selectStack</span><span class="p">({</span> <span class="nx">stackName</span><span class="p">,</span> <span class="nx">projectName</span><span class="o">:</span> <span class="s2">"bucket-test"</span><span class="p">,</span> <span class="nx">program</span>: <span class="kt">async</span> <span class="p">()</span> <span class="o">=></span> <span class="p">{}</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">destroy</span><span class="p">({</span> <span class="nx">onOutput</span>: <span class="kt">console.log</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="nx">stack</span><span class="p">.</span><span class="nx">workspace</span><span class="p">.</span><span class="nx">removeStack</span><span class="p">(</span><span class="nx">stackName</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="nx">it</span><span class="p">(</span><span class="s2">"creates a bucket with the right name prefix"</span><span class="p">,</span> <span class="kd">function</span> <span class="p">()</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">name</span> <span class="o">=</span> <span class="nx">outputs</span><span class="p">[</span><span class="s2">"bucketName"</span><span class="p">].</span><span class="nx">value</span> <span class="kr">as</span> <span class="kt">string</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"> <span class="nx">expect</span><span class="p">(</span><span class="nx">name</span><span class="p">).</span><span class="nx">to</span><span class="p">.</span><span class="nx">match</span><span class="p">(</span><span class="sr">/^test-bucket/</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span>
Run with: mocha -r ts-node/register integration.test.ts
<span class="line"><span class="cl"><span class="c1">// integration_test.go</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nx">integration_test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="p">(</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"context"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"fmt"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"os"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"testing"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi-aws/sdk/v6/go/aws/s3"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi/sdk/v3/go/auto"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi/sdk/v3/go/auto/optup"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/pulumi/pulumi/sdk/v3/go/pulumi"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"github.com/stretchr/testify/assert"</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">TestBucketIntegration</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">ctx</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">context</span><span class="p">.</span><span class="nf">Background</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">stack</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">auto</span><span class="p">.</span><span class="nf">NewStackInlineSource</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"integration-test"</span><span class="p">,</span><span class="w"> </span><span class="s">"bucket-test"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">ctx</span><span class="w"> </span><span class="o">*</span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">Context</span><span class="p">)</span><span class="w"> </span><span class="kt">error</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">bucket</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">s3</span><span class="p">.</span><span class="nf">NewBucket</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"test-bucket"</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">s3</span><span class="p">.</span><span class="nx">BucketArgs</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Tags</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nx">StringMap</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"Environment"</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"test"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="s">"ManagedBy"</span><span class="p">:</span><span class="w"> </span><span class="nx">pulumi</span><span class="p">.</span><span class="nf">String</span><span class="p">(</span><span class="s">"pulumi"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">nil</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="nx">err</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">ctx</span><span class="p">.</span><span class="nf">Export</span><span class="p">(</span><span class="s">"bucketName"</span><span class="p">,</span><span class="w"> </span><span class="nx">bucket</span><span class="p">.</span><span class="nf">ID</span><span class="p">())</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">return</span><span class="w"> </span><span class="kc">nil</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">NoError</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">stack</span><span class="p">.</span><span class="nf">SetConfig</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"aws:region"</span><span class="p">,</span><span class="w"> </span><span class="nx">auto</span><span class="p">.</span><span class="nx">ConfigValue</span><span class="p">{</span><span class="nx">Value</span><span class="p">:</span><span class="w"> </span><span class="s">"us-west-2"</span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">upResult</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">stack</span><span class="p">.</span><span class="nf">Up</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="nx">optup</span><span class="p">.</span><span class="nf">ProgressStreams</span><span class="p">(</span><span class="nx">os</span><span class="p">.</span><span class="nx">Stdout</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">NoError</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">err</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">t</span><span class="p">.</span><span class="nf">Cleanup</span><span class="p">(</span><span class="kd">func</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">_</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">stack</span><span class="p">.</span><span class="nf">Destroy</span><span class="p">(</span><span class="nx">ctx</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="p">=</span><span class="w"> </span><span class="nx">stack</span><span class="p">.</span><span class="nf">Workspace</span><span class="p">().</span><span class="nf">RemoveStack</span><span class="p">(</span><span class="nx">ctx</span><span class="p">,</span><span class="w"> </span><span class="s">"integration-test"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">name</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">fmt</span><span class="p">.</span><span class="nf">Sprintf</span><span class="p">(</span><span class="s">"%v"</span><span class="p">,</span><span class="w"> </span><span class="nx">upResult</span><span class="p">.</span><span class="nx">Outputs</span><span class="p">[</span><span class="s">"bucketName"</span><span class="p">].</span><span class="nx">Value</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">Contains</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="nx">name</span><span class="p">,</span><span class="w"> </span><span class="s">"test-bucket"</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Run with: go test ./... -v -timeout 10m
<span class="line"><span class="cl"><span class="c1">// IntegrationTests.cs</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">System.Threading.Tasks</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Pulumi.Automation</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="k">using</span> <span class="nn">Xunit</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="kd">public</span> <span class="k">class</span> <span class="nc">IntegrationTests</span> <span class="p">:</span> <span class="n">IAsyncLifetime</span>
</span></span><span class="line"><span class="cl"><span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kd">private</span> <span class="n">WorkspaceStack</span> <span class="n">_stack</span> <span class="p">=</span> <span class="kc">null</span><span class="p">!;</span>
</span></span><span class="line"><span class="cl"> <span class="kd">private</span> <span class="n">UpResult</span> <span class="n">_upResult</span> <span class="p">=</span> <span class="kc">null</span><span class="p">!;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="kd">async</span> <span class="n">Task</span> <span class="n">InitializeAsync</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">program</span> <span class="p">=</span> <span class="n">PulumiFn</span><span class="p">.</span><span class="n">Create</span><span class="p">(()</span> <span class="p">=></span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">bucket</span> <span class="p">=</span> <span class="k">new</span> <span class="n">Pulumi</span><span class="p">.</span><span class="n">Aws</span><span class="p">.</span><span class="n">S3</span><span class="p">.</span><span class="n">Bucket</span><span class="p">(</span><span class="s">"test-bucket"</span><span class="p">,</span> <span class="k">new</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="n">Tags</span> <span class="p">=</span> <span class="k">new</span><span class="p">()</span> <span class="p">{</span> <span class="p">[</span><span class="s">"Environment"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"test"</span><span class="p">,</span> <span class="p">[</span><span class="s">"ManagedBy"</span><span class="p">]</span> <span class="p">=</span> <span class="s">"pulumi"</span> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="k">new</span> <span class="n">System</span><span class="p">.</span><span class="n">Collections</span><span class="p">.</span><span class="n">Generic</span><span class="p">.</span><span class="n">Dictionary</span><span class="p"><</span><span class="kt">string</span><span class="p">,</span> <span class="kt">object?</span><span class="p">></span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"><span class="na"> ["bucketName"]</span> <span class="p">=</span> <span class="n">bucket</span><span class="p">.</span><span class="n">Id</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">};</span>
</span></span><span class="line"><span class="cl"> <span class="p">});</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="n">_stack</span> <span class="p">=</span> <span class="k">await</span> <span class="n">LocalWorkspace</span><span class="p">.</span><span class="n">CreateOrSelectStackAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">InlineProgramArgs</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">projectName</span><span class="p">:</span> <span class="s">"bucket-test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">stackName</span><span class="p">:</span> <span class="s">"integration-test"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">program</span><span class="p">:</span> <span class="n">program</span>
</span></span><span class="line"><span class="cl"> <span class="p">));</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">_stack</span><span class="p">.</span><span class="n">SetConfigAsync</span><span class="p">(</span><span class="s">"aws:region"</span><span class="p">,</span> <span class="k">new</span> <span class="n">ConfigValue</span><span class="p">(</span><span class="s">"us-west-2"</span><span class="p">));</span>
</span></span><span class="line"><span class="cl"> <span class="n">_upResult</span> <span class="p">=</span> <span class="k">await</span> <span class="n">_stack</span><span class="p">.</span><span class="n">UpAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">UpOptions</span> <span class="p">{</span> <span class="n">OnStandardOutput</span> <span class="p">=</span> <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="kd">async</span> <span class="n">Task</span> <span class="n">DisposeAsync</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">_stack</span><span class="p">.</span><span class="n">DestroyAsync</span><span class="p">(</span><span class="k">new</span> <span class="n">DestroyOptions</span> <span class="p">{</span> <span class="n">OnStandardOutput</span> <span class="p">=</span> <span class="n">Console</span><span class="p">.</span><span class="n">WriteLine</span> <span class="p">});</span>
</span></span><span class="line"><span class="cl"> <span class="k">await</span> <span class="n">_stack</span><span class="p">.</span><span class="n">Workspace</span><span class="p">.</span><span class="n">RemoveStackAsync</span><span class="p">(</span><span class="s">"integration-test"</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="na">
</span></span></span><span class="line"><span class="cl"><span class="na"> [Fact]</span>
</span></span><span class="line"><span class="cl"> <span class="kd">public</span> <span class="k">void</span> <span class="n">BucketNameHasExpectedPrefix</span><span class="p">()</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kt">var</span> <span class="n">name</span> <span class="p">=</span> <span class="n">_upResult</span><span class="p">.</span><span class="n">Outputs</span><span class="p">[</span><span class="s">"bucketName"</span><span class="p">].</span><span class="n">Value</span><span class="p">.</span><span class="n">ToString</span><span class="p">();</span>
</span></span><span class="line"><span class="cl"> <span class="n">Assert</span><span class="p">.</span><span class="n">StartsWith</span><span class="p">(</span><span class="s">"test-bucket"</span><span class="p">,</span> <span class="n">name</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"><span class="p">}</span>
</span></span>
Run with: dotnet test
<span class="line"><span class="cl"><span class="c1">// IntegrationTest.java</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">package</span><span class="w"> </span><span class="nn">myproject</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.Context</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.automation.LocalWorkspace</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.automation.UpOptions</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.automation.DestroyOptions</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.automation.ConfigValue</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">com.pulumi.automation.WorkspaceStack</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">org.junit.jupiter.api.*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import</span><span class="w"> </span><span class="nn">java.util.Map</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kn">import static</span><span class="w"> </span><span class="nn">org.junit.jupiter.api.Assertions.*</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nd">@TestInstance</span><span class="p">(</span><span class="n">TestInstance</span><span class="p">.</span><span class="na">Lifecycle</span><span class="p">.</span><span class="na">PER_CLASS</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="kd">class</span> <span class="nc">IntegrationTest</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">PROJECT_NAME</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"bucket_test_project"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="kd">static</span><span class="w"> </span><span class="kd">final</span><span class="w"> </span><span class="n">String</span><span class="w"> </span><span class="n">STACK_NAME</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="s">"integration-test"</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">WorkspaceStack</span><span class="w"> </span><span class="n">stack</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">private</span><span class="w"> </span><span class="n">Map</span><span class="o"><</span><span class="n">String</span><span class="p">,</span><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="na">pulumi</span><span class="p">.</span><span class="na">automation</span><span class="p">.</span><span class="na">OutputValue</span><span class="o">></span><span class="w"> </span><span class="n">outputs</span><span class="p">;</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@BeforeAll</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">setUp</span><span class="p">()</span><span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">Exception</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">stack</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">LocalWorkspace</span><span class="p">.</span><span class="na">createOrSelectStack</span><span class="p">(</span><span class="n">PROJECT_NAME</span><span class="p">,</span><span class="w"> </span><span class="n">STACK_NAME</span><span class="p">,</span><span class="w"> </span><span class="p">(</span><span class="n">Context</span><span class="w"> </span><span class="n">ctx</span><span class="p">)</span><span class="w"> </span><span class="o">-></span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">bucket</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="na">pulumi</span><span class="p">.</span><span class="na">aws</span><span class="p">.</span><span class="na">s3</span><span class="p">.</span><span class="na">Bucket</span><span class="p">(</span><span class="s">"test-bucket"</span><span class="p">,</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">com</span><span class="p">.</span><span class="na">pulumi</span><span class="p">.</span><span class="na">aws</span><span class="p">.</span><span class="na">s3</span><span class="p">.</span><span class="na">BucketArgs</span><span class="p">.</span><span class="na">builder</span><span class="p">()</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">tags</span><span class="p">(</span><span class="n">Map</span><span class="p">.</span><span class="na">of</span><span class="p">(</span><span class="s">"Environment"</span><span class="p">,</span><span class="w"> </span><span class="s">"test"</span><span class="p">,</span><span class="w"> </span><span class="s">"ManagedBy"</span><span class="p">,</span><span class="w"> </span><span class="s">"pulumi"</span><span class="p">))</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">.</span><span class="na">build</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">ctx</span><span class="p">.</span><span class="na">export</span><span class="p">(</span><span class="s">"bucketName"</span><span class="p">,</span><span class="w"> </span><span class="n">bucket</span><span class="p">.</span><span class="na">id</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">});</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">stack</span><span class="p">.</span><span class="na">workspace</span><span class="p">().</span><span class="na">installPlugin</span><span class="p">(</span><span class="s">"aws"</span><span class="p">,</span><span class="w"> </span><span class="s">"v7.34.0"</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">stack</span><span class="p">.</span><span class="na">setConfig</span><span class="p">(</span><span class="s">"aws:region"</span><span class="p">,</span><span class="w"> </span><span class="k">new</span><span class="w"> </span><span class="n">ConfigValue</span><span class="p">(</span><span class="s">"us-west-2"</span><span class="p">));</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">upResult</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">stack</span><span class="p">.</span><span class="na">up</span><span class="p">(</span><span class="n">UpOptions</span><span class="p">.</span><span class="na">builder</span><span class="p">().</span><span class="na">onStandardOutput</span><span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">::</span><span class="n">println</span><span class="p">).</span><span class="na">build</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">outputs</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="n">upResult</span><span class="p">.</span><span class="na">outputs</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@AfterAll</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">tearDown</span><span class="p">()</span><span class="w"> </span><span class="kd">throws</span><span class="w"> </span><span class="n">Exception</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="k">if</span><span class="w"> </span><span class="p">(</span><span class="n">stack</span><span class="w"> </span><span class="o">!=</span><span class="w"> </span><span class="kc">null</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">stack</span><span class="p">.</span><span class="na">destroy</span><span class="p">(</span><span class="n">DestroyOptions</span><span class="p">.</span><span class="na">builder</span><span class="p">().</span><span class="na">onStandardOutput</span><span class="p">(</span><span class="n">System</span><span class="p">.</span><span class="na">out</span><span class="p">::</span><span class="n">println</span><span class="p">).</span><span class="na">build</span><span class="p">());</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">stack</span><span class="p">.</span><span class="na">workspace</span><span class="p">().</span><span class="na">removeStack</span><span class="p">(</span><span class="n">STACK_NAME</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nd">@Test</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kt">void</span><span class="w"> </span><span class="nf">bucketNameHasExpectedPrefix</span><span class="p">()</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="kd">var</span><span class="w"> </span><span class="n">name</span><span class="w"> </span><span class="o">=</span><span class="w"> </span><span class="p">(</span><span class="n">String</span><span class="p">)</span><span class="w"> </span><span class="n">outputs</span><span class="p">.</span><span class="na">get</span><span class="p">(</span><span class="s">"bucketName"</span><span class="p">).</span><span class="na">value</span><span class="p">();</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="n">assertTrue</span><span class="p">(</span><span class="n">name</span><span class="p">.</span><span class="na">startsWith</span><span class="p">(</span><span class="s">"test-bucket"</span><span class="p">),</span><span class="w"> </span><span class="s">"Unexpected bucket name: "</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="n">name</span><span class="p">);</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Run with: mvn test
Using the Go integration framework
If you prefer Go-based integration tests, Pulumi ships a purpose-built Go test framework at github.com/pulumi/pulumi/pkg/v3/testing/integration. It handles the full create → validate → destroy lifecycle for any Pulumi program (written in any language), with an ExtraRuntimeValidation hook for assertions against deployed state.
<span class="line"><span class="cl"><span class="kd">func</span><span class="w"> </span><span class="nf">TestS3Website</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">integration</span><span class="p">.</span><span class="nf">ProgramTest</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="o">&</span><span class="nx">integration</span><span class="p">.</span><span class="nx">ProgramTestOptions</span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Dir</span><span class="p">:</span><span class="w"> </span><span class="nx">path</span><span class="p">.</span><span class="nf">Join</span><span class="p">(</span><span class="s">".."</span><span class="p">,</span><span class="w"> </span><span class="s">"my-s3-website"</span><span class="p">),</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">Config</span><span class="p">:</span><span class="w"> </span><span class="kd">map</span><span class="p">[</span><span class="kt">string</span><span class="p">]</span><span class="kt">string</span><span class="p">{</span><span class="s">"aws:region"</span><span class="p">:</span><span class="w"> </span><span class="s">"us-west-2"</span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">ExtraRuntimeValidation</span><span class="p">:</span><span class="w"> </span><span class="kd">func</span><span class="p">(</span><span class="nx">t</span><span class="w"> </span><span class="o">*</span><span class="nx">testing</span><span class="p">.</span><span class="nx">T</span><span class="p">,</span><span class="w"> </span><span class="nx">stack</span><span class="w"> </span><span class="nx">integration</span><span class="p">.</span><span class="nx">RuntimeValidationStackInfo</span><span class="p">)</span><span class="w"> </span><span class="p">{</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">url</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">stack</span><span class="p">.</span><span class="nx">Outputs</span><span class="p">[</span><span class="s">"websiteUrl"</span><span class="p">].(</span><span class="kt">string</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">resp</span><span class="p">,</span><span class="w"> </span><span class="nx">_</span><span class="w"> </span><span class="o">:=</span><span class="w"> </span><span class="nx">http</span><span class="p">.</span><span class="nf">Get</span><span class="p">(</span><span class="s">"http://"</span><span class="w"> </span><span class="o">+</span><span class="w"> </span><span class="nx">url</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nx">assert</span><span class="p">.</span><span class="nf">Equal</span><span class="p">(</span><span class="nx">t</span><span class="p">,</span><span class="w"> </span><span class="mi">200</span><span class="p">,</span><span class="w"> </span><span class="nx">resp</span><span class="p">.</span><span class="nx">StatusCode</span><span class="p">)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">},</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="p">})</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="p">}</span><span class="w">
</span></span></span>
Best practice: Always destroy test stacks in a
finallyblock or test teardown fixture. Leaked integration test stacks are a common cause of unexpected cloud spend.
How does policy as code complement IaC testing?
Unit and integration tests validate what your infrastructure does. Policy as code enforces what your infrastructure must conform to—security standards, tagging conventions, compliance requirements—and it runs automatically on every pulumi preview and pulumi up.
Pulumi Policies are currently supported in Python and TypeScript. You write policies in the same language as the rest of your stack, without learning a DSL. A mandatory policy blocks a deployment entirely when violated; an advisory policy surfaces a warning but allows the deploy to proceed.
<span class="line"><span class="cl"><span class="c1"># __main__.py in your policy pack directory</span>
</span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pulumi_policy</span> <span class="kn">import</span> <span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">EnforcementLevel</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">PolicyPack</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">ReportViolation</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">ResourceValidationArgs</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">ResourceValidationPolicy</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">REQUIRED_TAGS</span> <span class="o">=</span> <span class="p">{</span><span class="s2">"Name"</span><span class="p">,</span> <span class="s2">"Environment"</span><span class="p">,</span> <span class="s2">"Owner"</span><span class="p">}</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">require_tags</span><span class="p">(</span><span class="n">args</span><span class="p">:</span> <span class="n">ResourceValidationArgs</span><span class="p">,</span> <span class="n">report_violation</span><span class="p">:</span> <span class="n">ReportViolation</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">resource_type</span><span class="o">.</span><span class="n">startswith</span><span class="p">(</span><span class="s2">"aws:"</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">tags</span> <span class="o">=</span> <span class="n">args</span><span class="o">.</span><span class="n">props</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"tags"</span><span class="p">)</span> <span class="ow">or</span> <span class="p">{}</span>
</span></span><span class="line"><span class="cl"> <span class="n">missing</span> <span class="o">=</span> <span class="n">REQUIRED_TAGS</span> <span class="o">-</span> <span class="nb">set</span><span class="p">(</span><span class="n">tags</span><span class="o">.</span><span class="n">keys</span><span class="p">())</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">missing</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="n">report_violation</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="sa">f</span><span class="s2">"Resource is missing required tags: </span><span class="si">{</span><span class="s1">', '</span><span class="o">.</span><span class="n">join</span><span class="p">(</span><span class="nb">sorted</span><span class="p">(</span><span class="n">missing</span><span class="p">))</span><span class="si">}</span><span class="s2">"</span>
</span></span><span class="line"><span class="cl"> <span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">no_public_s3</span><span class="p">(</span><span class="n">args</span><span class="p">:</span> <span class="n">ResourceValidationArgs</span><span class="p">,</span> <span class="n">report_violation</span><span class="p">:</span> <span class="n">ReportViolation</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">resource_type</span> <span class="o">==</span> <span class="s2">"aws:s3/bucket:Bucket"</span><span class="p">:</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="n">args</span><span class="o">.</span><span class="n">props</span><span class="o">.</span><span class="n">get</span><span class="p">(</span><span class="s2">"acl"</span><span class="p">)</span> <span class="ow">in</span> <span class="p">(</span><span class="s2">"public-read"</span><span class="p">,</span> <span class="s2">"public-read-write"</span><span class="p">):</span>
</span></span><span class="line"><span class="cl"> <span class="n">report_violation</span><span class="p">(</span><span class="s2">"S3 buckets must not have a public ACL."</span><span class="p">)</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="n">PolicyPack</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">name</span><span class="o">=</span><span class="s2">"aws-security-baseline"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">policies</span><span class="o">=</span><span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="n">ResourceValidationPolicy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">name</span><span class="o">=</span><span class="s2">"require-tags"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">description</span><span class="o">=</span><span class="s2">"All AWS resources must have Name, Environment, and Owner tags."</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">enforcement_level</span><span class="o">=</span><span class="n">EnforcementLevel</span><span class="o">.</span><span class="n">MANDATORY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">validate</span><span class="o">=</span><span class="n">require_tags</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="n">ResourceValidationPolicy</span><span class="p">(</span>
</span></span><span class="line"><span class="cl"> <span class="n">name</span><span class="o">=</span><span class="s2">"no-public-s3"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">description</span><span class="o">=</span><span class="s2">"S3 buckets must not be publicly accessible via ACL."</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">enforcement_level</span><span class="o">=</span><span class="n">EnforcementLevel</span><span class="o">.</span><span class="n">MANDATORY</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="n">validate</span><span class="o">=</span><span class="n">no_public_s3</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="p">),</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">)</span>
</span></span>
<span class="line"><span class="cl"><span class="c1">// index.ts in your policy pack directory
</span></span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="o">*</span> <span class="kr">as</span> <span class="nx">aws</span> <span class="kr">from</span> <span class="s2">"@pulumi/aws"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl"><span class="kr">import</span> <span class="p">{</span> <span class="nx">PolicyPack</span><span class="p">,</span> <span class="nx">validateResourceOfType</span> <span class="p">}</span> <span class="kr">from</span> <span class="s2">"@pulumi/policy"</span><span class="p">;</span>
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="k">new</span> <span class="nx">PolicyPack</span><span class="p">(</span><span class="s2">"aws-security-baseline"</span><span class="p">,</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">policies</span><span class="o">:</span> <span class="p">[</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">name</span><span class="o">:</span> <span class="s2">"require-tags"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">description</span><span class="o">:</span> <span class="s2">"All EC2 instances must have Name, Environment, and Owner tags."</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">enforcementLevel</span><span class="o">:</span> <span class="s2">"mandatory"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">validateResource</span>: <span class="kt">validateResourceOfType</span><span class="p">(</span><span class="nx">aws</span><span class="p">.</span><span class="nx">ec2</span><span class="p">.</span><span class="nx">Instance</span><span class="p">,</span> <span class="p">(</span><span class="nx">instance</span><span class="p">,</span> <span class="nx">args</span><span class="p">,</span> <span class="nx">reportViolation</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">required</span> <span class="o">=</span> <span class="p">[</span><span class="s2">"Name"</span><span class="p">,</span> <span class="s2">"Environment"</span><span class="p">,</span> <span class="s2">"Owner"</span><span class="p">];</span>
</span></span><span class="line"><span class="cl"> <span class="kr">const</span> <span class="nx">tags</span> <span class="o">=</span> <span class="nx">instance</span><span class="p">.</span><span class="nx">tags</span> <span class="o">||</span> <span class="p">{};</span>
</span></span><span class="line"><span class="cl"> <span class="k">for</span> <span class="p">(</span><span class="kr">const</span> <span class="nx">tag</span> <span class="k">of</span> <span class="nx">required</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="o">!</span><span class="nx">tags</span><span class="p">[</span><span class="nx">tag</span><span class="p">])</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">reportViolation</span><span class="p">(</span><span class="sb">`Missing required tag: </span><span class="si">${</span><span class="nx">tag</span><span class="si">}</span><span class="sb">`</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}),</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">name</span><span class="o">:</span> <span class="s2">"no-public-s3"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">description</span><span class="o">:</span> <span class="s2">"S3 buckets must not have a public ACL."</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">enforcementLevel</span><span class="o">:</span> <span class="s2">"mandatory"</span><span class="p">,</span>
</span></span><span class="line"><span class="cl"> <span class="nx">validateResource</span>: <span class="kt">validateResourceOfType</span><span class="p">(</span><span class="nx">aws</span><span class="p">.</span><span class="nx">s3</span><span class="p">.</span><span class="nx">Bucket</span><span class="p">,</span> <span class="p">(</span><span class="nx">bucket</span><span class="p">,</span> <span class="nx">args</span><span class="p">,</span> <span class="nx">reportViolation</span><span class="p">)</span> <span class="o">=></span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="k">if</span> <span class="p">(</span><span class="nx">bucket</span><span class="p">.</span><span class="nx">acl</span> <span class="o">===</span> <span class="s2">"public-read"</span> <span class="o">||</span> <span class="nx">bucket</span><span class="p">.</span><span class="nx">acl</span> <span class="o">===</span> <span class="s2">"public-read-write"</span><span class="p">)</span> <span class="p">{</span>
</span></span><span class="line"><span class="cl"> <span class="nx">reportViolation</span><span class="p">(</span><span class="s2">"S3 bucket must not have a public ACL."</span><span class="p">);</span>
</span></span><span class="line"><span class="cl"> <span class="p">}</span>
</span></span><span class="line"><span class="cl"> <span class="p">}),</span>
</span></span><span class="line"><span class="cl"> <span class="p">},</span>
</span></span><span class="line"><span class="cl"> <span class="p">],</span>
</span></span><span class="line"><span class="cl"><span class="p">});</span>
</span></span>
Running a policy pack
<span class="line"><span class="cl"><span class="c1"># Scaffold a new policy pack from a template</span>
</span></span><span class="line"><span class="cl">mkdir my-policies <span class="o">&&</span> <span class="nb">cd</span> my-policies
</span></span><span class="line"><span class="cl">pulumi policy new aws-typescript
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Run policy checks against a stack</span>
</span></span><span class="line"><span class="cl">pulumi preview --policy-pack ./my-policies
</span></span><span class="line"><span class="cl">pulumi up --policy-pack ./my-policies
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Or publish to Pulumi Cloud and enforce organization-wide</span>
</span></span><span class="line"><span class="cl">pulumi policy publish
</span></span>
As Joe Duffy, Pulumi CEO, puts it: “The smartest agent in the world still needs guardrails, audit trails, and policy enforcement to be trusted with production systems at scale.”
Policy checks complement unit tests: unit tests verify your intent (“I wrote tags into this resource”), while policies enforce your standards (“all resources must have these tags, regardless of what any one developer intended”). For complex compliance environments, publish policies to Pulumi Cloud and assign them via policy groups to enforce them across the stacks or accounts you choose—including organization-wide.
How is testing IaC in Pulumi different from Terraform?
The fundamental difference is language cohesion. With Pulumi, you write infrastructure, tests, and policies all in the same general-purpose language. With Terraform, your infrastructure is HCL but your tests must be something else—either Go (Terratest) or a constrained HCL DSL (terraform test).
Pulumi
Terratest
terraform test (≥ 1.6)
Language for tests
Same language as infra (Python, TypeScript, Go, C#, Java); YAML programs tested via Automation API from any of those languages
Always Go (regardless of infra language)
HCL DSL (.tftest.hcl)
Unit tests with mocks
Yes — pulumi.runtime.set_mocks(), no cloud credentials needed
No — no mock layer for cloud providers
Limited — mock_provider (v1.7+) is HCL-declarative, no programmatic logic
Integration testing
Automation API (any language) or Go framework
Full-featured but Go-only
Yes, via command = apply run blocks
Policy / guardrails
Pulumi Policies: Python or TypeScript, runs at preview time
External tools (checkov, tfsec, OPA/Rego — separate toolchain)
Sentinel (enterprise) or external
Execution speed
Unit: milliseconds; integration: depends on cloud
Minutes (real deployments by default)
Plan-only: fast; apply: minutes
Learning curve
Use existing language skills and test frameworks
Requires Go knowledge and understanding of go test
Low if you know HCL; limited expressiveness
Terratest is battle-tested and widely adopted, particularly for Terraform module testing. It offers deep integrations with AWS, GCP, Azure, and Kubernetes. Its limitation is that it has no mock layer for cloud providers, so most test suites deploy real infrastructure, which makes them slower and costlier to run on every commit.
terraform test has improved significantly in Terraform 1.6 and 1.7. The command = plan mode avoids real deployments, and mock_provider enables basic unit-like testing. But expressiveness is bounded by HCL’s declarative model—no general-purpose programming, no third-party assertion libraries, and a fixed set of run/assert test constructs.
With Pulumi, there’s no context switch. The same developer who writes the infrastructure writes the tests in the same language, using the same IDE, the same debugger, and the same CI pipeline. That cohesion is a productivity multiplier.
How to set up IaC testing with Pulumi
Follow these steps to add a complete test suite to a Pulumi project. The examples use Python, but the pattern is identical in TypeScript, Go, C#, or Java.
{ "@context": "https://schema.org", "@type": "HowTo", "name": "How to Set Up IaC Testing with Pulumi", "description": "Add unit tests, integration tests, and policy checks to a Pulumi infrastructure project in seven steps.", "totalTime": "PT30M", "step": [ { "@type": "HowToStep", "name": "Install Pulumi and choose a language SDK", "text": "Install the Pulumi CLI and initialize a new project with your preferred language. Run 'pulumi new aws-python' (or aws-typescript, aws-go, etc.) to scaffold a project with the right SDK dependencies." }, { "@type": "HowToStep", "name": "Add a test framework", "text": "Add a language-native test runner: pytest for Python ('pip install pytest'), Mocha + ts-node for TypeScript ('npm install --save-dev mocha ts-node @types/mocha chai'), or the standard testing package for Go (built in)." }, { "@type": "HowToStep", "name": "Implement the Mocks class and set mocks before importing your program", "text": "Create a class that extends pulumi.runtime.Mocks (Python) or implements the setMocks interface (TypeScript). Override new_resource to return dummy IDs and pass-through state. Call pulumi.runtime.set_mocks() before importing your Pulumi program—this is the critical import-order rule." }, { "@type": "HowToStep", "name": "Write unit tests asserting resource properties", "text": "Write test functions that access stack outputs (infra.server.tags, infra.group.ingress) via pulumi.Output.all(...).apply(...). Assert security rules, required tags, naming conventions, and other properties. Decorate Python test methods with @pulumi.runtime.test; use done() callbacks in Mocha." }, { "@type": "HowToStep", "name": "Add integration tests using the Automation API with ephemeral stacks", "text": "Import pulumi.automation (Python) or @pulumi/pulumi/automation (TypeScript). Create an ephemeral stack with create_or_select_stack(), call stack.up() to deploy, run assertions against stack.outputs, then call stack.destroy() in a teardown fixture. Always destroy in a finally block to avoid leaked resources." }, { "@type": "HowToStep", "name": "Enforce guardrails with a Pulumi policy pack", "text": "Create a policy pack directory and run 'pulumi policy new aws-python' or 'pulumi policy new aws-typescript'. Define ResourceValidationPolicy rules for your compliance requirements. Use EnforcementLevel.MANDATORY to block non-compliant deployments. Run 'pulumi preview --policy-pack ./my-policies' to enforce locally, or publish to Pulumi Cloud for org-wide enforcement." }, { "@type": "HowToStep", "name": "Run all tests in CI on every pull request", "text": "Add unit tests to your standard CI job (no cloud credentials needed). Add integration tests in a separate CI stage with cloud credentials, using a dedicated test account. Reference the Pulumi GitHub Actions integration or any CI provider—unit tests run on every PR commit; integration tests run on merge to main or on a schedule." } ] }
Step 1: Install Pulumi and choose a language SDK
<span class="line"><span class="cl"><span class="c1"># Install Pulumi CLI</span>
</span></span><span class="line"><span class="cl">curl -fsSL https://get.pulumi.com <span class="p">|</span> sh
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Create a new project (or use an existing one)</span>
</span></span><span class="line"><span class="cl">pulumi new aws-python --name my-project --stack dev
</span></span>
Step 2: Add a test framework
<span class="line"><span class="cl"><span class="c1"># Python</span>
</span></span><span class="line"><span class="cl">pip install pytest pytest-asyncio
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># TypeScript</span>
</span></span><span class="line"><span class="cl">npm install --save-dev mocha ts-node @types/mocha chai @types/chai
</span></span><span class="line"><span class="cl">
</span></span><span class="line"><span class="cl"><span class="c1"># Go uses the built-in testing package — no additional dependencies</span>
</span></span>
Step 3: Implement the Mocks class
Create mocks.py (or equivalent) with your Mocks subclass. Keep it simple for unit tests: return [args.name + "_id", args.inputs] from new_resource.
Step 4: Write unit tests
Create test_infra.py in your project root. Import mocks first, then your program. Write test functions that use @pulumi.runtime.test and pulumi.Output.all(...).apply(...) to assert resource properties.
Step 5: Add integration tests
Create test_integration.py with a pytest fixture that creates a stack, calls stack.up(), yields outputs for assertions, and calls stack.destroy() in teardown. Point this at a dedicated test cloud account.
Step 6: Create a policy pack
<span class="line"><span class="cl">mkdir policies <span class="o">&&</span> <span class="nb">cd</span> policies
</span></span><span class="line"><span class="cl">pulumi policy new aws-python
</span></span><span class="line"><span class="cl"><span class="c1"># Edit __main__.py to add your rules</span>
</span></span>
Step 7: Wire it all into CI
<span class="line"><span class="cl"><span class="c"># .github/workflows/test.yml (GitHub Actions excerpt)</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="nt">jobs</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">unit-tests</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">pulumi/actions@v6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pip install -r requirements.txt</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">python -m pytest tests/unit/ -v</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">integration-tests</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">runs-on</span><span class="p">:</span><span class="w"> </span><span class="l">ubuntu-latest</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">needs</span><span class="p">:</span><span class="w"> </span><span class="l">unit-tests</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">environment</span><span class="p">:</span><span class="w"> </span><span class="l">staging</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">steps</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">actions/checkout@v4</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">uses</span><span class="p">:</span><span class="w"> </span><span class="l">pulumi/actions@v6</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">pip install -r requirements.txt</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span>- <span class="nt">env</span><span class="p">:</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">PULUMI_ACCESS_TOKEN</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.PULUMI_ACCESS_TOKEN }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">AWS_ACCESS_KEY_ID</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.AWS_ACCESS_KEY_ID }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">AWS_SECRET_ACCESS_KEY</span><span class="p">:</span><span class="w"> </span><span class="l">${{ secrets.AWS_SECRET_ACCESS_KEY }}</span><span class="w">
</span></span></span><span class="line"><span class="cl"><span class="w"> </span><span class="nt">run</span><span class="p">:</span><span class="w"> </span><span class="l">python -m pytest tests/integration/ -v --timeout=300</span><span class="w">
</span></span></span>
Frequently asked questions
What is infrastructure as code testing?
Infrastructure as code testing is the practice of writing automated checks that validate your IaC programs before they deploy to production. Just like application testing, it includes unit tests (fast, no cloud credentials, mock the provider), integration tests (real cloud deployments in ephemeral environments), and policy checks (rules that enforce compliance standards on every preview and deploy).
Can you unit test IaC without deploying to the cloud?
Yes. Pulumi’s mocking framework intercepts all cloud API calls and replaces them with in-process stubs. Unit tests run entirely in memory—no cloud credentials, no network calls, no cost. A suite of 50 unit tests runs in under a second. This is the primary reason to write unit tests: fast, free, deterministic feedback on every commit.
Do you need real cloud credentials to test Pulumi?
Only for integration tests. Unit tests use Pulumi’s mock runtime and require no cloud credentials at all. Policy checks also run without credentials at pulumi preview time. Integration tests that use the Automation API do need credentials—they deploy real resources—so they’re typically run in a CI stage with access to a dedicated test account, not on every PR.
What’s the difference between unit and integration tests for IaC?
Unit tests validate resource properties, configurations, and relationships using mocked cloud providers—they run in milliseconds with no cloud credentials. Integration tests deploy actual resources to a real cloud environment, validate runtime behavior (does the endpoint respond? does the database accept connections?), and then destroy everything. Unit tests are cheap and frequent; integration tests are slower, cost real cloud spend, and run less often.
How do you mock cloud resources in Pulumi?
Implement pulumi.runtime.Mocks (Python) or call pulumi.runtime.setMocks() (TypeScript/JavaScript) before importing your Pulumi program. The new_resource method receives every resource registration and returns a fake [id, state] pair. The call method handles data-source lookups. Set mocks with pulumi.runtime.set_mocks(MyMocks()) and then import your program—the runtime will route all resource registrations through your mock instead of making real API calls.
What test frameworks work with Pulumi?
Any language-native test framework works. For Python: pytest (recommended) or unittest. For TypeScript/JavaScript: Mocha, Jest, or Vitest. For Go: the standard testing package. For C#: NUnit or xUnit. For Java: JUnit. The @pulumi/pulumi/automation SDK and pulumi.automation module integrate naturally with all of them. YAML is Pulumi’s declarative configuration language; because it has no control flow or executable statements, you cannot write test logic in YAML itself. YAML programs are tested by pointing the Automation API from Python, TypeScript, Go, C#, or Java at the project directory and asserting on the stack outputs.
How do you test Pulumi in CI/CD?
Split your test suite into two CI stages. Stage 1 (unit tests): runs on every PR commit, no cloud credentials required, fast. Stage 2 (integration tests): runs on merge to main or on a schedule, requires cloud credentials for a dedicated test account, uses the Automation API to deploy ephemeral stacks. The Pulumi GitHub Actions integration simplifies credential injection and stack management in both stages.
Is policy as code the same as testing?
Policy as code is complementary to—but distinct from—testing. Tests validate what your program produces (resource A has property B); policies enforce what your resources must conform to (all resources must have tag X). Policies run automatically at preview time and block non-compliant deployments at deploy time. Together, they create defense in depth: tests verify intent, policies enforce standards regardless of intent.
How is Pulumi testing different from Terratest?
Terratest typically deploys real infrastructure—it has no mock layer for cloud providers—so most test runs provision actual cloud resources, incurring real cost and taking 5–30 minutes. Tests must be written in Go regardless of what language your infrastructure uses. Pulumi’s unit testing framework runs in milliseconds with no cloud credentials, uses your existing language and test runner, and provides true mock isolation. For integration testing, Pulumi’s Automation API offers a similar model to Terratest but in any language.
How do you tear down resources after integration tests?
In Python pytest, use a module-scoped fixture that yields after stack.up() and calls stack.destroy() in the teardown. In TypeScript Mocha, call stack.destroy() in an after() hook. In Go, use defer stack.Destroy(ctx, ...). Always use a try/finally pattern (or equivalent in your language) so teardown runs even when a test assertion fails. Pulumi Cloud also has built-in stack TTL and auto-destroy features for extra safety.
Where to go next
Testing IaC is not an all-or-nothing investment. Start by adding a handful of unit tests to your most critical stack—the one that manages your production VPC, your IAM roles, or your data infrastructure. Pick three to five properties that, if wrong, would cause an outage or a security incident. Write tests for those. Run them in CI. Expand from there.
When you’re ready to go deeper:
- Testing overview — Pulumi’s full testing documentation
- Unit testing guide — detailed mock API reference with Go and C# examples
- Automation API integration testing — advanced patterns (multi-stack tests, config injection, parallel test execution)
- Policy as code authoring — writing and publishing Pulumi Policies
- Pulumi vs. Terraform — a full comparison of the two platforms
If you’re migrating from Terraform, the Pulumi conversion tool translates your existing HCL to Python, TypeScript, Go, C#, and more, including your test infrastructure. Your Terratest or terraform test suites can be ported to Pulumi’s native test runner—using your existing language—as part of the migration.
Fetched July 2, 2026




