blob: 007d375f164fede65bb6f13a5d6641e63ec8dc8a [file] [log] [blame]
/*
* Copyright 2020-present Open Networking Foundation
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package utils
import (
"context"
"sync"
"testing"
"time"
)
func TestRequestQueueOrdering(t *testing.T) {
rq := NewRequestQueue()
// acquire lock immediately, so our requests will queue up
if err := rq.WaitForGreenLight(context.Background()); err != nil {
t.Error(err)
return
}
doneOrder := make([]int, 0, 10)
wg := sync.WaitGroup{}
wg.Add(10)
// queue up 10 requests
for i := 0; i < 10; i++ {
go func(i int) {
if err := rq.WaitForGreenLight(context.Background()); err != nil {
t.Error(err)
}
doneOrder = append(doneOrder, i)
rq.RequestComplete()
wg.Done()
}(i)
// ensure that the last request is queued before starting the next one
time.Sleep(time.Millisecond)
}
// complete the first process
rq.RequestComplete()
wg.Wait()
// verify that the processes completed in the correct order
for i := 0; i < 10; i++ {
if doneOrder[i] != i {
t.Errorf("Thread %d executed at time %d, should have been %d", doneOrder[i], i, doneOrder[i])
}
}
}
func TestRequestQueueCancellation(t *testing.T) {
rq := NewRequestQueue()
// acquire lock immediately, so our requests will queue up
if err := rq.WaitForGreenLight(context.Background()); err != nil {
t.Error(err)
return
}
wg := sync.WaitGroup{}
wg.Add(10)
willCancelContext, cancel := context.WithCancel(context.Background())
// queue up 10 requests
for i := 0; i < 10; i++ {
go func(i int) {
// will cancel processes 0, 1, 4, 5, 8, 9
willCancel := (i/2)%2 == 0
ctx := context.Background()
if willCancel {
ctx = willCancelContext
}
if err := rq.WaitForGreenLight(ctx); err != nil {
if !willCancel || err != context.Canceled {
t.Errorf("wait gave unexpected error %s", err)
} //else cancellation was expected
} else {
if willCancel {
t.Error("this should have been canceled")
} //else completed as expected
rq.RequestComplete()
}
wg.Done()
}(i)
}
// cancel processes
cancel()
// wait a moment for the cancellations to go through
time.Sleep(time.Millisecond)
// release the lock, and allow the processes to complete
rq.RequestComplete()
// wait for all processes to complete
wg.Wait()
}