blob: 007d375f164fede65bb6f13a5d6641e63ec8dc8a [file] [log] [blame]
Kent Hagermana05f4d42020-04-01 15:11:22 -04001/*
2 * Copyright 2020-present Open Networking Foundation
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17package utils
18
19import (
20 "context"
21 "sync"
22 "testing"
23 "time"
24)
25
26func TestRequestQueueOrdering(t *testing.T) {
27 rq := NewRequestQueue()
28 // acquire lock immediately, so our requests will queue up
29 if err := rq.WaitForGreenLight(context.Background()); err != nil {
30 t.Error(err)
31 return
32 }
33
34 doneOrder := make([]int, 0, 10)
35
36 wg := sync.WaitGroup{}
37 wg.Add(10)
38
39 // queue up 10 requests
40 for i := 0; i < 10; i++ {
41 go func(i int) {
42 if err := rq.WaitForGreenLight(context.Background()); err != nil {
43 t.Error(err)
44 }
45 doneOrder = append(doneOrder, i)
46 rq.RequestComplete()
47
48 wg.Done()
49 }(i)
50
51 // ensure that the last request is queued before starting the next one
52 time.Sleep(time.Millisecond)
53 }
54
55 // complete the first process
56 rq.RequestComplete()
57
58 wg.Wait()
59
60 // verify that the processes completed in the correct order
61 for i := 0; i < 10; i++ {
62 if doneOrder[i] != i {
63 t.Errorf("Thread %d executed at time %d, should have been %d", doneOrder[i], i, doneOrder[i])
64 }
65 }
66}
67
68func TestRequestQueueCancellation(t *testing.T) {
69 rq := NewRequestQueue()
70 // acquire lock immediately, so our requests will queue up
71 if err := rq.WaitForGreenLight(context.Background()); err != nil {
72 t.Error(err)
73 return
74 }
75
76 wg := sync.WaitGroup{}
77 wg.Add(10)
78
79 willCancelContext, cancel := context.WithCancel(context.Background())
80
81 // queue up 10 requests
82 for i := 0; i < 10; i++ {
83 go func(i int) {
84 // will cancel processes 0, 1, 4, 5, 8, 9
85 willCancel := (i/2)%2 == 0
86
87 ctx := context.Background()
88 if willCancel {
89 ctx = willCancelContext
90 }
91
92 if err := rq.WaitForGreenLight(ctx); err != nil {
93 if !willCancel || err != context.Canceled {
94 t.Errorf("wait gave unexpected error %s", err)
95 } //else cancellation was expected
96 } else {
97 if willCancel {
98 t.Error("this should have been canceled")
99 } //else completed as expected
100 rq.RequestComplete()
101 }
102 wg.Done()
103 }(i)
104 }
105
106 // cancel processes
107 cancel()
108
109 // wait a moment for the cancellations to go through
110 time.Sleep(time.Millisecond)
111
112 // release the lock, and allow the processes to complete
113 rq.RequestComplete()
114
115 // wait for all processes to complete
116 wg.Wait()
117}