question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

[dotnet] Unit tests with Helm.V3.Chart throw NullReferenceException

See original GitHub issue

I’m trying to write some unit tests in C# for my stacks and I’m having trouble with a stack which contains a Helm.V3.Chart. Running unit tests which utilize charts currently throw System.NullReferenceException.

Expected behavior

Unit tests execute without exceptions.

Current behavior

The following exception is thrown when executing a unit test with a stack containing Helm.V3.Chart.

   Pulumi.RunException : Running program '<path>\bin\Debug\net5.0\testhost.dll' failed with an unhandled exception:
System.NullReferenceException: Object reference not set to an instance of an object.
   at System.Collections.Immutable.ImmutableArray.CreateRange[TSource,TResult](ImmutableArray`1 items, Func`2 selector)
   at Pulumi.Extensions.SelectAsArray[TItem,TResult](ImmutableArray`1 items, Func`2 map)
   at Pulumi.InputList`1.op_Implicit(ImmutableArray`1 values)
   at Pulumi.Kubernetes.Helm.V3.Chart.<>c__DisplayClass3_0.<ParseTemplate>b__0(ImmutableArray`1 objs)
   at Pulumi.Output`1.ApplyHelperAsync[U](Task`1 dataTask, Func`2 func)
   at Pulumi.Output`1.ApplyHelperAsync[U](Task`1 dataTask, Func`2 func)
   at Pulumi.Output`1.Pulumi.IOutput.GetDataAsync()
   at Pulumi.Serialization.Serializer.SerializeAsync(String ctx, Object prop, Boolean keepResources)
   at Pulumi.Deployment.SerializeFilteredPropertiesAsync(String label, IDictionary`2 args, Predicate`1 acceptKey, Boolean keepResources)
   at Pulumi.Deployment.SerializeAllPropertiesAsync(String label, IDictionary`2 args, Boolean keepResources)
   at Pulumi.Deployment.RegisterResourceOutputsAsync(Resource resource, Output`1 outputs)
   at Pulumi.Deployment.Runner.<>c__DisplayClass9_0.<<WhileRunningAsync>g__HandleCompletion|0>d.MoveNext()
--- End of stack trace from previous location ---
   at Pulumi.Deployment.Runner.WhileRunningAsync()
    Stack Trace:
       at Pulumi.Deployment.TestAsync(IMocks mocks, Func`2 runAsync, TestOptions options)
    <snip>
--- End of stack trace from previous location ---

I did some digging and found that the trouble is caused by the implicit conversion operator invoked at https://github.com/pulumi/pulumi-kubernetes/blob/80d4c16c2240d77ca575273a9c167c739e7681a3/sdk/dotnet/Helm/V3/Chart.cs#L365

The actual problem seems to be that the ImmutableArray-parameter https://github.com/pulumi/pulumi-kubernetes/blob/80d4c16c2240d77ca575273a9c167c739e7681a3/sdk/dotnet/Helm/V3/Invokes.cs#L46 given to HelmTemplateResult is uninitialized when running the tests. Since the ImmutableArray is uninitialized, the System.NullReferenceException is thrown when trying to do the implicit conversion.

Steps to reproduce

The problem can be produced by having the following stack:

public class FailingHelmStack : Pulumi.Stack
{
    public FailingHelmStack()
    {
        var chart = new Pulumi.Kubernetes.Helm.V3.Chart("chart"
            , new Pulumi.Kubernetes.Helm.ChartArgs()
            {
                Chart = "ingress-nginx",
                Namespace = "kube-system",
                FetchOptions = new Pulumi.Kubernetes.Helm.ChartFetchArgs
                {
                    Repo = "https://kubernetes.github.io/ingress-nginx",
                },
            });
    }
}

And invoking it with Deployment.TestAsync in a C# test project.

Context (Environment)

Trying to write unit tests for stacks which contain Helm-charts.

Proposed fix

Ensure that the HelmTemplateResult.Result array is always initialized.

~~For example by adding the following to HelmTemplateResult constructor https://github.com/pulumi/pulumi-kubernetes/blob/80d4c16c2240d77ca575273a9c167c739e7681a3/sdk/dotnet/Helm/V3/Invokes.cs#L48~~

Result = result;
// Ensure the Result array is always initialized
if (Result.IsDefault)
{
    Result = ImmutableArray<ImmutableDictionary<string, object>>.Empty;
}

If this seems like a reasonable solution, I can submit a PR.

NOTE I am not sure if similiar problem occurs anywhere else with ImmutableArray

UPDATE The implicit conversion fix is in pulumi/pulumi#6544

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Comments:9 (5 by maintainers)

github_iconTop GitHub Comments

1reaction
t0yv0commented, Mar 18, 2021

I have a workaround for your unit test that makes it pass for me:

https://github.com/vipentti/pulumi-helm-chart-unittest-issue/pull/1

At a high level, what I think is happening, the Mock implementation you were using was violating some assumptions of how kubernetes:helm:template resource responds. I could only find this by perusing the provider.go source code in pulumi-kubernetes… but it seems like a “result” property is populated with output to decodeYaml, which has this:

// decodeYaml parses a YAML string, and then returns a slice of untyped structs that can be marshalled into
// Pulumi RPC calls. If a default namespace is specified, set that on the relevant decoded objects.

So mocking the helm resources deeply and accurately sounds like something off the beaten path. I am a bit new to Pulumi and will ask around if there is a better way. Please let me know if my PR unblocks you to get to something sufficiently useful, or you run into more roadblocks trying to mock the Helm provider?

Considering changes to pulumi-kubernetes. Technically with the original shallow mock, this is what’s happening:

V3/Chart.cs calls Invokes.HelmTemplate(..)
which calls Deployement.Instance.InvokeAsync<HelmTemplateResult>("kubernetes:helm:template", .., ..) 
which calls  internal interface IDeployment { Task<T> InvokeAsync(..) } 
which returns null
which gets wrapped in HelmTemplateResult and continues downstream

So we could consider HelmTemplateResult normalizing null to empty ImmutableArray. It is clear though this only affects the scenario of testing with incomplete mocks, and I am wondering if this would actually unblock some useful testing?

1reaction
vipentticommented, Mar 17, 2021

@t0yv0 I’ve created a small repo which displays the problem https://github.com/vipentti/pulumi-helm-chart-unittest-issue

Read more comments on GitHub >

github_iconTop Results From Across the Web

ASP.NET Core unit test throws Null Exception when ...
For some reason, I keep getting a NullReferenceException when testing that I get a ControllerBase.Problem(String, String, Nullable<Int32>, ...
Read more >
Fork of lrills/helm-unittest but for Helm 3
It will install the latest version of binary into helm plugin directory. Get Started. Add tests in .helmignore of your chart, and create...
Read more >
Yes, you can unit test Helm Charts
I have found creating Helm charts a challenge as it's difficult to test as a chart gets more complex. Linting, packaging, etc. all...
Read more >
Chart Tests
A test in a helm chart lives under the templates/ directory and is a job definition that specifies a container with a given...
Read more >
Azure PowerShell release notes
Fixed 'New-AzVM' cmdlet when creating VM with bootdiagnostic storage causes exception 'Kind' cannot be null. Az.CosmosDB. Added support for ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found