osquery-1/osquery/events/events_tests.cpp

354 lines
10 KiB
C++
Raw Normal View History

// Copyright 2004-present Facebook. All Rights Reserved.
2014-12-14 11:43:31 +00:00
#include <typeinfo>
2014-12-15 05:20:20 +00:00
#include <boost/filesystem/operations.hpp>
2014-09-30 02:06:33 +00:00
#include <gtest/gtest.h>
#include <osquery/events.h>
#include <osquery/tables.h>
namespace osquery {
2014-12-15 05:20:20 +00:00
const std::string kTestingEventsDBPath = "/tmp/rocksdb-osquery-testevents";
2014-12-14 11:43:31 +00:00
class EventsTests : public ::testing::Test {
2014-09-30 02:06:33 +00:00
public:
2014-12-15 05:20:20 +00:00
void SetUp() {
// Setup a testing DB instance
DBHandle::getInstanceAtPath(kTestingEventsDBPath);
}
void TearDown() { EventFactory::deregisterEventPublishers(); }
};
2014-12-14 11:43:31 +00:00
// The most basic event publisher uses useless Subscription/Event.
class BasicEventPublisher
: public EventPublisher<SubscriptionContext, EventContext> {};
class AnotherBasicEventPublisher
: public EventPublisher<SubscriptionContext, EventContext> {};
2014-12-15 05:20:20 +00:00
// Create some semi-useless subscription and event structures.
struct FakeSubscriptionContext : SubscriptionContext {
int require_this_value;
};
struct FakeEventContext : EventContext {
int required_value;
};
2014-12-14 11:43:31 +00:00
// Typdef the shared_ptr accessors.
typedef std::shared_ptr<FakeSubscriptionContext> FakeSubscriptionContextRef;
typedef std::shared_ptr<FakeEventContext> FakeEventContextRef;
// Now a publisher with a type.
class FakeEventPublisher
: public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
2014-12-15 02:03:41 +00:00
DECLARE_PUBLISHER("FakePublisher");
};
2014-12-14 11:43:31 +00:00
class AnotherFakeEventPublisher
: public EventPublisher<FakeSubscriptionContext, FakeEventContext> {
2014-12-15 02:03:41 +00:00
DECLARE_PUBLISHER("AnotherFakePublisher");
};
2014-12-14 11:43:31 +00:00
TEST_F(EventsTests, test_event_pub) {
auto pub = std::make_shared<FakeEventPublisher>();
2014-12-15 02:03:41 +00:00
EXPECT_EQ(pub->type(), "FakePublisher");
2014-12-14 11:43:31 +00:00
// Test type names.
auto pub_sub = pub->createSubscriptionContext();
EXPECT_EQ(typeid(FakeSubscriptionContext), typeid(*pub_sub));
}
TEST_F(EventsTests, test_register_event_pub) {
// A caller may register an event type using the class template.
2014-12-14 11:43:31 +00:00
// This template class is equivilent to the reinterpret casting target.
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
EXPECT_TRUE(status.ok());
2014-12-14 11:43:31 +00:00
// This class is the SAME, there was no type override.
status = EventFactory::registerEventPublisher<AnotherBasicEventPublisher>();
EXPECT_FALSE(status.ok());
// This class is different but also uses different types!
status = EventFactory::registerEventPublisher<FakeEventPublisher>();
EXPECT_TRUE(status.ok());
2014-12-14 11:43:31 +00:00
// May also register the event_pub instance
auto pub = std::make_shared<AnotherFakeEventPublisher>();
status = EventFactory::registerEventPublisher<AnotherFakeEventPublisher>(pub);
EXPECT_TRUE(status.ok());
}
2014-12-15 02:03:41 +00:00
TEST_F(EventsTests, test_event_pub_types) {
auto pub = std::make_shared<FakeEventPublisher>();
EXPECT_EQ(pub->type(), "FakePublisher");
EventFactory::registerEventPublisher(pub);
auto pub2 = EventFactory::getEventPublisher("FakePublisher");
EXPECT_EQ(pub->type(), pub2->type());
}
TEST_F(EventsTests, test_create_event_pub) {
2014-12-14 11:43:31 +00:00
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
EXPECT_TRUE(status.ok());
// Make sure only the first event type was recorded.
EXPECT_EQ(EventFactory::numEventPublishers(), 1);
}
TEST_F(EventsTests, test_create_subscription) {
EventFactory::registerEventPublisher<BasicEventPublisher>();
// Make sure a subscription cannot be added for a non-existent event type.
// Note: It normally would not make sense to create a blank subscription.
auto subscription = Subscription::create();
2014-12-15 02:03:41 +00:00
auto status = EventFactory::addSubscription("FakePublisher", subscription);
EXPECT_FALSE(status.ok());
2014-10-04 00:50:25 +00:00
// In this case we can still add a blank subscription to an existing event
// type.
2014-12-14 11:43:31 +00:00
status = EventFactory::addSubscription("publisher", subscription);
EXPECT_TRUE(status.ok());
// Make sure the subscription is added.
2014-12-14 11:43:31 +00:00
EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 1);
}
TEST_F(EventsTests, test_multiple_subscriptions) {
Status status;
EventFactory::registerEventPublisher<BasicEventPublisher>();
auto subscription = Subscription::create();
2014-12-14 11:43:31 +00:00
status = EventFactory::addSubscription("publisher", subscription);
status = EventFactory::addSubscription("publisher", subscription);
2014-12-14 11:43:31 +00:00
EXPECT_EQ(EventFactory::numSubscriptions("publisher"), 2);
}
struct TestSubscriptionContext : public SubscriptionContext {
int smallest;
};
2014-12-14 11:43:31 +00:00
class TestEventPublisher
: public EventPublisher<TestSubscriptionContext, EventContext> {
2014-12-15 02:03:41 +00:00
DECLARE_PUBLISHER("TestPublisher");
2014-12-15 05:20:20 +00:00
public:
2014-12-08 10:22:59 +00:00
Status setUp() {
smallest_ever_ += 1;
return Status(0, "OK");
}
void configure() {
int smallest_subscription = smallest_ever_;
configure_run = true;
for (const auto& subscription : subscriptions_) {
auto subscription_context = getSubscriptionContext(subscription->context);
if (smallest_subscription > subscription_context->smallest) {
smallest_subscription = subscription_context->smallest;
}
}
smallest_ever_ = smallest_subscription;
}
void tearDown() { smallest_ever_ += 1; }
TestEventPublisher() : EventPublisher() {
smallest_ever_ = 0;
configure_run = false;
}
// Custom methods do not make sense, but for testing it exists.
int getTestValue() { return smallest_ever_; }
public:
bool configure_run;
private:
int smallest_ever_;
};
TEST_F(EventsTests, test_create_custom_event_pub) {
2014-12-14 11:43:31 +00:00
auto status = EventFactory::registerEventPublisher<BasicEventPublisher>();
auto pub = std::make_shared<TestEventPublisher>();
status = EventFactory::registerEventPublisher(pub);
// These event types have unique event type IDs
EXPECT_TRUE(status.ok());
EXPECT_EQ(EventFactory::numEventPublishers(), 2);
// Make sure the setUp function was called.
2014-12-14 11:43:31 +00:00
EXPECT_EQ(pub->getTestValue(), 1);
}
TEST_F(EventsTests, test_custom_subscription) {
// Step 1, register event type
2014-12-14 11:43:31 +00:00
auto pub = std::make_shared<TestEventPublisher>();
auto status = EventFactory::registerEventPublisher(pub);
// Step 2, create and configure a subscription context
2014-12-14 11:43:31 +00:00
auto sc = std::make_shared<TestSubscriptionContext>();
sc->smallest = -1;
// Step 3, add the subscription to the event type
2014-12-15 02:03:41 +00:00
status = EventFactory::addSubscription("TestPublisher", sc);
EXPECT_TRUE(status.ok());
2014-12-14 11:43:31 +00:00
EXPECT_EQ(pub->numSubscriptions(), 1);
// The event type must run configure for each added subscription.
2014-12-14 11:43:31 +00:00
EXPECT_TRUE(pub->configure_run);
EXPECT_EQ(pub->getTestValue(), -1);
}
TEST_F(EventsTests, test_tear_down) {
2014-12-14 11:43:31 +00:00
auto pub = std::make_shared<TestEventPublisher>();
auto status = EventFactory::registerEventPublisher(pub);
// Make sure set up incremented the test value.
2014-12-14 11:43:31 +00:00
EXPECT_EQ(pub->getTestValue(), 1);
2014-12-15 02:03:41 +00:00
status = EventFactory::deregisterEventPublisher("TestPublisher");
EXPECT_TRUE(status.ok());
// Make sure tear down inremented the test value.
2014-12-14 11:43:31 +00:00
EXPECT_EQ(pub->getTestValue(), 2);
// Once more, now deregistering all event types.
2014-12-14 11:43:31 +00:00
status = EventFactory::registerEventPublisher(pub);
EXPECT_EQ(pub->getTestValue(), 3);
status = EventFactory::deregisterEventPublishers();
EXPECT_TRUE(status.ok());
2014-12-14 11:43:31 +00:00
EXPECT_EQ(pub->getTestValue(), 4);
// Make sure the factory state represented.
EXPECT_EQ(EventFactory::numEventPublishers(), 0);
}
static int kBellHathTolled = 0;
2014-12-15 05:20:20 +00:00
Status TestTheeCallback(EventContextRef context) {
kBellHathTolled += 1;
return Status(0, "OK");
}
2014-12-15 05:20:20 +00:00
class FakeEventSubscriber : public EventSubscriber<FakeEventPublisher> {
DECLARE_SUBSCRIBER("FakeSubscriber");
public:
bool bellHathTolled;
bool contextBellHathTolled;
bool shouldFireBethHathTolled;
FakeEventSubscriber() {
bellHathTolled = false;
contextBellHathTolled = false;
shouldFireBethHathTolled = false;
}
2014-12-15 18:17:56 +00:00
Status Callback(const EventContextRef& ec) {
2014-12-15 05:20:20 +00:00
// We don't care about the subscription or the event contexts.
bellHathTolled = true;
return Status(0, "OK");
}
2014-12-15 18:17:56 +00:00
Status SpecialCallback(const FakeEventContextRef& ec) {
2014-12-15 05:20:20 +00:00
// Now we care that the event context is corrected passed.
if (ec->required_value == 42) {
contextBellHathTolled = true;
}
return Status(0, "OK");
}
void lateInit() {
auto sub_ctx = createSubscriptionContext();
subscribe(&FakeEventSubscriber::Callback, sub_ctx);
}
void laterInit() {
auto sub_ctx = createSubscriptionContext();
sub_ctx->require_this_value = 42;
subscribe(&FakeEventSubscriber::SpecialCallback, sub_ctx);
}
};
TEST_F(EventsTests, test_event_sub) {
auto sub = std::make_shared<FakeEventSubscriber>();
EXPECT_EQ(sub->type(), "FakePublisher");
EXPECT_EQ(sub->name(), "FakeSubscriber");
}
TEST_F(EventsTests, test_event_sub_subscribe) {
auto pub = std::make_shared<FakeEventPublisher>();
EventFactory::registerEventPublisher(pub);
auto sub = std::make_shared<FakeEventSubscriber>();
EventFactory::registerEventSubscriber(sub);
// Don't overload the normal `init` Subscription member.
sub->lateInit();
EXPECT_EQ(pub->numSubscriptions(), 1);
auto ec = pub->createEventContext();
pub->fire(ec, 0);
EXPECT_TRUE(sub->bellHathTolled);
}
TEST_F(EventsTests, test_event_sub_context) {
auto pub = std::make_shared<FakeEventPublisher>();
EventFactory::registerEventPublisher(pub);
auto sub = std::make_shared<FakeEventSubscriber>();
EventFactory::registerEventSubscriber(sub);
sub->laterInit();
auto ec = pub->createEventContext();
ec->required_value = 42;
pub->fire(ec, 0);
EXPECT_TRUE(sub->contextBellHathTolled);
}
TEST_F(EventsTests, test_fire_event) {
Status status;
2014-12-14 11:43:31 +00:00
auto pub = std::make_shared<BasicEventPublisher>();
status = EventFactory::registerEventPublisher(pub);
auto subscription = Subscription::create();
subscription->callback = TestTheeCallback;
2014-12-14 11:43:31 +00:00
status = EventFactory::addSubscription("publisher", subscription);
2014-09-19 08:54:33 +00:00
// The event context creation would normally happen in the event type.
2014-12-14 11:43:31 +00:00
auto ec = pub->createEventContext();
pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 1);
auto second_subscription = Subscription::create();
2014-12-14 11:43:31 +00:00
status = EventFactory::addSubscription("publisher", second_subscription);
// Now there are two subscriptions (one sans callback).
2014-12-14 11:43:31 +00:00
pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 2);
// Now both subscriptions have callbacks.
second_subscription->callback = TestTheeCallback;
2014-12-14 11:43:31 +00:00
pub->fire(ec, 0);
EXPECT_EQ(kBellHathTolled, 4);
}
}
int main(int argc, char* argv[]) {
testing::InitGoogleTest(&argc, argv);
2014-12-15 05:20:20 +00:00
int status = RUN_ALL_TESTS();
boost::filesystem::remove_all(osquery::kTestingEventsDBPath);
return status;
}