示例#1
0
        /// <summary>
        /// Entry point to test a Pulumi application. Deployment will
        /// instantiate a new stack instance based on the type passed as TStack
        /// type parameter. This method creates no real resources.
        /// Note: Currently, unit tests that call <see cref="TestAsync{TStack}"/>
        /// must run serially; parallel execution is not supported.
        /// </summary>
        /// <param name="mocks">Hooks to mock the engine calls.</param>
        /// <param name="options">Optional settings for the test run.</param>
        /// <typeparam name="TStack">The type of the stack to test.</typeparam>
        /// <returns>Test result containing created resources and errors, if any.</returns>
        public static async Task <ImmutableArray <Resource> > TestAsync <TStack>(IMocks mocks, TestOptions?options = null) where TStack : Stack, new()
        {
            var        engine  = new MockEngine();
            var        monitor = new MockMonitor(mocks);
            Deployment deployment;

            lock (_instanceLock)
            {
                if (_instance != null)
                {
                    throw new NotSupportedException($"Multiple executions of {nameof(TestAsync)} must run serially. Please configure your unit test suite to run tests one-by-one.");
                }

                deployment = new Deployment(engine, monitor, options);
                Instance   = new DeploymentInstance(deployment);
            }

            try
            {
                await deployment._runner.RunAsync <TStack>();

                return(engine.Errors.Count switch
                {
                    1 => throw new RunException(engine.Errors.Single()),
                    int v when v > 1 => throw new AggregateException(engine.Errors.Select(e => new RunException(e))),
                    _ => monitor.Resources.ToImmutableArray()
                });
            }
示例#2
0
        // this method *must* remain marked async
        // in order to protect the scope of the AsyncLocal Deployment.Instance we cannot elide the task (return it early)
        // if the task is returned early and not awaited, than it is possible for any code that runs before the eventual await
        // to be executed synchronously and thus have multiple calls to one of the Run methods affecting each others Deployment.Instance
        internal static async Task <int> CreateRunnerAndRunAsync(
            Func <Deployment> deploymentFactory,
            Func <IRunner, Task <int> > runAsync)
        {
            var deployment = deploymentFactory();

            Instance = new DeploymentInstance(deployment);
            return(await runAsync(deployment._runner).ConfigureAwait(false));
        }