blob: 84d826c3594e3488447cc2512faa1f7027448253 [file] [log] [blame]
/*
* Copyright (C) 2020 The Android Open Source Project
*
* 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
*
* http://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 <gtest/gtest.h>
#include <stddef.h>
#include <stdint.h>
#include <thread>
#include "app_test_base.h"
#include "chpp/app.h"
#include "chpp/clients/discovery.h"
#include "chpp/clients/loopback.h"
#include "chpp/clients/timesync.h"
#include "chpp/log.h"
#include "chpp/platform/platform_link.h"
#include "chpp/transport.h"
/*
* Test suite for the CHPP Loopback client/service
*/
namespace chpp {
namespace {
class ChppAppTest : public AppTestBase {};
TEST_F(ChppAppTest, SimpleStartStop) {
// Simple test to make sure start/stop work threads work without crashing
ASSERT_TRUE(mClientLinkContext.linkEstablished);
ASSERT_TRUE(mServiceLinkContext.linkEstablished);
}
TEST_F(ChppAppTest, TransportLayerLoopback) {
// This tests the more limited transport-layer-looopback. In contrast,
// the regular application-layer loopback test provides a more thorough test
// and test results.
constexpr size_t kTestLen =
CHPP_LINUX_LINK_TX_MTU_BYTES - CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES;
uint8_t buf[kTestLen];
for (size_t i = 0; i < kTestLen; i++) {
buf[i] = (uint8_t)(i + 100);
}
std::this_thread::sleep_for(std::chrono::milliseconds(2000));
CHPP_LOGI("Starting transport-layer loopback test (max buffer = %zu)...",
kTestLen);
EXPECT_EQ(CHPP_APP_ERROR_NONE,
chppRunTransportLoopback(mClientAppContext.transportContext, buf,
kTestLen));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
EXPECT_EQ(CHPP_APP_ERROR_NONE,
mClientAppContext.transportContext->loopbackResult);
EXPECT_EQ(
CHPP_APP_ERROR_NONE,
chppRunTransportLoopback(mClientAppContext.transportContext, buf, 100));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
EXPECT_EQ(CHPP_APP_ERROR_NONE,
mClientAppContext.transportContext->loopbackResult);
EXPECT_EQ(
CHPP_APP_ERROR_NONE,
chppRunTransportLoopback(mClientAppContext.transportContext, buf, 1));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
EXPECT_EQ(CHPP_APP_ERROR_NONE,
mClientAppContext.transportContext->loopbackResult);
EXPECT_EQ(
CHPP_APP_ERROR_INVALID_LENGTH,
chppRunTransportLoopback(mClientAppContext.transportContext, buf, 0));
std::this_thread::sleep_for(std::chrono::milliseconds(300));
EXPECT_EQ(CHPP_APP_ERROR_INVALID_LENGTH,
mClientAppContext.transportContext->loopbackResult);
}
TEST_F(ChppAppTest, SimpleLoopback) {
constexpr size_t kTestLen = CHPP_LINUX_LINK_TX_MTU_BYTES -
CHPP_TRANSPORT_ENCODING_OVERHEAD_BYTES -
CHPP_LOOPBACK_HEADER_LEN;
uint8_t buf[kTestLen];
for (size_t i = 0; i < kTestLen; i++) {
buf[i] = (uint8_t)(i + 100);
}
CHPP_LOGI(
"Starting loopback test without fragmentation (max buffer = %zu)...",
kTestLen);
struct ChppLoopbackTestResult result =
chppRunLoopbackTest(&mClientAppContext, buf, kTestLen);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
result = chppRunLoopbackTest(&mClientAppContext, buf, 10);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
result = chppRunLoopbackTest(&mClientAppContext, buf, 1);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
result = chppRunLoopbackTest(&mClientAppContext, buf, 0);
EXPECT_EQ(result.error, CHPP_APP_ERROR_INVALID_LENGTH);
}
TEST_F(ChppAppTest, FragmentedLoopback) {
constexpr size_t kTestLen = UINT16_MAX;
uint8_t buf[kTestLen];
for (size_t i = 0; i < kTestLen; i++) {
// Arbitrary data. A modulus of 251, a prime number, reduces the chance of
// alignment with the MTU.
buf[i] = (uint8_t)((i % 251) + 64);
}
CHPP_LOGI("Starting loopback test with fragmentation (max buffer = %zu)...",
kTestLen);
struct ChppLoopbackTestResult result =
chppRunLoopbackTest(&mClientAppContext, buf, kTestLen);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
result = chppRunLoopbackTest(&mClientAppContext, buf, 50000);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
result = chppRunLoopbackTest(
&mClientAppContext, buf,
chppTransportTxMtuSize(mClientAppContext.transportContext) -
CHPP_LOOPBACK_HEADER_LEN + 1);
EXPECT_EQ(result.error, CHPP_APP_ERROR_NONE);
}
TEST_F(ChppAppTest, Timesync) {
constexpr uint64_t kMaxRtt = 2 * CHPP_NSEC_PER_MSEC; // in ms
constexpr int64_t kMaxOffset = 1 * CHPP_NSEC_PER_MSEC; // in ms
CHPP_LOGI("Starting timesync test...");
std::this_thread::sleep_for(std::chrono::milliseconds(100));
EXPECT_TRUE(chppTimesyncMeasureOffset(&mClientAppContext));
std::this_thread::sleep_for(std::chrono::milliseconds(100));
EXPECT_EQ(chppTimesyncGetResult(&mClientAppContext)->error,
CHPP_APP_ERROR_NONE);
EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->rttNs, kMaxRtt);
EXPECT_NE(chppTimesyncGetResult(&mClientAppContext)->rttNs, 0);
EXPECT_LT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, kMaxOffset);
EXPECT_GT(chppTimesyncGetResult(&mClientAppContext)->offsetNs, -kMaxOffset);
EXPECT_NE(chppTimesyncGetResult(&mClientAppContext)->offsetNs, 0);
}
TEST_F(ChppAppTest, DiscoveryMatched) {
constexpr uint64_t kTimeoutMs = 5000;
EXPECT_TRUE(chppWaitForDiscoveryComplete(&mClientAppContext, kTimeoutMs));
EXPECT_TRUE(chppAreAllClientsMatched(&mClientAppContext));
}
} // namespace
} // namespace chpp