@@ -20,6 +20,7 @@ import (
2020 "errors"
2121 "fmt"
2222 "io"
23+ "sync"
2324 "testing"
2425 "time"
2526
@@ -76,3 +77,51 @@ func TestArduinoCliDaemonCompileWithLotOfOutput(t *testing.T) {
7677 testCompile ()
7778 testCompile ()
7879}
80+
81+ func TestInitAndMonitorConcurrency (t * testing.T ) {
82+ // See: https://github.com/arduino/arduino-cli/issues/2719
83+
84+ env , cli := integrationtest .CreateEnvForDaemon (t )
85+ defer env .CleanUp ()
86+
87+ _ , _ , err := cli .Run ("core" , "install" , "arduino:avr" )
88+ require .NoError (t , err )
89+
90+ grpcInst := cli .Create ()
91+ require .NoError (t , grpcInst .Init ("" , "" , func (ir * commands.InitResponse ) {
92+ fmt .Printf ("INIT> %v\n " , ir .GetMessage ())
93+ }))
94+
95+ cli .InstallMockedSerialMonitor (t )
96+
97+ // Open the serial monitor for 5 seconds
98+ ctx , cancel := context .WithTimeout (context .Background (), 5 * time .Second )
99+ defer cancel ()
100+ mon , err := grpcInst .Monitor (ctx , & commands.Port {
101+ Address : "/dev/test" ,
102+ Protocol : "serial" ,
103+ })
104+ require .NoError (t , err )
105+ var monitorCompleted sync.WaitGroup
106+ monitorCompleted .Add (1 )
107+ go func () {
108+ for {
109+ msg , err := mon .Recv ()
110+ if err != nil {
111+ break
112+ }
113+ fmt .Println ("MON> " , msg )
114+ }
115+ fmt .Println ("MON CLOSED" )
116+ monitorCompleted .Done ()
117+ }()
118+
119+ // Check that Init completes without blocking when the monitor is open
120+ start := time .Now ()
121+ require .NoError (t , grpcInst .Init ("" , "" , func (ir * commands.InitResponse ) {
122+ fmt .Printf ("INIT> %v\n " , ir .GetMessage ())
123+ }))
124+ require .LessOrEqual (t , time .Since (start ), 4 * time .Second )
125+ cancel ()
126+ monitorCompleted .Wait ()
127+ }
0 commit comments