service_su_test.go 3.5 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178
  1. // Copyright 2015 Daniel Theophanes.
  2. // Use of this source code is governed by a zlib-style
  3. // license that can be found in the LICENSE file.
  4. // This needs to be run as root/admin hence the reason there is a build tag
  5. // +build su
  6. package service_test
  7. import (
  8. "fmt"
  9. "io/ioutil"
  10. "log"
  11. "os"
  12. "path/filepath"
  13. "regexp"
  14. "testing"
  15. "time"
  16. "github.com/kardianos/service"
  17. )
  18. const runAsServiceArg = "RunThisAsService"
  19. func TestMain(m *testing.M) {
  20. if len(os.Args) == 2 {
  21. os.Exit(m.Run())
  22. } else if len(os.Args) == 4 && os.Args[2] == runAsServiceArg {
  23. reportDir := os.Args[3]
  24. writeReport(reportDir, "call")
  25. runService()
  26. writeReport(reportDir, "finished")
  27. os.Exit(0)
  28. }
  29. log.Fatalf("Invalid arguments: %v", os.Args)
  30. }
  31. func TestInstallRunRestartStopRemove(t *testing.T) {
  32. p := &program{}
  33. reportDir := mustTempDir(t)
  34. defer os.RemoveAll(reportDir)
  35. s := mustNewRunAsService(t, p, reportDir)
  36. _ = s.Uninstall()
  37. if err := s.Install(); err != nil {
  38. t.Fatal("Install", err)
  39. }
  40. defer s.Uninstall()
  41. if err := s.Start(); err != nil {
  42. t.Fatal("Start", err)
  43. }
  44. defer s.Stop()
  45. checkReport(t, reportDir, "Start()", 1, 0)
  46. if err := s.Restart(); err != nil {
  47. t.Fatal("restart", err)
  48. }
  49. checkReport(t, reportDir, "Restart()", 2, 1)
  50. p.numStopped = 0
  51. if err := s.Stop(); err != nil {
  52. t.Fatal("stop", err)
  53. }
  54. checkReport(t, reportDir, "Stop()", 2, 2)
  55. if err := s.Uninstall(); err != nil {
  56. t.Fatal("uninstall", err)
  57. }
  58. }
  59. func runService() {
  60. p := &program{}
  61. sc := &service.Config{
  62. Name: "go_service_test",
  63. }
  64. s, err := service.New(p, sc)
  65. if err != nil {
  66. log.Fatal(err)
  67. }
  68. if err = s.Run(); err != nil {
  69. log.Fatal(err)
  70. }
  71. }
  72. func mustTempDir(t *testing.T) string {
  73. dir, err := ioutil.TempDir("", "servicetest")
  74. if err != nil {
  75. t.Fatal(err)
  76. }
  77. return dir
  78. }
  79. func writeReport(reportDir string, action string) {
  80. b := []byte("go_test_service_report")
  81. timeStamp := time.Now().UnixNano()
  82. err := ioutil.WriteFile(
  83. filepath.Join(reportDir, fmt.Sprintf("%d-%s", timeStamp, action)),
  84. b,
  85. 0644,
  86. )
  87. if err != nil {
  88. log.Fatal(err)
  89. }
  90. }
  91. var matchActionRegexp = regexp.MustCompile("^(\\d+-)([a-z]*)$")
  92. func getReport(
  93. t *testing.T,
  94. reportDir string,
  95. ) (numCalls int, numFinished int) {
  96. numCalls = 0
  97. numFinished = 0
  98. files, err := ioutil.ReadDir(reportDir)
  99. if err != nil {
  100. t.Fatalf("ReadDir(%s) err: %s", reportDir, err)
  101. }
  102. for _, file := range files {
  103. if matchActionRegexp.MatchString(file.Name()) {
  104. action := matchActionRegexp.ReplaceAllString(file.Name(), "$2")
  105. switch action {
  106. case "call":
  107. numCalls++
  108. case "finished":
  109. numFinished++
  110. default:
  111. t.Fatalf("getReport() found report with incorrect action: %s", action)
  112. }
  113. }
  114. }
  115. return
  116. }
  117. func checkReport(
  118. t *testing.T,
  119. reportDir string,
  120. msgPrefix string,
  121. wantNumCalled int,
  122. wantNumFinished int,
  123. ) {
  124. var numCalled int
  125. var numFinished int
  126. for i := 0; i < 25; i++ {
  127. numCalled, numFinished = getReport(t, reportDir)
  128. <-time.After(200 * time.Millisecond)
  129. if numCalled == wantNumCalled && numFinished == wantNumFinished {
  130. return
  131. }
  132. }
  133. if numCalled != wantNumCalled {
  134. t.Fatalf("%s - numCalled: %d, want %d",
  135. msgPrefix, numCalled, wantNumCalled)
  136. }
  137. if numFinished != wantNumFinished {
  138. t.Fatalf("%s - numFinished: %d, want %d",
  139. msgPrefix, numFinished, wantNumFinished)
  140. }
  141. }
  142. func mustNewRunAsService(
  143. t *testing.T,
  144. p *program,
  145. reportDir string,
  146. ) service.Service {
  147. sc := &service.Config{
  148. Name: "go_service_test",
  149. Arguments: []string{"-test.v=true", runAsServiceArg, reportDir},
  150. }
  151. s, err := service.New(p, sc)
  152. if err != nil {
  153. t.Fatal(err)
  154. }
  155. return s
  156. }