• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 // Copyright 2021 The Pigweed Authors
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4 // use this file except in compliance with the License. You may obtain a copy of
5 // the License at
6 //
7 //     https://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11 // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12 // License for the specific language governing permissions and limitations under
13 // the License.
14 
15 #include "pw_multisink/multisink.h"
16 
17 #include "gtest/gtest.h"
18 #include "pw_multisink/drain.h"
19 
20 namespace pw::multisink {
21 
22 class MultiSinkTest : public ::testing::Test {
23  protected:
24   static constexpr std::byte kMessage[] = {
25       (std::byte)0xDE, (std::byte)0xAD, (std::byte)0xBE, (std::byte)0xEF};
26   static constexpr size_t kMaxDrains = 3;
27   static constexpr size_t kEntryBufferSize = 1024;
28   static constexpr size_t kBufferSize = 5 * kEntryBufferSize;
29 
MultiSinkTest()30   MultiSinkTest() : multisink_(buffer_) {}
31 
ExpectMessageAndDropCount(Drain & drain,std::span<const std::byte> expected_message,uint32_t expected_drop_count)32   void ExpectMessageAndDropCount(Drain& drain,
33                                  std::span<const std::byte> expected_message,
34                                  uint32_t expected_drop_count) {
35     uint32_t drop_count = 0;
36     Result<ConstByteSpan> result = drain.GetEntry(entry_buffer_, drop_count);
37     if (expected_message.empty()) {
38       EXPECT_EQ(Status::OutOfRange(), result.status());
39     } else {
40       ASSERT_TRUE(result.ok());
41       EXPECT_EQ(memcmp(result.value().data(),
42                        expected_message.data(),
43                        expected_message.size_bytes()),
44                 0);
45     }
46     EXPECT_EQ(drop_count, expected_drop_count);
47   }
48 
49   std::byte buffer_[kBufferSize];
50   std::byte entry_buffer_[kEntryBufferSize];
51   Drain drains_[kMaxDrains];
52   MultiSink multisink_;
53 };
54 
TEST_F(MultiSinkTest,SingleDrain)55 TEST_F(MultiSinkTest, SingleDrain) {
56   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0]));
57   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
58 
59   // Single entry push and pop.
60   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
61 
62   // Multiple entries with intermittent drops.
63   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
64   multisink_.HandleDropped();
65   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
66   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
67   ExpectMessageAndDropCount(drains_[0], kMessage, 1u);
68 
69   // Send drops only.
70   multisink_.HandleDropped();
71   ExpectMessageAndDropCount(drains_[0], {}, 1u);
72 
73   // Confirm out-of-range if no entries are expected.
74   ExpectMessageAndDropCount(drains_[0], {}, 0u);
75 }
76 
TEST_F(MultiSinkTest,MultipleDrain)77 TEST_F(MultiSinkTest, MultipleDrain) {
78   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0]));
79   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[1]));
80 
81   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
82   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
83   multisink_.HandleDropped();
84   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
85   multisink_.HandleDropped();
86 
87   // Drain one drain entirely.
88   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
89   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
90   ExpectMessageAndDropCount(drains_[0], kMessage, 1u);
91   ExpectMessageAndDropCount(drains_[0], {}, 1u);
92   ExpectMessageAndDropCount(drains_[0], {}, 0u);
93 
94   // Confirm the other drain can be drained separately.
95   ExpectMessageAndDropCount(drains_[1], kMessage, 0u);
96   ExpectMessageAndDropCount(drains_[1], kMessage, 0u);
97   ExpectMessageAndDropCount(drains_[1], kMessage, 1u);
98   ExpectMessageAndDropCount(drains_[1], {}, 1u);
99   ExpectMessageAndDropCount(drains_[1], {}, 0u);
100 }
101 
TEST_F(MultiSinkTest,LateRegistration)102 TEST_F(MultiSinkTest, LateRegistration) {
103   // Confirm that entries pushed before attaching a drain are not seen by the
104   // drain.
105   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
106 
107   // The drain does not observe 'drops' as it did not see entries, and only sees
108   // the one entry that was added after attach.
109   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0]));
110   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
111   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
112   ExpectMessageAndDropCount(drains_[0], {}, 0u);
113 }
114 
TEST_F(MultiSinkTest,DynamicDrainRegistration)115 TEST_F(MultiSinkTest, DynamicDrainRegistration) {
116   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0]));
117 
118   multisink_.HandleDropped();
119   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
120   multisink_.HandleDropped();
121   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
122 
123   // Drain out one message and detach it.
124   ExpectMessageAndDropCount(drains_[0], kMessage, 1u);
125   EXPECT_EQ(OkStatus(), multisink_.DetachDrain(drains_[0]));
126 
127   // Reattach the drain and confirm that you only see events after attaching.
128   EXPECT_EQ(OkStatus(), multisink_.AttachDrain(drains_[0]));
129   ExpectMessageAndDropCount(drains_[0], {}, 0u);
130 
131   EXPECT_EQ(OkStatus(), multisink_.HandleEntry(kMessage));
132   ExpectMessageAndDropCount(drains_[0], kMessage, 0u);
133   ExpectMessageAndDropCount(drains_[0], {}, 0u);
134 }
135 
136 }  // namespace pw::multisink
137