blob: 1a58ac2af842434340fb3b29aa215a8a361f2fb2 [file] [log] [blame]
/*
*
* Copyright (c) 2020 Project CHIP 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
*
* 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.
*/
/**
* @file
* This is a unit test suite for <tt>chip::System::SystemWakeEvent</tt>
*
*/
#ifndef __STDC_LIMIT_MACROS
#define __STDC_LIMIT_MACROS
#endif
// config
#include <system/SystemConfig.h>
// module header
#include "TestSystemLayer.h"
#include <nlunit-test.h>
#include <support/CodeUtils.h>
#include <support/ErrorStr.h>
#include <support/TestUtils.h>
#include <system/SystemError.h>
#include <system/SystemLayer.h>
#include <system/SystemWakeEvent.h>
#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
#include <pthread.h>
#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
using namespace chip::System;
#if CHIP_SYSTEM_CONFIG_USE_SOCKETS
namespace {
struct TestContext
{
SystemWakeEvent mWakeEvent;
fd_set mReadSet;
fd_set mWriteSet;
fd_set mErrorSet;
TestContext() { mWakeEvent.Open(); }
~TestContext() { mWakeEvent.Close(); }
int SelectWakeEvent(timeval timeout = {})
{
FD_ZERO(&mReadSet);
FD_ZERO(&mWriteSet);
FD_ZERO(&mErrorSet);
FD_SET(mWakeEvent.GetNotifFD(), &mReadSet);
return select(mWakeEvent.GetNotifFD() + 1, &mReadSet, &mWriteSet, &mErrorSet, &timeout);
}
};
void TestOpen(nlTestSuite * inSuite, void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
NL_TEST_ASSERT(inSuite, lContext.mWakeEvent.GetNotifFD() >= 0);
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 0);
}
void TestNotify(nlTestSuite * inSuite, void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 0);
// Check that select() succeeds after Notify() has been called
lContext.mWakeEvent.Notify();
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1);
NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet));
// ...and state of the event is not cleared automatically
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1);
NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet));
}
void TestConfirm(nlTestSuite * inSuite, void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
// Check that select() succeeds after Notify() has been called
lContext.mWakeEvent.Notify();
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 1);
NL_TEST_ASSERT(inSuite, FD_ISSET(lContext.mWakeEvent.GetNotifFD(), &lContext.mReadSet));
// Check that Confirm() clears state of the event
lContext.mWakeEvent.Confirm();
NL_TEST_ASSERT(inSuite, lContext.SelectWakeEvent() == 0);
}
#if CHIP_SYSTEM_CONFIG_POSIX_LOCKING
void * WaitForEvent(void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
// wait 5 seconds
return reinterpret_cast<void *>(lContext.SelectWakeEvent(timeval{ 5, 0 }));
}
void TestBlockingSelect(nlTestSuite * inSuite, void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
// Spawn a thread waiting for the event
pthread_t tid = 0;
NL_TEST_ASSERT(inSuite, 0 == pthread_create(&tid, nullptr, WaitForEvent, aContext));
lContext.mWakeEvent.Notify();
void * selectResult = nullptr;
NL_TEST_ASSERT(inSuite, 0 == pthread_join(tid, &selectResult));
NL_TEST_ASSERT(inSuite, selectResult == reinterpret_cast<void *>(1));
}
#else // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
void TestBlockingSelect(nlTestSuite *, void *) {}
#endif // CHIP_SYSTEM_CONFIG_POSIX_LOCKING
void TestClose(nlTestSuite * inSuite, void * aContext)
{
TestContext & lContext = *static_cast<TestContext *>(aContext);
lContext.mWakeEvent.Close();
const auto notifFD = lContext.mWakeEvent.GetNotifFD();
// Check that Close() has cleaned up itself and reopen is possible
NL_TEST_ASSERT(inSuite, lContext.mWakeEvent.Open() == CHIP_SYSTEM_NO_ERROR);
NL_TEST_ASSERT(inSuite, notifFD < 0);
}
} // namespace
// Test Suite
/**
* Test Suite. It lists all the test functions.
*/
// clang-format off
static const nlTest sTests[] =
{
NL_TEST_DEF("WakeEvent::TestOpen", TestOpen),
NL_TEST_DEF("WakeEvent::TestNotify", TestNotify),
NL_TEST_DEF("WakeEvent::TestConfirm", TestConfirm),
NL_TEST_DEF("WakeEvent::TestBlockingSelect", TestBlockingSelect),
NL_TEST_DEF("WakeEvent::TestClose", TestClose),
NL_TEST_SENTINEL()
};
// clang-format on
// clang-format off
static nlTestSuite kTheSuite =
{
"chip-system-wake-event",
sTests
};
// clang-format on
int TestSystemWakeEvent(void)
{
TestContext context;
// Run test suit againt one lContext.
nlTestRunner(&kTheSuite, &context);
return nlTestRunnerStats(&kTheSuite);
}
CHIP_REGISTER_TEST_SUITE(TestSystemWakeEvent)
#else // CHIP_SYSTEM_CONFIG_USE_SOCKETS
int TestSystemWakeEvent(void)
{
return SUCCESS;
}
#endif // CHIP_SYSTEM_CONFIG_USE_SOCKETS