1- import { test , expect , describe , mock , afterEach } from "bun:test"
1+ import { test , expect , describe , mock , afterEach , spyOn } from "bun:test"
22import { Config } from "../../src/config/config"
33import { Instance } from "../../src/project/instance"
44import { Auth } from "../../src/auth"
@@ -10,6 +10,7 @@ import { pathToFileURL } from "url"
1010import { Global } from "../../src/global"
1111import { ProjectID } from "../../src/project/schema"
1212import { Filesystem } from "../../src/util/filesystem"
13+ import { BunProc } from "../../src/bun"
1314
1415// Get managed config directory from environment (set in preload.ts)
1516const managedConfigDir = process . env . OPENCODE_TEST_MANAGED_CONFIG_DIR !
@@ -763,6 +764,39 @@ test("installs dependencies in writable OPENCODE_CONFIG_DIR", async () => {
763764 }
764765} )
765766
767+ test ( "serializes concurrent config dependency installs" , async ( ) => {
768+ await using tmp = await tmpdir ( )
769+ const dirs = [ path . join ( tmp . path , "a" ) , path . join ( tmp . path , "b" ) ]
770+ await Promise . all ( dirs . map ( ( dir ) => fs . mkdir ( dir , { recursive : true } ) ) )
771+
772+ const seen : string [ ] = [ ]
773+ let active = 0
774+ let max = 0
775+ const run = spyOn ( BunProc , "run" ) . mockImplementation ( async ( _cmd , opts ) => {
776+ active ++
777+ max = Math . max ( max , active )
778+ seen . push ( opts ?. cwd ?? "" )
779+ await new Promise ( ( resolve ) => setTimeout ( resolve , 25 ) )
780+ active --
781+ return {
782+ code : 0 ,
783+ stdout : Buffer . alloc ( 0 ) ,
784+ stderr : Buffer . alloc ( 0 ) ,
785+ }
786+ } )
787+
788+ try {
789+ await Promise . all ( dirs . map ( ( dir ) => Config . installDependencies ( dir ) ) )
790+ } finally {
791+ run . mockRestore ( )
792+ }
793+
794+ expect ( max ) . toBe ( 1 )
795+ expect ( seen . toSorted ( ) ) . toEqual ( dirs . toSorted ( ) )
796+ expect ( await Filesystem . exists ( path . join ( dirs [ 0 ] , "package.json" ) ) ) . toBe ( true )
797+ expect ( await Filesystem . exists ( path . join ( dirs [ 1 ] , "package.json" ) ) ) . toBe ( true )
798+ } )
799+
766800test ( "resolves scoped npm plugins in config" , async ( ) => {
767801 await using tmp = await tmpdir ( {
768802 init : async ( dir ) => {
0 commit comments