@@ -18,6 +18,7 @@ import {
18
18
ParamsSource ,
19
19
resolveBuildFlags ,
20
20
runBuild ,
21
+ SamBuildResult ,
21
22
} from '../../../shared/sam/build'
22
23
import { TreeNode } from '../../../shared/treeview/resourceTreeDataProvider'
23
24
import { createWizardTester } from '../wizards/wizardTestUtils'
@@ -34,6 +35,7 @@ import { samconfigCompleteData, validTemplateData } from './samTestUtils'
34
35
import { CloudFormationTemplateRegistry } from '../../../shared/fs/templateRegistry'
35
36
import { getTestWindow } from '../vscode/window'
36
37
import { CancellationError } from '../../../shared/utilities/timeoutUtils'
38
+ import { SamAppLocation } from '../../../awsService/appBuilder/explorer/samProject'
37
39
import { SemVer } from 'semver'
38
40
39
41
describe ( 'SAM BuildWizard' , async function ( ) {
@@ -423,22 +425,8 @@ describe('SAM runBuild', () => {
423
425
verifyCorrectDependencyCall ( )
424
426
} )
425
427
426
- it ( '[entry: appbuilder node] with default flags should instantiate correct process in terminal' , async ( ) => {
427
- const prompterTester = PrompterTester . init ( )
428
- . handleQuickPick ( 'Specify parameter source for build' , async ( quickPick ) => {
429
- // Need sometime to wait for the template to search for template file
430
- await quickPick . untilReady ( )
431
-
432
- assert . strictEqual ( quickPick . items . length , 2 )
433
- const items = quickPick . items
434
- assert . strictEqual ( quickPick . items . length , 2 )
435
- assert . deepStrictEqual ( items [ 0 ] , { data : ParamsSource . Specify , label : 'Specify build flags' } )
436
- assert . deepStrictEqual ( items [ 1 ] . label , 'Use default values' )
437
- quickPick . acceptItem ( quickPick . items [ 1 ] )
438
- } )
439
- . build ( )
440
-
441
- // Invoke sync command from command palette
428
+ it ( '[entry: appbuilder node] with default flags should instantiate correct process in terminal and show progress notification' , async ( ) => {
429
+ const prompterTester = getPrompterTester ( )
442
430
const expectedSamAppLocation = {
443
431
workspaceFolder : workspaceFolder ,
444
432
samTemplateUri : templateFile ,
@@ -447,6 +435,10 @@ describe('SAM runBuild', () => {
447
435
448
436
await runBuild ( new AppNode ( expectedSamAppLocation ) )
449
437
438
+ getTestWindow ( )
439
+ . getFirstMessage ( )
440
+ . assertProgress ( `Building SAM template at ${ expectedSamAppLocation . samTemplateUri . path } ` )
441
+
450
442
assert . deepEqual ( mockChildProcessClass . getCall ( 0 ) . args , [
451
443
'sam-cli-path' ,
452
444
[
@@ -472,6 +464,27 @@ describe('SAM runBuild', () => {
472
464
prompterTester . assertCallAll ( )
473
465
} )
474
466
467
+ it ( '[entry: appbuilder node] should throw an error when running two build processes in parallel for the same template' , async ( ) => {
468
+ const prompterTester = getPrompterTester ( )
469
+ const expectedSamAppLocation = {
470
+ workspaceFolder : workspaceFolder ,
471
+ samTemplateUri : templateFile ,
472
+ projectRoot : projectRoot ,
473
+ }
474
+ await assert . rejects (
475
+ async ( ) => {
476
+ await runInParallel ( expectedSamAppLocation )
477
+ } ,
478
+ ( e : any ) => {
479
+ assert . strictEqual ( e instanceof ToolkitError , true )
480
+ assert . strictEqual ( e . message , 'This template is already being built' )
481
+ assert . strictEqual ( e . code , 'BuildInProgress' )
482
+ return true
483
+ }
484
+ )
485
+ prompterTester . assertCallAll ( undefined , 2 )
486
+ } )
487
+
475
488
it ( '[entry: command palette] use samconfig should instantiate correct process in terminal' , async ( ) => {
476
489
const samconfigFile = vscode . Uri . file ( await testFolder . write ( 'samconfig.toml' , samconfigCompleteData ) )
477
490
@@ -587,6 +600,38 @@ describe('SAM runBuild', () => {
587
600
} )
588
601
} )
589
602
603
+ async function runInParallel ( samLocation : SamAppLocation ) : Promise < [ SamBuildResult , SamBuildResult ] > {
604
+ return Promise . all ( [ runBuild ( new AppNode ( samLocation ) ) , delayedRunBuild ( samLocation ) ] )
605
+ }
606
+
607
+ // We add a small delay to avoid the unlikely but possible race condition.
608
+ async function delayedRunBuild ( samLocation : SamAppLocation ) : Promise < SamBuildResult > {
609
+ return new Promise ( async ( resolve , reject ) => {
610
+ // Add a small delay before returning the build promise
611
+ setTimeout ( ( ) => {
612
+ // Do nothing, just let the delay pass
613
+ } , 20 )
614
+
615
+ const buildPromise = runBuild ( new AppNode ( samLocation ) )
616
+ buildPromise . then ( resolve ) . catch ( reject )
617
+ } )
618
+ }
619
+
620
+ function getPrompterTester ( ) {
621
+ return PrompterTester . init ( )
622
+ . handleQuickPick ( 'Specify parameter source for build' , async ( quickPick ) => {
623
+ // Need sometime to wait for the template to search for template file
624
+ await quickPick . untilReady ( )
625
+
626
+ assert . strictEqual ( quickPick . items . length , 2 )
627
+ const items = quickPick . items
628
+ assert . strictEqual ( quickPick . items . length , 2 )
629
+ assert . deepStrictEqual ( items [ 0 ] , { data : ParamsSource . Specify , label : 'Specify build flags' } )
630
+ assert . deepStrictEqual ( items [ 1 ] . label , 'Use default values' )
631
+ quickPick . acceptItem ( quickPick . items [ 1 ] )
632
+ } )
633
+ . build ( )
634
+ }
590
635
function testResolveBuildFlags (
591
636
sandbox : sinon . SinonSandbox ,
592
637
parsedVersion : SemVer ,
0 commit comments