blob: ce349d70512c51fba5265183dc2e062305bc5f56 [file] [log] [blame]
// Copyright 2021 The Pigweed Authors
//
// 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
//
// https://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.
#include "pw_work_queue/work_queue.h"
#include "gtest/gtest.h"
#include "pw_function/function.h"
#include "pw_log/log.h"
#include "pw_sync/thread_notification.h"
#include "pw_thread/thread.h"
#include "pw_work_queue/test_thread.h"
namespace pw::work_queue {
namespace {
TEST(WorkQueue, PingPongOneRequestType) {
struct {
int counter = 0;
sync::ThreadNotification worker_ping;
} context;
WorkQueueWithBuffer<10> work_queue;
// Start the worker thread.
thread::Thread work_thread(test::WorkQueueThreadOptions(), work_queue);
// Pick a number bigger than the circular buffer to ensure we loop around.
const int kPingPongs = 300;
for (int i = 0; i < kPingPongs; ++i) {
// Ping: throw work at the queue that will increment our counter.
EXPECT_EQ(OkStatus(), work_queue.PushWork([&context] {
context.counter++;
PW_LOG_INFO("Send pong...");
context.worker_ping.release();
}));
// Throw a distraction in the queue.
EXPECT_EQ(OkStatus(), work_queue.PushWork([] {
PW_LOG_INFO("I'm a random task in the work queue; nothing to see here!");
}));
// Pong: wait for the callback to notify us from the worker thread.
context.worker_ping.acquire();
}
// Wait for the worker thread to terminate.
work_queue.RequestStop();
work_thread.join();
EXPECT_EQ(context.counter, kPingPongs);
}
TEST(WorkQueue, PingPongTwoRequestTypesWithExtraRequests) {
struct {
int counter = 0;
sync::ThreadNotification worker_ping;
} context_a, context_b;
WorkQueueWithBuffer<10> work_queue;
// Start the worker thread.
thread::Thread work_thread(test::WorkQueueThreadOptions(), work_queue);
// Pick a number bigger than the circular buffer to ensure we loop around.
const int kPingPongs = 300;
// Run a bunch of work items in the queue.
for (int i = 0; i < kPingPongs; ++i) {
// Other requests...
EXPECT_EQ(OkStatus(),
work_queue.PushWork([] { PW_LOG_INFO("Chopping onions"); }));
// Ping A: throw work at the queue that will increment our counter.
EXPECT_EQ(OkStatus(), work_queue.PushWork([&context_a] {
context_a.counter++;
context_a.worker_ping.release();
}));
// Other requests...
EXPECT_EQ(OkStatus(),
work_queue.PushWork([] { PW_LOG_INFO("Dicing carrots"); }));
EXPECT_EQ(OkStatus(),
work_queue.PushWork([] { PW_LOG_INFO("Blanching spinach"); }));
// Ping B: throw work at the queue that will increment our counter.
EXPECT_EQ(OkStatus(), work_queue.PushWork([&context_b] {
context_b.counter++;
context_b.worker_ping.release();
}));
// Other requests...
EXPECT_EQ(OkStatus(),
work_queue.PushWork([] { PW_LOG_INFO("Peeling potatoes"); }));
// Pong A & B: wait for the callbacks to notify us from the worker thread.
context_a.worker_ping.acquire();
context_b.worker_ping.acquire();
}
// Wait for the worker thread to terminate.
work_queue.RequestStop();
work_thread.join();
EXPECT_EQ(context_a.counter, kPingPongs);
EXPECT_EQ(context_b.counter, kPingPongs);
}
// TODO(ewout): Add unit tests for the metrics once they have been restructured.
} // namespace
} // namespace pw::work_queue