diff options
Diffstat (limited to 'pw_multisink/multisink_test.cc')
-rw-r--r-- | pw_multisink/multisink_test.cc | 136 |
1 files changed, 136 insertions, 0 deletions
diff --git a/pw_multisink/multisink_test.cc b/pw_multisink/multisink_test.cc new file mode 100644 index 000000000..4e0f553c7 --- /dev/null +++ b/pw_multisink/multisink_test.cc @@ -0,0 +1,136 @@ +// 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_multisink/multisink.h" + +#include "gtest/gtest.h" +#include "pw_multisink/drain.h" + +namespace pw::multisink { + +class MultiSinkTest : public ::testing::Test { + protected: + static constexpr std::byte kMessage[] = { + (std::byte)0xDE, (std::byte)0xAD, (std::byte)0xBE, (std::byte)0xEF}; + static constexpr size_t kMaxDrains = 3; + static constexpr size_t kEntryBufferSize = 1024; + static constexpr size_t kBufferSize = 5 * kEntryBufferSize; + + MultiSinkTest() : multisink_(buffer_) {} + + void ExpectMessageAndDropCount(Drain& drain, + std::span<const std::byte> expected_message, + uint32_t expected_drop_count) { + uint32_t drop_count = 0; + Result<ConstByteSpan> result = drain.GetEntry(entry_buffer_, drop_count); + if (expected_message.empty()) { + EXPECT_EQ(Status::OutOfRange(), result.status()); + } else { + ASSERT_TRUE(result.ok()); + EXPECT_EQ(memcmp(result.value().data(), + expected_message.data(), + expected_message.size_bytes()), + 0); + } + EXPECT_EQ(drop_count, expected_drop_count); + } + + std::byte buffer_[kBufferSize]; + std::byte entry_buffer_[kEntryBufferSize]; + Drain drains_[kMaxDrains]; + MultiSink multisink_; +}; + +TEST_F(MultiSinkTest, SingleDrain) { + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0])); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + + // Single entry push and pop. + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + + // Multiple entries with intermittent drops. + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + multisink_.HandleDropped(); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + ExpectMessageAndDropCount(drains_[0], kMessage, 1u); + + // Send drops only. + multisink_.HandleDropped(); + ExpectMessageAndDropCount(drains_[0], {}, 1u); + + // Confirm out-of-range if no entries are expected. + ExpectMessageAndDropCount(drains_[0], {}, 0u); +} + +TEST_F(MultiSinkTest, MultipleDrain) { + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0])); + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[1])); + + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + multisink_.HandleDropped(); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + multisink_.HandleDropped(); + + // Drain one drain entirely. + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + ExpectMessageAndDropCount(drains_[0], kMessage, 1u); + ExpectMessageAndDropCount(drains_[0], {}, 1u); + ExpectMessageAndDropCount(drains_[0], {}, 0u); + + // Confirm the other drain can be drained separately. + ExpectMessageAndDropCount(drains_[1], kMessage, 0u); + ExpectMessageAndDropCount(drains_[1], kMessage, 0u); + ExpectMessageAndDropCount(drains_[1], kMessage, 1u); + ExpectMessageAndDropCount(drains_[1], {}, 1u); + ExpectMessageAndDropCount(drains_[1], {}, 0u); +} + +TEST_F(MultiSinkTest, LateRegistration) { + // Confirm that entries pushed before attaching a drain are not seen by the + // drain. + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + + // The drain does not observe 'drops' as it did not see entries, and only sees + // the one entry that was added after attach. + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0])); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + ExpectMessageAndDropCount(drains_[0], {}, 0u); +} + +TEST_F(MultiSinkTest, DynamicDrainRegistration) { + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0])); + + multisink_.HandleDropped(); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + multisink_.HandleDropped(); + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + + // Drain out one message and detach it. + ExpectMessageAndDropCount(drains_[0], kMessage, 1u); + EXPECT_EQ(OkStatus(), multisink_.DetachDrain(drains_[0])); + + // Reattach the drain and confirm that you only see events after attaching. + EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0])); + ExpectMessageAndDropCount(drains_[0], {}, 0u); + + EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage)); + ExpectMessageAndDropCount(drains_[0], kMessage, 0u); + ExpectMessageAndDropCount(drains_[0], {}, 0u); +} + +} // namespace pw::multisink |