Skip to content
New issue

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

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

Already on GitHub? Sign in to your account

Introduce provider upgrade tests #2714

Merged
merged 51 commits into from
Sep 1, 2023
Merged

Introduce provider upgrade tests #2714

merged 51 commits into from
Sep 1, 2023

Conversation

t0yv0
Copy link
Member

@t0yv0 t0yv0 commented Aug 25, 2023

Partially fixes #2719

This PR adds coverage for testing provider upgrades from a baseline version (currently 5.42.0) to the in-source release candidate. The tests check that there are no upgrade or replace plans when upgrading the provider. This is verified on a few select resources.

Currently tested resources include:

  • aws:ec2/subnet:Subnet
  • aws:ec2/vpc:Vpc
  • aws:ec2:SecurityGroup
  • aws:eks:Cluster
  • aws:iam:Role
  • aws:iam:RolePolicyAttachment
  • aws:rds/instance:Instance
  • aws:route53:ResolverEndpoint
  • aws:s3/bucket:Bucket

The test relies on recording and replaying the behavior of the baseline version. There are two versions of the test, in-memory TestProviderUpgradeQuick version and full acceptance-style TestProviderUpgrade version. Full version is skipped for the moment with references to discovered issues.

@t0yv0 t0yv0 requested a review from iwahbe August 25, 2023 13:38
@github-actions
Copy link

github-actions bot commented Aug 25, 2023

Does the PR have any schema changes?

Does the PR have any schema changes?

Looking good! No breaking changes found.
No new resources/functions.

Maintainer note: consult the runbook for dealing with any breaking changes.

@t0yv0
Copy link
Member Author

t0yv0 commented Aug 25, 2023

@iwahbe I've pondered sequencing here and I think if there's ongoing work to bring AWS repo under ci-mgmt perhaps this PR is not a good time to split examples and tests.

I don't think we were tracking this before so here's a new issue:

pulumi/ci-mgmt#526

Once pulumi-aws is under ci-mgmt we can roll out examples/tests split everywhere including here, then move tests around.

Makefile Show resolved Hide resolved
@t0yv0
Copy link
Member Author

t0yv0 commented Aug 25, 2023

Let me confirm but I also think this is self-sufficient for recording v5 provider; the baseline version is currently written in the Pulumi.yaml Program file. So if doing something like adding example resources we should be able to re-record this baseline version from the main branch without having to checkout some earlier branch.

examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
}

if isPureMethod(t, line) {
line = ignoreStables(t, line)
Copy link
Member

Choose a reason for hiding this comment

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

This is fine for now, but we should remember to make stables stable and then remove this, since this field is effectively no longer under test.

Comment on lines +87 to +88
ambientProvider, _ := exec.LookPath(providerBinary)
require.Emptyf(t, ambientProvider, "please remove the provider from PATH")
Copy link
Member

Choose a reason for hiding this comment

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

Instead of this, can we just set PULUMI_IGNORE_AMBIENT_PLUGINS=true? It should accomplish the same thing without requiring destructive user action.

Copy link
Member Author

Choose a reason for hiding this comment

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

Hmm. Not sure, I prefer this I think to fail loudly. Perhaps if we went PULUMI_IGNORE_AMBIENT_PLUGINS way I'd like another check to fail loudly if baseline recording is not on the expected version.

examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
info := providerUpgradeInfo{}
info.testCaseDir = filepath.Join("testdata", "resources")
pyaml := filepath.Join(info.testCaseDir, "Pulumi.yaml")
v := parseProviderVersion(t, pyaml)
Copy link
Member

Choose a reason for hiding this comment

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

We will eventually want to provision multiple providers. The obvious example is lots of tags configurations. We can leave it for now and revisit.

Copy link
Member Author

Choose a reason for hiding this comment

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

I'd leave it, I'm not sure how to avoid copy-pasting resource configurations, perhaps we can parameterize the stacks somehow or resort to YAML munging. We might also need to break down this single stack into N stacks. I'd like to check in a reasonably working first version before making those extensions though.

Comment on lines 194 to 196
pt.RunPulumiCommand("stack", "export", "--file", newStateFile)
stackName := parseStackName(t, readFile(t, newStateFile))
fixedState := withUpdatedStackName(t, stackName, readFile(t, stateFile))
Copy link
Member

Choose a reason for hiding this comment

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

We read the new state file twice, and write it once. Can we do this?

Suggested change
pt.RunPulumiCommand("stack", "export", "--file", newStateFile)
stackName := parseStackName(t, readFile(t, newStateFile))
fixedState := withUpdatedStackName(t, stackName, readFile(t, stateFile))
pt.RunPulumiCommand("stack", "export", "--file", newStateFile)
newStateFileBytes := readFile(t, newStateFile)
stackName := parseStackName(t, newStateFileBytes)
fixedState := withUpdatedStackName(t, stackName, newStateFileBytes)

Copy link
Member Author

Choose a reason for hiding this comment

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

Well no, I think in fact this would invalidate the test.. We want to read the pre-recorded stateFile (from stateFile variable). We're only reading the newStateFile as a workaround to determine currently allocated stack's name. I can factor it out into a function to make more obvious.

examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
@t0yv0 t0yv0 mentioned this pull request Aug 25, 2023
12 tasks
@t0yv0 t0yv0 changed the title Introduce provider upgrade tests for the V6 RC branch Introduce provider upgrade tests Aug 28, 2023
@t0yv0 t0yv0 requested review from iwahbe, a team and mikhailshilkov August 28, 2023 16:48
@t0yv0 t0yv0 marked this pull request as ready for review August 28, 2023 16:50
Copy link
Member

@mjeffryes mjeffryes left a comment

Choose a reason for hiding this comment

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

I have many comments and questions, but nothing blocking. This seems like a useful tool, and something where we can safely land it and continue to improve

Makefile Outdated

# Runs integration tests on the baseline version and updates testdata to record expected behavior.
test.upgrade.record::
cd examples && PULUMI_ACCEPT=true go test -v -tags all -run TestProviderUpgradeRecord -timeout 2h
Copy link
Member

Choose a reason for hiding this comment

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

The Makefile feels like a non-ideal place to define a 2hr timeout. I would expect to define a timeout in the workflow for a CI job or just rely on the user for a timeout when running locally?

Copy link
Member Author

Choose a reason for hiding this comment

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

This is the state of the art in the Makefile already :) Just following existing practice.

)

const (
acceptEnvVar = "PULUMI_ACCEPT"
Copy link
Member

Choose a reason for hiding this comment

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

The name of this variable is pretty generic for something that just toggles between record and compare modes.

Copy link
Member

Choose a reason for hiding this comment

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

The name is consistent with similar tests in pulumi/pulumi and pulumi/pulumi-{yaml, java}.

Copy link
Member Author

Choose a reason for hiding this comment

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

https://github.com/hexops/autogold defines custom -update flag which is an interesting approach we could use too. I'm just indeed opting for consistency with pulumi/pulumi where we use this strange PULUMI_ACCEPT var.

Comment on lines 76 to 79
func TestProviderUpgradeRecord(t *testing.T) {
if !accept {
t.Skipf("Skipping; to record baselines set %s env var to true", acceptEnvVar)
}
Copy link
Member

Choose a reason for hiding this comment

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

I wonder if this should just be a separate binary rather than a test? I can see how writing it as a test makes it easier to get a testing.T for integration.ProgramTest(t, &test) below, but it also means you have to have the extra env var to keep it from running most of the time. If it's not a huge amount of work to just make it run as a separate command, that could be a bit easier to maintain in the long term.

Copy link
Member

Choose a reason for hiding this comment

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

We normally have this in a single test, that is always run in either a "record" or "replay" mode. We might want to do that here, since TestProviderUpgradeQuick and TestProviderUpgradeRecord interact via the file system.

Since it never makes sense to run both tests in 1 go, we might want to merge them here as well.

Copy link
Member Author

Choose a reason for hiding this comment

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

Edited for it to sit in a single test. I do think refreshing belongs in the test world and not a separate binary, more idiomatic Go it seems, see https://github.com/hexops/autogold again.

examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
examples/provider_upgrade_test.go Outdated Show resolved Hide resolved

func providerServer(t *testing.T) pulumirpc.ResourceProviderServer {
ctx := context.Background()
version.Version = "0.0.1"
Copy link
Member

Choose a reason for hiding this comment

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

probably just a go n00b type question, but I don't see where version is defined, or understand why you're setting it here?

Copy link
Member

Choose a reason for hiding this comment

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

version.Version is a global variable, normally set by the linker. We set it here because we expect that version.Version is valid semver (which "" is not).

Copy link
Member

@iwahbe iwahbe left a comment

Choose a reason for hiding this comment

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

I think we can merge as is, and this will provider a useful backstop.

In the future, I think we should talk about the test structure. In particular, I don't understand why we have 3 test functions (with separate code) when I can only remember us wanting two tests.

Before we merge this PR, I would like all 3 tests to have a doc comment explaining what they are doing and how to run them (PULUMI_ACCEPT, etc.).

Comment on lines 76 to 79
func TestProviderUpgradeRecord(t *testing.T) {
if !accept {
t.Skipf("Skipping; to record baselines set %s env var to true", acceptEnvVar)
}
Copy link
Member

Choose a reason for hiding this comment

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

We normally have this in a single test, that is always run in either a "record" or "replay" mode. We might want to do that here, since TestProviderUpgradeQuick and TestProviderUpgradeRecord interact via the file system.

Since it never makes sense to run both tests in 1 go, we might want to merge them here as well.

examples/provider_upgrade_test.go Outdated Show resolved Hide resolved
@t0yv0 t0yv0 merged commit 8e8d685 into master Sep 1, 2023
15 checks passed
@t0yv0 t0yv0 deleted the t0yv0/upgrade-tests-v6 branch September 1, 2023 00:56
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Provider Upgrade Testing
3 participants