• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2022 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <gtest/gtest.h>
18 
19 #include <cstdint>
20 #include <iostream>
21 #include <thread>
22 #include <type_traits>
23 
24 #include "chpp/app.h"
25 #include "chpp/crc.h"
26 #include "chpp/link.h"
27 #include "chpp/log.h"
28 #include "chpp/platform/platform_link.h"
29 #include "chpp/transport.h"
30 #include "fake_link.h"
31 #include "packet_util.h"
32 
33 using chpp::test::FakeLink;
34 
35 namespace {
36 
init(void * linkContext,struct ChppTransportState * transportContext)37 static void init(void *linkContext,
38                  struct ChppTransportState *transportContext) {
39   auto context = static_cast<struct ChppTestLinkState *>(linkContext);
40   context->fake = new FakeLink();
41   context->transportContext = transportContext;
42 }
43 
deinit(void * linkContext)44 static void deinit(void *linkContext) {
45   auto context = static_cast<struct ChppTestLinkState *>(linkContext);
46   auto *fake = reinterpret_cast<FakeLink *>(context->fake);
47   delete fake;
48 }
49 
send(void * linkContext,size_t len)50 static enum ChppLinkErrorCode send(void *linkContext, size_t len) {
51   auto context = static_cast<struct ChppTestLinkState *>(linkContext);
52   auto *fake = reinterpret_cast<FakeLink *>(context->fake);
53   fake->appendTxPacket(&context->txBuffer[0], len);
54   return CHPP_LINK_ERROR_NONE_SENT;
55 }
56 
doWork(void *,uint32_t)57 static void doWork(void * /*linkContext*/, uint32_t /*signal*/) {}
58 
reset(void *)59 static void reset(void * /*linkContext*/) {}
60 
getConfig(void *)61 struct ChppLinkConfiguration getConfig(void * /*linkContext*/) {
62   return ChppLinkConfiguration{
63       .txBufferLen = CHPP_TEST_LINK_TX_MTU_BYTES,
64       .rxBufferLen = CHPP_TEST_LINK_RX_MTU_BYTES,
65   };
66 }
67 
getTxBuffer(void * linkContext)68 uint8_t *getTxBuffer(void *linkContext) {
69   auto context = static_cast<struct ChppTestLinkState *>(linkContext);
70   return &context->txBuffer[0];
71 }
72 
73 }  // namespace
74 
75 const struct ChppLinkApi gLinkApi = {
76     .init = &init,
77     .deinit = &deinit,
78     .send = &send,
79     .doWork = &doWork,
80     .reset = &reset,
81     .getConfig = &getConfig,
82     .getTxBuffer = &getTxBuffer,
83 };
84 
85 namespace chpp::test {
86 
87 class FakeLinkSyncTests : public testing::Test {
88  protected:
SetUp()89   void SetUp() override {
90     chppTransportInit(&mTransportContext, &mAppContext, &mLinkContext,
91                       &gLinkApi);
92     chppAppInitWithClientServiceSet(&mAppContext, &mTransportContext,
93                                     /*clientServiceSet=*/{});
94     mFakeLink = reinterpret_cast<FakeLink *>(mLinkContext.fake);
95 
96     mWorkThread = std::thread(chppWorkThreadStart, &mTransportContext);
97 
98     // Proceed to the initialized state by performing the CHPP 3-way handshake
99     ASSERT_TRUE(mFakeLink->waitForTxPacket());
100     std::vector<uint8_t> resetPkt = mFakeLink->popTxPacket();
101     ASSERT_TRUE(comparePacket(resetPkt, generateResetPacket()))
102         << "Full packet: " << asResetPacket(resetPkt);
103 
104     ChppResetPacket resetAck = generateResetAckPacket();
105     chppRxDataCb(&mTransportContext, reinterpret_cast<uint8_t *>(&resetAck),
106                  sizeof(resetAck));
107 
108     ASSERT_TRUE(mFakeLink->waitForTxPacket());
109     std::vector<uint8_t> ackPkt = mFakeLink->popTxPacket();
110     ASSERT_TRUE(comparePacket(ackPkt, generateEmptyPacket()))
111         << "Full packet: " << asChpp(ackPkt);
112   }
113 
TearDown()114   void TearDown() override {
115     chppWorkThreadStop(&mTransportContext);
116     mWorkThread.join();
117     EXPECT_EQ(mFakeLink->getTxPacketCount(), 0);
118   }
119 
txPacket()120   void txPacket() {
121     uint32_t *payload = static_cast<uint32_t *>(chppMalloc(sizeof(uint32_t)));
122     *payload = 0xdeadbeef;
123     bool enqueued = chppEnqueueTxDatagramOrFail(&mTransportContext, payload,
124                                                 sizeof(uint32_t));
125     EXPECT_TRUE(enqueued);
126   }
127 
128   ChppTransportState mTransportContext = {};
129   ChppAppState mAppContext = {};
130   ChppTestLinkState mLinkContext = {};
131   FakeLink *mFakeLink;
132   std::thread mWorkThread;
133 };
134 
TEST_F(FakeLinkSyncTests,CheckRetryOnTimeout)135 TEST_F(FakeLinkSyncTests, CheckRetryOnTimeout) {
136   txPacket();
137   ASSERT_TRUE(mFakeLink->waitForTxPacket());
138   EXPECT_EQ(mFakeLink->getTxPacketCount(), 1);
139 
140   std::vector<uint8_t> pkt1 = mFakeLink->popTxPacket();
141 
142   // Ideally, to speed up the test, we'd have a mechanism to trigger
143   // chppNotifierWait() to return immediately, to simulate timeout
144   ASSERT_TRUE(mFakeLink->waitForTxPacket());
145   EXPECT_EQ(mFakeLink->getTxPacketCount(), 1);
146   std::vector<uint8_t> pkt2 = mFakeLink->popTxPacket();
147 
148   // The retry packet should be an exact match of the first one
149   EXPECT_EQ(pkt1, pkt2);
150 }
151 
TEST_F(FakeLinkSyncTests,NoRetryAfterAck)152 TEST_F(FakeLinkSyncTests, NoRetryAfterAck) {
153   txPacket();
154   ASSERT_TRUE(mFakeLink->waitForTxPacket());
155   EXPECT_EQ(mFakeLink->getTxPacketCount(), 1);
156 
157   // Generate and reply back with an ACK
158   std::vector<uint8_t> pkt = mFakeLink->popTxPacket();
159   ChppEmptyPacket ack = generateAck(pkt);
160   chppRxDataCb(&mTransportContext, reinterpret_cast<uint8_t *>(&ack),
161                sizeof(ack));
162 
163   // We shouldn't get that packet again
164   EXPECT_FALSE(mFakeLink->waitForTxPacket());
165 }
166 
TEST_F(FakeLinkSyncTests,MultipleNotifications)167 TEST_F(FakeLinkSyncTests, MultipleNotifications) {
168   constexpr int kNumPackets = 5;
169   for (int i = 0; i < kNumPackets; i++) {
170     txPacket();
171   }
172 
173   for (int i = 0; i < kNumPackets; i++) {
174     ASSERT_TRUE(mFakeLink->waitForTxPacket());
175 
176     // Generate and reply back with an ACK
177     std::vector<uint8_t> pkt = mFakeLink->popTxPacket();
178     ChppEmptyPacket ack = generateAck(pkt);
179     chppRxDataCb(&mTransportContext, reinterpret_cast<uint8_t *>(&ack),
180                  sizeof(ack));
181   }
182 
183   EXPECT_FALSE(mFakeLink->waitForTxPacket());
184 }
185 
186 }  // namespace chpp::test
187