@@ -7,7 +7,9 @@ package operation
7
7
import (
8
8
"fmt"
9
9
"math/rand"
10
+ "net"
10
11
"os"
12
+ "os/exec"
11
13
"path/filepath"
12
14
"runtime"
13
15
"testing"
@@ -27,17 +29,26 @@ func TestMain(m *testing.M) {
27
29
Cmd : "configurable" ,
28
30
Args : []string {},
29
31
}
32
+ port , err := getFreePort ()
33
+ if err != nil {
34
+ panic (err )
35
+ }
36
+ serviceSpec := program.Spec {
37
+ ServicePort : port ,
38
+ Name : "serviceable" ,
39
+ Cmd : "serviceable" ,
40
+ Args : []string {fmt .Sprintf ("%d" , port )},
41
+ }
30
42
31
- program .Supported = append (program .Supported , configurableSpec )
43
+ program .Supported = append (program .Supported , configurableSpec , serviceSpec )
44
+ program .SupportedMap ["configurable" ] = configurableSpec
45
+ program .SupportedMap ["serviceable" ] = serviceSpec
32
46
33
- p := getProgram ("configurable" , "1.0" )
34
- spec := p .Spec ()
35
- path := spec .BinaryPath
36
- if runtime .GOOS == "windows" {
37
- path += ".exe"
47
+ if err := isAvailable ("configurable" , "1.0" ); err != nil {
48
+ panic (err )
38
49
}
39
- if s , err := os . Stat ( path ); err != nil || s = = nil {
40
- panic (fmt . Errorf ( "binary not available %s" , spec . BinaryPath ) )
50
+ if err := isAvailable ( "serviceable" , "1.0" ); err != nil {
51
+ panic (err )
41
52
}
42
53
43
54
os .Exit (m .Run ())
@@ -366,3 +377,93 @@ func TestConfigurableStartStop(t *testing.T) {
366
377
})
367
378
}
368
379
}
380
+
381
+ func TestConfigurableService (t * testing.T ) {
382
+ p := getProgram ("serviceable" , "1.0" )
383
+
384
+ operator := getTestOperator (t , downloadPath , installPath , p )
385
+ if err := operator .start (p , nil ); err != nil {
386
+ t .Fatal (err )
387
+ }
388
+ defer operator .stop (p ) // failure catch, to ensure no sub-process stays running
389
+
390
+ // emulating a service, so we need to start the binary here in the test
391
+ spec := p .Spec ()
392
+ cmd := exec .Command (spec .BinaryPath , fmt .Sprintf ("%d" , p .ServicePort ()))
393
+ cmd .Env = append (cmd .Env , os .Environ ()... )
394
+ cmd .Dir = filepath .Dir (spec .BinaryPath )
395
+ cmd .Stdout = os .Stdout
396
+ cmd .Stderr = os .Stderr
397
+ if err := cmd .Start (); err != nil {
398
+ t .Fatal (err )
399
+ }
400
+
401
+ waitFor (t , func () error {
402
+ items := operator .State ()
403
+ item , ok := items [p .ID ()]
404
+ if ! ok {
405
+ return fmt .Errorf ("no state for process" )
406
+ }
407
+ if item .Status != state .Running {
408
+ return fmt .Errorf ("process never went to running" )
409
+ }
410
+ return nil
411
+ })
412
+
413
+ // try to configure
414
+ cfg := make (map [string ]interface {})
415
+ tstFilePath := filepath .Join (os .TempDir (), fmt .Sprintf ("tmp%d" , rand .Uint32 ()))
416
+ cfg ["TestFile" ] = tstFilePath
417
+ if err := operator .pushConfig (p , cfg ); err != nil {
418
+ t .Fatalf ("failed to config: %v" , err )
419
+ }
420
+
421
+ waitFor (t , func () error {
422
+ if s , err := os .Stat (tstFilePath ); err != nil || s == nil {
423
+ return fmt .Errorf ("failed to create a file using Config call %s" , tstFilePath )
424
+ }
425
+ return nil
426
+ })
427
+
428
+ items := operator .State ()
429
+ item0 , ok := items [p .ID ()]
430
+ if ! ok || item0 .Status != state .Running {
431
+ t .Fatalf ("Process no longer running after config %#v" , items )
432
+ }
433
+
434
+ // stop the process
435
+ if err := operator .stop (p ); err != nil {
436
+ t .Fatalf ("Failed to stop service: %v" , err )
437
+ }
438
+
439
+ if err := cmd .Wait (); err != nil {
440
+ t .Fatalf ("Process failed: %v" , err )
441
+ }
442
+ }
443
+
444
+ func isAvailable (name , version string ) error {
445
+ p := getProgram (name , version )
446
+ spec := p .Spec ()
447
+ path := spec .BinaryPath
448
+ if runtime .GOOS == "windows" {
449
+ path += ".exe"
450
+ }
451
+ if s , err := os .Stat (path ); err != nil || s == nil {
452
+ return fmt .Errorf ("binary not available %s" , spec .BinaryPath )
453
+ }
454
+ return nil
455
+ }
456
+
457
+ // getFreePort finds a free port.
458
+ func getFreePort () (int , error ) {
459
+ addr , err := net .ResolveTCPAddr ("tcp" , "localhost:0" )
460
+ if err != nil {
461
+ return 0 , err
462
+ }
463
+ l , err := net .ListenTCP ("tcp" , addr )
464
+ if err != nil {
465
+ return 0 , err
466
+ }
467
+ defer l .Close ()
468
+ return l .Addr ().(* net.TCPAddr ).Port , nil
469
+ }
0 commit comments