https://pulumi.com logo
#typescript
Title
# typescript
l

little-cartoon-10569

05/13/2021, 1:59 AM
I'm unit testing (mocha+pulumi.runtime.setMocks()) and getting an error aynchronously. The offending test is passing, and about 4 or 5 tests later, another test fails with an error obviously caused by my changed suite.
I suspect that it has something to do with mixins, as I'm working on EventRuleEventSubscription resources (that @faint-table-42725 helped with yesterday).
The error is:
Copy code
Uncaught Error: unknown resource urn:pulumi:stack::project::aws:lambda/function:Function$aws:cloudwatch:EventRuleEventSubscription::filtering-ec2-start
      at MockMonitor.registerResourceOutputs (node_modules/@pulumi/pulumi/runtime/mocks.js:125:23)
      at /pulumi/projects/node_modules/@pulumi/pulumi/runtime/resource.js:615:91
      at new Promise (<anonymous>)
      at Object.<anonymous> (node_modules/@pulumi/pulumi/runtime/resource.js:615:50)
      at Generator.next (<anonymous>)
      at fulfilled (node_modules/@pulumi/pulumi/runtime/resource.js:18:58)
I've recently upgraded to Pulumi 3.2.1 from 2.24.1, so there's changes in my setMocks code (I now use MockResourceArgs and MockCallArgs), so that may be relevant.
The resource involved is created thus (abbreviated):
Copy code
const role = new aws.iam.Role( ... );
const policy = new aws.iam.Policy( ... );
new aws.iam.RolePolicyAttachment( ... );
const rule = new aws.cloudwatch.EventRule( ... );
const handler = new aws.lambda.CallbackFunction<aws.cloudwatch.EventRuleEvent, void>(name,
  role: role,
  callback: async (_: aws.cloudwatch.EventRuleEvent) => {
    ...
  }
}, opts);
const subscription = new aws.cloudwatch.EventRuleEventSubscription(name, rule, handler, {}, otherOpts);
My newResource function is this:
Copy code
function (args: pulumi.runtime.MockResourceArgs): { id: string, state: Record<string, any> } {
        let state = {
          ...args.inputs,
          id: `${args.inputs.name ?? args.name}_id`,
          name: args.inputs.name ?? args.name,
        };

        return {
          id: state.id,
          state: state,
        };
      }
Afaict, the "unknown resource" error is coming from mocks.ts#registerResourceOutputs. Under what circumstances can
this.resources.get(req.getUrn())
return a falsey value?
All I can think of is that the logic in
req.getUrn()
doesn't match the logic used to compose the urn in the resource constructor?
I see two different logics used for composing URNs: mocks.ts has
newUrn
, and resource.js has
createUrn
.
I don't know how to prove that either or both of them produce urnpulumistack:projectawslambda/function:Function$awscloudwatchEventRuleEventSubscription::filtering-ec2-start in my case.
Experiment: changed the async callback to be a no-op sync callback, and no change.
I best-effort followed through the logic in newUrn and createUrn. Couldn't figure out how to get the debugger to stop in those places, it's all too async for me 🙂 newUrn produces the URN in the error message, which includes the pulumiType of just the parent and resource. According to my fumbling logic, createUrn produces a URN with the grandparent (and any other ancestors) in it too, e.g.:
urn:pulumi.stack::project::aws:cloudwatch/eventRule:EventRule$aws:lambda/function:Function$aws:cloudwatch:EventRuleEventSubscription::filtering-ec2-start
It looks like createUrn matches what I see in my real stack. So maybe there's a bug in mocks.ts#newUrn, on this line:
const parentType = qualifiedType.split("$").pop();
That seems to preclude the possibility of having a parent graph depth greater than 2....
I removed the parent of the CallbackFunction and EventRuleEventScheduler, and the "unknown resource" error went away, so it seems like that analysis has a chance of being right...
However I got a nameless "Uncaught" error in the same place when I did that, so I'm not out of the woods yet.
Looks like the nameless uncaught error is due to
utils.withAlias()
. The resource-faking code can't handle aliases...
And there's no way to set them to empty in the EventRuleEventSubscription constructor.
No way to break the parenting code in that constructor, either.