process_race_test.go 1.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102
  1. package xray
  2. import (
  3. "errors"
  4. "os/exec"
  5. "sync"
  6. "testing"
  7. "time"
  8. )
  9. // TestProcessLifecycleFieldsRaceSafe drives the lifecycle fields (cmd, done,
  10. // exitErr) the way Start/startCommand and the waitForCommand goroutine do, while
  11. // the status getters read them concurrently. Run with -race: any unsynchronized
  12. // access to those fields is reported as a data race.
  13. func TestProcessLifecycleFieldsRaceSafe(t *testing.T) {
  14. p := &process{logWriter: NewLogWriter()}
  15. var wg sync.WaitGroup
  16. stop := make(chan struct{})
  17. // Writer: churn cmd/done/exitErr like Start + waitForCommand.
  18. wg.Go(func() {
  19. for {
  20. select {
  21. case <-stop:
  22. return
  23. default:
  24. }
  25. p.mu.Lock()
  26. p.cmd = &exec.Cmd{}
  27. p.done = make(chan struct{})
  28. p.mu.Unlock()
  29. p.setExitErr(errors.New("boom"))
  30. }
  31. })
  32. // Readers: the concurrent status getters.
  33. for range 4 {
  34. wg.Go(func() {
  35. for {
  36. select {
  37. case <-stop:
  38. return
  39. default:
  40. }
  41. _ = p.IsRunning()
  42. _ = p.GetErr()
  43. _ = p.GetResult()
  44. }
  45. })
  46. }
  47. time.Sleep(50 * time.Millisecond)
  48. close(stop)
  49. wg.Wait()
  50. }
  51. // TestProcessVersionAPIPortRaceSafe writes version/apiPort the way Start's
  52. // refresh helpers do while GetXrayVersion/GetAPIPort read them concurrently.
  53. // Run with -race: an unsynchronized access to either field is reported.
  54. func TestProcessVersionAPIPortRaceSafe(t *testing.T) {
  55. inner := &process{
  56. logWriter: NewLogWriter(),
  57. config: &Config{InboundConfigs: []InboundConfig{{Tag: "api", Port: 12345}}},
  58. }
  59. p := &Process{inner}
  60. var wg sync.WaitGroup
  61. stop := make(chan struct{})
  62. wg.Go(func() {
  63. for {
  64. select {
  65. case <-stop:
  66. return
  67. default:
  68. }
  69. p.refreshAPIPort()
  70. inner.mu.Lock()
  71. inner.version = "v1.2.3"
  72. inner.mu.Unlock()
  73. }
  74. })
  75. for range 4 {
  76. wg.Go(func() {
  77. for {
  78. select {
  79. case <-stop:
  80. return
  81. default:
  82. }
  83. _ = p.GetAPIPort()
  84. _ = p.GetXrayVersion()
  85. }
  86. })
  87. }
  88. time.Sleep(50 * time.Millisecond)
  89. close(stop)
  90. wg.Wait()
  91. }