blob: 308ed7d128a494cc34b97ec81a9dd899b8d155e3 [file] [log] [blame]
// Copyright 2021 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be found in the LICENSE file.
#include <gtest/gtest.h>
#include <wlan/drivers/components/frame.h>
#include <wlan/drivers/components/frame_storage.h>
namespace {
using wlan::drivers::components::Frame;
using wlan::drivers::components::FrameStorage;
constexpr uint8_t kVmoId = 13;
constexpr size_t kVmoOffset = 0x0c00;
constexpr uint16_t kBufferId = 123;
constexpr uint8_t kPortId = 7;
constexpr uint8_t kPriority = 9;
uint8_t data[256] = {};
TEST(FrameTest, DefaultConstructible) { Frame frame; }
TEST(FrameTest, ParamConstructible) {
Frame frame(nullptr, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId);
EXPECT_EQ(frame.VmoId(), kVmoId);
EXPECT_EQ(frame.VmoOffset(), kVmoOffset);
EXPECT_EQ(frame.BufferId(), kBufferId);
EXPECT_EQ(frame.Data(), data);
EXPECT_EQ(frame.Size(), sizeof(data));
EXPECT_EQ(frame.PortId(), kPortId);
EXPECT_EQ(frame.Headroom(), 0u);
}
TEST(FrameTest, MoveConstructible) {
Frame frame(nullptr, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId);
Frame new_frame(std::move(frame));
EXPECT_EQ(new_frame.VmoId(), kVmoId);
EXPECT_EQ(new_frame.VmoOffset(), kVmoOffset);
EXPECT_EQ(new_frame.BufferId(), kBufferId);
EXPECT_EQ(new_frame.Data(), data);
EXPECT_EQ(new_frame.Size(), sizeof(data));
EXPECT_EQ(new_frame.PortId(), kPortId);
EXPECT_EQ(new_frame.Headroom(), 0u);
}
TEST(FrameTest, MoveAssignable) {
Frame frame(nullptr, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId);
Frame new_frame(nullptr, 0, 0, 0, nullptr, 0, 0);
new_frame = std::move(frame);
EXPECT_EQ(new_frame.VmoId(), kVmoId);
EXPECT_EQ(new_frame.VmoOffset(), kVmoOffset);
EXPECT_EQ(new_frame.BufferId(), kBufferId);
EXPECT_EQ(new_frame.Data(), data);
EXPECT_EQ(new_frame.Size(), sizeof(data));
EXPECT_EQ(new_frame.PortId(), kPortId);
EXPECT_EQ(new_frame.Headroom(), 0u);
}
TEST(FrameTest, SetParameters) {
Frame frame;
frame.SetSize(sizeof(data));
frame.SetPriority(kPriority);
frame.SetPortId(kPortId);
EXPECT_EQ(frame.Size(), sizeof(data));
EXPECT_EQ(frame.Priority(), kPriority);
EXPECT_EQ(frame.PortId(), kPortId);
}
TEST(FrameTest, GrowAndShrink) {
Frame frame(nullptr, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId);
constexpr uint32_t kHeadShrinkage = 42u;
constexpr uint32_t kHeadGrowth = 17u;
frame.ShrinkHead(kHeadShrinkage);
EXPECT_EQ(frame.Headroom(), kHeadShrinkage);
EXPECT_EQ(frame.Data(), data + kHeadShrinkage);
EXPECT_EQ(frame.VmoOffset(), kVmoOffset + kHeadShrinkage);
EXPECT_EQ(frame.Size(), sizeof(data) - kHeadShrinkage);
frame.GrowHead(kHeadGrowth);
EXPECT_EQ(frame.Headroom(), kHeadShrinkage - kHeadGrowth);
EXPECT_EQ(frame.Data(), data + kHeadShrinkage - kHeadGrowth);
EXPECT_EQ(frame.VmoOffset(), kVmoOffset + kHeadShrinkage - kHeadGrowth);
EXPECT_EQ(frame.Size(), sizeof(data) - kHeadShrinkage + kHeadGrowth);
constexpr uint32_t kTailShrinkage = 64u;
constexpr uint32_t kTailGrowth = 9u;
const uint32_t initial_size = frame.Size();
frame.ShrinkTail(kTailShrinkage);
EXPECT_EQ(frame.Size(), initial_size - kTailShrinkage);
frame.GrowTail(kTailGrowth);
EXPECT_EQ(frame.Size(), initial_size - kTailShrinkage + kTailGrowth);
}
TEST(FrameTest, AutomaticLifetime) {
FrameStorage storage;
Frame moved_frame;
uint16_t frame1_buffer_id = 0;
uint16_t frame2_buffer_id = 0;
{
Frame frame1, frame2;
{
std::lock_guard lock(storage);
storage.Store(Frame(&storage, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId));
storage.Store(
Frame(&storage, kVmoId, kVmoOffset, kBufferId + 1, data, sizeof(data), kPortId));
frame1 = *storage.Acquire();
frame2 = *storage.Acquire();
ASSERT_TRUE(storage.empty());
}
frame1_buffer_id = frame1.BufferId();
frame2_buffer_id = frame2.BufferId();
// Modify the frame1's data pointer, headroom and size by shrinking its head. This should be
// reverted once the frame is returned to storage.
frame1.ShrinkHead(42u);
// Modify frame2 as well and verify that it does not change when moved.
frame2.ShrinkHead(13u);
moved_frame = std::move(frame2);
// frame1 goes out of scope and should be returned to storage
// frame2 was moved from and should not be returned to storage
}
std::lock_guard lock(storage);
// frame1 should have returned to storage and been reset, frame2 should now be in moved_frame
ASSERT_EQ(storage.size(), 1u);
EXPECT_EQ(storage.front().VmoId(), kVmoId);
EXPECT_EQ(storage.front().VmoOffset(), kVmoOffset);
EXPECT_EQ(storage.front().BufferId(), frame1_buffer_id);
EXPECT_EQ(storage.front().Data(), data);
EXPECT_EQ(storage.front().Size(), sizeof(data));
EXPECT_EQ(storage.front().PortId(), kPortId);
EXPECT_EQ(storage.front().Headroom(), 0u);
EXPECT_EQ(moved_frame.VmoId(), kVmoId);
EXPECT_EQ(moved_frame.VmoOffset(), kVmoOffset + 13u);
EXPECT_EQ(moved_frame.BufferId(), frame2_buffer_id);
EXPECT_EQ(moved_frame.Data(), data + 13);
EXPECT_EQ(moved_frame.Size(), sizeof(data) - 13u);
EXPECT_EQ(moved_frame.PortId(), kPortId);
EXPECT_EQ(moved_frame.Headroom(), 13u);
}
TEST(FrameTest, ManualLifetime) {
FrameStorage storage;
Frame frame;
{
std::lock_guard lock(storage);
storage.Store(Frame(&storage, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId));
frame = *storage.Acquire();
ASSERT_TRUE(storage.empty());
}
// Modify the frame's data pointer, headroom and size by shrinking its head. This should be
// reverted once the frame is returned to storage.
frame.ShrinkHead(42u);
// Return it.
frame.ReturnToStorage();
std::lock_guard lock(storage);
ASSERT_FALSE(storage.empty());
EXPECT_EQ(storage.front().VmoId(), kVmoId);
EXPECT_EQ(storage.front().VmoOffset(), kVmoOffset);
EXPECT_EQ(storage.front().BufferId(), kBufferId);
EXPECT_EQ(storage.front().Data(), data);
EXPECT_EQ(storage.front().Size(), sizeof(data));
EXPECT_EQ(storage.front().PortId(), kPortId);
EXPECT_EQ(storage.front().Headroom(), 0u);
}
TEST(FrameTest, ReleaseFromStorage) {
constexpr uint32_t kShrinkage = 42u;
FrameStorage storage;
{
Frame frame;
{
std::lock_guard lock(storage);
storage.Store(Frame(&storage, kVmoId, kVmoOffset, kBufferId, data, sizeof(data), kPortId));
frame = *storage.Acquire();
ASSERT_TRUE(storage.empty());
}
// Modify the frame's data pointer, headroom and size by shrinking its head. This should be
// reverted once the frame is returned to storage.
frame.ShrinkHead(kShrinkage);
frame.ReleaseFromStorage();
// Frame goes out of scope, it should not be returned to storage because it was released.
}
std::lock_guard lock(storage);
ASSERT_TRUE(storage.empty());
}
} // namespace