github.com/vpnishe/netstack@v1.10.6/gate/gate_test.go (about) 1 // Copyright 2018 The gVisor 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 gate_test 16 17 import ( 18 "sync" 19 "testing" 20 "time" 21 22 "github.com/vpnishe/netstack/gate" 23 ) 24 25 func TestBasicEnter(t *testing.T) { 26 var g gate.Gate 27 28 if !g.Enter() { 29 t.Fatalf("Failed to enter when it should be allowed") 30 } 31 32 g.Leave() 33 34 g.Close() 35 36 if g.Enter() { 37 t.Fatalf("Allowed to enter when it should fail") 38 } 39 } 40 41 func enterFunc(t *testing.T, g *gate.Gate, enter, leave, reenter chan struct{}, done1, done2, done3 *sync.WaitGroup) { 42 // Wait until instructed to enter. 43 <-enter 44 if !g.Enter() { 45 t.Errorf("Failed to enter when it should be allowed") 46 } 47 48 done1.Done() 49 50 // Wait until instructed to leave. 51 <-leave 52 g.Leave() 53 54 done2.Done() 55 56 // Wait until instructed to reenter. 57 <-reenter 58 if g.Enter() { 59 t.Errorf("Allowed to enter when it should fail") 60 } 61 done3.Done() 62 } 63 64 func TestConcurrentEnter(t *testing.T) { 65 var g gate.Gate 66 var done1, done2, done3 sync.WaitGroup 67 68 // Create 1000 worker goroutines. 69 enter := make(chan struct{}) 70 leave := make(chan struct{}) 71 reenter := make(chan struct{}) 72 done1.Add(1000) 73 done2.Add(1000) 74 done3.Add(1000) 75 for i := 0; i < 1000; i++ { 76 go enterFunc(t, &g, enter, leave, reenter, &done1, &done2, &done3) 77 } 78 79 // Tell them all to enter, then leave. 80 close(enter) 81 done1.Wait() 82 83 close(leave) 84 done2.Wait() 85 86 // Close the gate, then have the workers try to enter again. 87 g.Close() 88 close(reenter) 89 done3.Wait() 90 } 91 92 func closeFunc(g *gate.Gate, done chan struct{}) { 93 g.Close() 94 close(done) 95 } 96 97 func TestCloseWaits(t *testing.T) { 98 var g gate.Gate 99 100 // Enter 10 times. 101 for i := 0; i < 10; i++ { 102 if !g.Enter() { 103 t.Fatalf("Failed to enter when it should be allowed") 104 } 105 } 106 107 // Launch closer. Check that it doesn't complete. 108 done := make(chan struct{}) 109 go closeFunc(&g, done) 110 111 for i := 0; i < 10; i++ { 112 select { 113 case <-done: 114 t.Fatalf("Close function completed too soon") 115 case <-time.After(100 * time.Millisecond): 116 } 117 118 g.Leave() 119 } 120 121 // Now the closer must complete. 122 <-done 123 } 124 125 func TestMultipleSerialCloses(t *testing.T) { 126 var g gate.Gate 127 128 // Enter 10 times. 129 for i := 0; i < 10; i++ { 130 if !g.Enter() { 131 t.Fatalf("Failed to enter when it should be allowed") 132 } 133 } 134 135 // Launch closer. Check that it doesn't complete. 136 done := make(chan struct{}) 137 go closeFunc(&g, done) 138 139 for i := 0; i < 10; i++ { 140 select { 141 case <-done: 142 t.Fatalf("Close function completed too soon") 143 case <-time.After(100 * time.Millisecond): 144 } 145 146 g.Leave() 147 } 148 149 // Now the closer must complete. 150 <-done 151 152 // Close again should not block. 153 done = make(chan struct{}) 154 go closeFunc(&g, done) 155 156 select { 157 case <-done: 158 case <-time.After(2 * time.Second): 159 t.Fatalf("Second Close is blocking") 160 } 161 } 162 163 func worker(g *gate.Gate, done *sync.WaitGroup) { 164 for { 165 if !g.Enter() { 166 break 167 } 168 g.Leave() 169 } 170 done.Done() 171 } 172 173 func TestConcurrentAll(t *testing.T) { 174 var g gate.Gate 175 var done sync.WaitGroup 176 177 // Launch 1000 goroutines to concurrently enter/leave. 178 done.Add(1000) 179 for i := 0; i < 1000; i++ { 180 go worker(&g, &done) 181 } 182 183 // Wait for the goroutines to do some work, then close the gate. 184 time.Sleep(2 * time.Second) 185 g.Close() 186 187 // Wait for all of them to complete. 188 done.Wait() 189 }