@marcel91200 / caddy Mirror · read-only
Fork 0

Fast and extensible multi-platform HTTP/1-2-3 web server with automatic HTTPS

Mirrored from https://github.com/Slazee/caddy.git

Synced Nov 10, 23:45 UTC

master
go 118 lines 3.39 KB
Raw
1 // Copyright 2015 Matthew Holt and The Caddy Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14
15 package notify
16
17 import (
18 "testing"
19 "time"
20
21 "golang.org/x/sys/windows/svc"
22 )
23
24 func await(t *testing.T, done <-chan struct{}) {
25 t.Helper()
26 select {
27 case <-done:
28 case <-time.After(5 * time.Second):
29 t.Fatal("status operation did not return")
30 }
31 }
32
33 func checkStatus(t *testing.T, statuses <-chan svc.Status, want svc.Status) {
34 t.Helper()
35 select {
36 case got := <-statuses:
37 if got != want {
38 t.Fatalf("status: got %+v, want %+v", got, want)
39 }
40 case <-time.After(5 * time.Second):
41 t.Fatal("status was not published")
42 }
43 }
44
45 func TestStatusOwner(t *testing.T) {
46 running := svc.Status{State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown}
47 for _, tc := range []struct {
48 name string
49 prepare func()
50 want svc.Status
51 }{
52 {"initial", func() {}, svc.Status{State: svc.StartPending}},
53 {"ready", func() { _ = Reloading(); _ = Ready() }, running},
54 {"error", func() { _ = Ready(); _ = Error(nil, 7) }, svc.Status{State: svc.StopPending, ServiceSpecificExitCode: 7}},
55 {"explicit", func() { _ = Status("paused") }, svc.Status{State: svc.Paused, Accepts: svc.AcceptStop | svc.AcceptShutdown | svc.AcceptPauseAndContinue}},
56 {"stopping", func() { _ = Stopping(); _ = Ready(); _ = Reloading() }, svc.Status{State: svc.StopPending}},
57 } {
58 t.Run(tc.name, func(t *testing.T) {
59 SetGlobalStatus(nil)
60 t.Cleanup(func() { SetGlobalStatus(nil) })
61 statuses := make(chan svc.Status, 2)
62 done := make(chan struct{})
63 go func() {
64 defer close(done)
65 tc.prepare() // No attached channel: must return without a receiver.
66 SetGlobalStatus(statuses)
67 Interrogate()
68 }()
69 await(t, done)
70 checkStatus(t, statuses, tc.want)
71 checkStatus(t, statuses, tc.want)
72 })
73 }
74 }
75
76 func TestStatusOrderWithUnbufferedReceiver(t *testing.T) {
77 SetGlobalStatus(nil)
78 statuses := make(chan svc.Status)
79 done := make(chan struct{})
80 go func() {
81 defer close(done)
82 SetGlobalStatus(statuses)
83 _ = Ready()
84 _ = Reloading()
85 _ = Error(nil, 3)
86 _ = Ready() // A reload error is not an irreversible shutdown.
87 _ = Stopping()
88 _ = Ready()
89 _ = Status("running")
90 _ = Status("stopped")
91 Interrogate()
92 }()
93 // Drain on assertion failure so a blocked sender can release statusMu.
94 t.Cleanup(func() {
95 for {
96 select {
97 case <-statuses:
98 case <-done:
99 SetGlobalStatus(nil)
100 return
101 case <-time.After(5 * time.Second):
102 t.Error("sender did not finish during cleanup")
103 return
104 }
105 }
106 })
107 for _, want := range []svc.Status{
108 {State: svc.StartPending},
109 {State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
110 {State: svc.StartPending},
111 {State: svc.StopPending, ServiceSpecificExitCode: 3},
112 {State: svc.Running, Accepts: svc.AcceptStop | svc.AcceptShutdown},
113 {State: svc.StopPending}, {State: svc.Stopped}, {State: svc.Stopped},
114 } {
115 checkStatus(t, statuses, want)
116 }
117 await(t, done)
118 }