ConfigPlanChecks PreApply

Hi,

I am currently stuck with the usage of pre-apply plan checks with terraform-plugin-testing and was wondering if anybody could point me in a correct direction.

In our resource we are adding a resource ModifyPlan() to populate the id already during plan phase when a resource needs to be created. The reason for this is because the id refers to a specific naming of the object to be managed which is useful to know for users during plan for other external validation use-cases.

When executing the plan, it correctly displays my desired output in cli and json plan output.
See example (generalised the example) of how the output would look with the constructed id from the required attribute input.

Terraform will perform the following actions:

  # resource_name.test_2 will be created
  + resource "resource_name" "test_2" {
      + id        = "some-value-[test_key]"
      + key       = "test_key"
    }

All my current tests are still functioning as expected and the next thing I wanted to add is test validations for the id being set during plan. From reading the documentation my expectation was to use the ConfigPlanChecks - PreApply in my tests. See example below:

ConfigPlanChecks: resource.ConfigPlanChecks{
  PreApply: []plancheck.PlanCheck{
    plancheck.ExpectKnownValue(
      "resource_name.test_2",
      tfjsonpath.New("id"),
      knownvalue.NotNull(),
    ),
  },
},

But this results in the following error:

Step 1/1 error: Pre-apply plan check(s) failed:
        path not found: specified key id not found in map at id

To me this seems that tfjsonpath cannot find the “id” attribute and is throwing an error. If I set tfjsonpath.New("test_key") it seems to be working as expected (assuming my understanding of the usage is correct).

Is there a way to test that the “id” attribute is being populated in plan?

Hi @akinross,

Sorry that you’re running into trouble here. From what you’ve provided here, the plan check test assertion look correct. I tried to replicate the issue on my end with this setup:

func (r *ExampleResource) ModifyPlan(ctx context.Context, req resource.ModifyPlanRequest, resp *resource.ModifyPlanResponse) {  
    var data *ExampleResourceModel  
  
    resp.Diagnostics.Append(req.Plan.Get(ctx, &data)...)  
  
    strAttribute := data.StringAttribute.ValueString()  
  
    data.Id = types.StringValue("test-string-" + strAttribute)  
  
    if resp.Diagnostics.HasError() {  
       return  
    }  
      
    resp.Diagnostics.Append(resp.Plan.Set(ctx, &data)...)  
}

And in the test:

Steps: []resource.TestStep{  
    {  
       Config: `resource "scaffolding_example" "one" {  
       string_attribute = "attrvalue"    
       }`,  
       ConfigPlanChecks: resource.ConfigPlanChecks{  
          PreApply: []plancheck.PlanCheck{  
             plancheck.ExpectKnownValue(  
                "scaffolding_example.one",  
                tfjsonpath.New("id"),  
                knownvalue.StringExact("test-string-attrvalue"),  
             ),  
          },  
       },  
    },  
},

And the test above passes for me. One reason why you might be seeing this error is that the id attribute is Unknown in the plan. You can check this by replacing your test assertion with:

plancheck.ExpectUnknownValue(  
    "resource_name.test_2",  
    tfjsonpath.New("id"),  
),

If the above test passes, then it’s likely that there’s something going on in your ModifyPlan() that’s not populating the id attribute correctly.

Hi @SBGoods,

Thank you for the reply and apologies for my late response.

I had a check and indeed the test with ExpectUnknownValue passes, which I find strange due to the plan output being constructed correctly.

I will have a deeper look at what is happening when I have some more time available. When I find what is happening I will update the thread.