VOL-2859 Added test cases for RequestQueue.

Also moved RequestQueue into its own file.

Change-Id: Iadac5fcbaeb9e7e18b74bd7d3c04a5ec6a397ada
diff --git a/rw_core/utils/request_queue_test.go b/rw_core/utils/request_queue_test.go
new file mode 100644
index 0000000..007d375
--- /dev/null
+++ b/rw_core/utils/request_queue_test.go
@@ -0,0 +1,117 @@
+/*
+ * 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()
+}