示例#1
0
TEST_F(WebsocketTest, CleanShutdown) {
  AutoRequired<WebsocketExceptionFilter>();
  
  // Try starting and stopping server multiple times
  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<AutoNetServer>();
    
    ctxt->Initiate();
    ctxt->Wait(std::chrono::milliseconds(200));
    ctxt->SignalShutdown(true);
  }
  
  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<AutoNetServer>();
    
    ctxt->Initiate();
    ctxt->Wait(std::chrono::milliseconds(200));
    ctxt->SignalShutdown(true);
  }
  
  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<AutoNetServer>();
    
    ctxt->Initiate();
    ctxt->Wait(std::chrono::milliseconds(200));
    ctxt->SignalShutdown(true);
  }
}
示例#2
0
TEST_F(CoreContextTest, CorrectHitAllocatorNew) {
  HasOverriddenNewOperator::s_deleterHitCount = 0;
  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);

    // Verify that the overload itsef gets called as expected:
    ASSERT_EQ(
      (void*) HasOverriddenNewOperator::s_space,
      new HasOverriddenNewOperator(false)
    ) << "Overloaded new operator on a test type did not get invoked as expected";

    // Create an instance which won't throw:
    auto hono = AutoCurrentContext()->Construct<HasOverriddenNewOperator>(false);

    // Verify the correct new allocator was hit:
    ASSERT_EQ(
      (void*)HasOverriddenNewOperator::s_space,
      (void*)hono.get()
    ) << "Overridden new allocator was not invoked as anticipated";
  }

  // Verify that the deleter got hit as anticipated:
  ASSERT_EQ(1UL, HasOverriddenNewOperator::s_deleterHitCount) << "The correct deleter was not hit under ordinary teardown";
}
TEST_F(ContextEnumeratorTest, VerifySimpleEnumeration) {
  // Create a pair of descendant contexts, verify we don't accidentally hit these when enumerating children
  AutoCreateContext outer;
  AutoCreateContext inner;
  CurrentContextPusher pshr(inner);

  // Add a few children to the current context:
  AutoCreateContext c1;
  AutoCreateContext c2;
  AutoCreateContext c3;
  AutoCreateContext c4;

  std::unordered_set<std::shared_ptr<CoreContext>> allCtxts;
  allCtxts.insert(AutoCurrentContext());
  allCtxts.insert(c1);
  allCtxts.insert(c2);
  allCtxts.insert(c3);
  allCtxts.insert(c4);

  // Create the enumerator, verify we get the expected count:
  size_t nContexts = 0;
  for(const std::shared_ptr<CoreContext>& cur : CurrentContextEnumerator()) {
    ASSERT_TRUE(!!allCtxts.count(cur)) << "Context enumerator accidentally enumerated a context not rooted in the specified parent";

    allCtxts.erase(cur);
    nContexts++;
  }

  ASSERT_EQ(5UL, nContexts) << "Context enumerator did not encounter the number of expected children";
  ASSERT_TRUE(allCtxts.empty()) << "Context enumerator did not encounter all children as expected";
}
示例#4
0
TEST_F(MultiInheritTest, VerifyBaseInitializer) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  MultiInheritDerived derived;

  // Expect that something autowires when we're done at least:
  ASSERT_TRUE(derived.m_member.IsAutowired());
}
示例#5
0
TEST_F(ContextCreatorTest, ValidateMultipleEviction) {
  AutoCurrentContext()->Initiate();

  // Number of dependent contexts to be created
  const size_t count = 100;

  // Teardown lock, counter, and condition:
  std::mutex lock;
  std::condition_variable cond;
  int counter = count;

  // Obtain creator pointer:
  AutoRequired<Creator> creator;

  // Set up a signal manager at global context scope:
  AutoRequired<GlobalSignal> signal;
  {
    // Array of objects to test destruction on, and corresponding collection of contexts:
    std::shared_ptr<WaitMember> members[count];

    // Create a few contexts:
    for(int i = count; i--;) {
      AutoCreateContext ctxt;
      CurrentContextPusher pshr(ctxt);

      // Trivial validation that the newly created context is an empty context:
      ASSERT_EQ(static_cast<size_t>(0), ctxt->GetMemberCount()) << "A created context was not empty";

      // Add in an object to test asynchronous destruction:
      AutoRequired<WaitMember> obj;
      members[i] = obj;
      ASSERT_EQ(signal.get(), obj->m_signal.get()) << "Dependent context wiring did not correctly match to the enclosing scope";

      // Add a notifier to signal a continue condition when we have everything we need:
      ctxt->AddTeardownListener([&lock, &cond, &counter] {
        (std::lock_guard<std::mutex>)lock,
        counter--,
        cond.notify_all();
      });

      // Kick off the context:
      ctxt->Initiate();
    }

    // Signal all members and then release everything:
    signal->Signal();
  }

  // Wait for all contexts to be destroyed
  std::unique_lock<std::mutex> lk(lock);
  bool wait_status = cond.wait_for(lk, std::chrono::seconds(1), [&counter] {return counter == 0;});
  ASSERT_TRUE(wait_status) << "All teardown listeners didn't trigger, counter still at " << counter;

  // Validate that everything expires:
  ASSERT_EQ(static_cast<size_t>(0), creator->GetSize()) << "Not all contexts were evicted as expected";
}
TEST_F(ContextEnumeratorTest, VerifyComplexEnumeration) {
  std::shared_ptr<CoreContext> firstNamed, secondNamed;

  AutoCreateContext firstContext;
  {
    CurrentContextPusher pshr(firstContext);
    AutoCreateContextT<NamedContext> named;
    firstNamed = named;
  }
  AutoCreateContext secondContext;
  {
    CurrentContextPusher pshr(secondContext);
    AutoCreateContextT<NamedContext> named;
    secondNamed = named;
  }

  // Verify there is only one context under the first context
  int firstCount = 0;
  for(auto ctxt : ContextEnumeratorT<NamedContext>(firstContext)) {
    firstCount++;
    ASSERT_EQ(ctxt, firstNamed);
    ASSERT_EQ(ctxt->GetParentContext(), firstContext);
  }
  ASSERT_EQ(firstCount, 1) << "Expected exactly one context in the parent context, found " << firstCount;

  // Verify there is only one context under the second context
  int secondCount = 0;
  for(auto ctxt : ContextEnumeratorT<NamedContext>(secondContext)) {
    secondCount++;
    ASSERT_EQ(ctxt, secondNamed);
    ASSERT_EQ(ctxt->GetParentContext(), secondContext);
  }
  ASSERT_EQ(secondCount, 1) << "Expected exactly one context in the parent context, found " << secondCount;

  // Verify global context structure
  int globalCount = 0;
  for(auto ctxt : ContextEnumeratorT<NamedContext>(AutoGlobalContext())) {
    globalCount++;
  }
  ASSERT_EQ(globalCount, 2) << "Expected exactly one context in the parent context, found " << globalCount;
}
示例#7
0
TEST_F(MultiInheritTest, VerifyCast) {
  // Create a dummy context and make it current:
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  // Insert a MultiInherit object:
  auto obj = ctxt->Inject<MultiInherit>();

  // Autowire in the pObj:
  Autowired<MultiInherit> wiredPobj;
  ASSERT_TRUE(wiredPobj.IsAutowired()) << "Autowiring failed for a multi-inheritance object";

  // Verify that we get a pObj back with correct casting:
  ASSERT_EQ(obj.get(), wiredPobj.get()) << "Autowiring failed on a multiple inheritance object";
}
TEST_F(AutowiringUtilitiesTest, ThreadSpecificPtr) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  
  AutoRequired<Thread1> thread1;
  AutoRequired<Thread2> thread2;
  
  s_thread_specific_int.reset(new int(5));
  
  ctxt->Initiate();
  
  std::this_thread::sleep_for(std::chrono::milliseconds(50));
  
  EXPECT_EQ(5, *s_thread_specific_int);
  AutoCurrentContext()->SignalShutdown(true);
}
示例#9
0
TEST_F(AutoPacketFactoryTest, AutoPacketFactoryCycle) {
  AutoCurrentContext()->Initiate();

  std::weak_ptr<CoreContext> ctxtWeak;
  std::weak_ptr<HoldsAutoPacketFactoryReference> hapfrWeak;
  std::shared_ptr<AutoPacket> packet;

  {
    // Create a context, fill it up, kick it off:
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);
    AutoRequired<HoldsAutoPacketFactoryReference> hapfr(ctxt);
    ctxt->Initiate();

    // A weak pointer is used to detect object destruction
    ctxtWeak = ctxt;
    hapfrWeak = hapfr;

    // Trivial validation-of-reciept:
    AutoRequired<AutoPacketFactory> factory;
    {
      auto trivial = factory->NewPacket();
      trivial->Decorate((int) 54);
      ASSERT_EQ(54, hapfr->m_value) << "A simple packet was not received as expected by an AutoFilter";
    }

    // Create a packet which will force in a back-reference:
    packet = factory->NewPacket();

    // Terminate the context:
    ctxt->SignalShutdown();

    // Verify that we can still decorate the packet and also that the packet is delivered to the factory:
    packet->Decorate((int) 55);

    // Relock, verify the value was received by the hapfr:
    ASSERT_EQ(55, hapfr->m_value) << "AutoFilter did not receive a packet as expected";
  }

  // The context cannot go out of socpe until all packets in the context are out of scope
  ASSERT_FALSE(ctxtWeak.expired()) << "Context went out of scope before all packets were finished being processed";

  // Now we can release the packet and verify that everything gets cleaned up:
  packet.reset();
  ASSERT_TRUE(ctxtWeak.expired()) << "AutoPacketFactory incorrectly held a cyclic reference even after the context was shut down";
  ASSERT_TRUE(hapfrWeak.expired()) << "The last packet from a factory was released; this should have resulted in teardown, but it did not";
}
示例#10
0
TEST_F(AutoConstructTest, CanConstructRvalueCtor) {
  auto originalPtr = std::make_shared<int>(555);

  // Make a unique pointer to a shared pointer, and pass it in:
  {
    AutoCreateContext ctxt;
    CurrentContextPusher pshr(ctxt);

    std::unique_ptr<std::shared_ptr<int>> forwarded{new std::shared_ptr<int>(originalPtr)};
    AutoConstruct<CanOnlyAcceptMovedInput> coami(std::move(forwarded));

    // Should have the correct number of references, no more and no less
    ASSERT_EQ(2UL, originalPtr.use_count()) << "Forwarding unique pointer did not correctly";
  }

  ASSERT_TRUE(originalPtr.unique()) << "Memory leak detected due to incorrect forwarding of a unique pointer";
}
TEST_F(AutowiringUtilitiesTest, ThreadSpecificPtr) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);
  
  AutoRequired<Thread1> thread1;
  AutoRequired<Thread2> thread2;
  
  s_thread_specific_int.reset(new int(5));
  
  ctxt->Initiate();
  
  auto limit = std::chrono::high_resolution_clock::now() + std::chrono::seconds(10);
  while(std::chrono::high_resolution_clock::now() < limit)
    if(5 == *s_thread_specific_int)
      return;
 
  FAIL() << "Thread specific pointer did not increment to the destination value in a timely fashion";
}
示例#12
0
TEST_F(ObjectPoolTest, VerifyAsynchronousUsage) {
  AutoCreateContext ctxt;
  CurrentContextPusher pshr(ctxt);

  AutoRequired<SimpleThreadedT<PooledObject>> obj;
  AutoFired<SharedPtrReceiver<PooledObject>> spr;
  ObjectPool<PooledObject> pool(3);

  {
    // Obtain the pool limit in objects:
    std::shared_ptr<PooledObject> obj1, obj2, obj3;
    pool(obj1);
    pool(obj2);
    pool(obj3);

    ASSERT_TRUE(nullptr != obj1.get()) << "Failed to obtain an entry from a new object pool";

    // Block--verify that we _do not_ get any of those objects back while they are
    // still outstanding.
    {
      auto obj4 = pool.WaitFor(std::chrono::milliseconds(1));
      EXPECT_TRUE(obj4 == nullptr) << "Pool issued another element even though it should have hit its outstanding limit";
    }

    // Now we kick off threads:
    AutoCurrentContext()->Initiate();

    // Fire off a few events:
    spr(&SharedPtrReceiver<PooledObject>::OnEvent)(obj1);
    spr(&SharedPtrReceiver<PooledObject>::OnEvent)(obj2);
    spr(&SharedPtrReceiver<PooledObject>::OnEvent)(obj3);
  }

  // This should return more or less right away as objects become available:
  {
    auto obj4 = pool.WaitFor(std::chrono::milliseconds(10));
    EXPECT_TRUE(obj4 != nullptr) << "Object pool failed to be notified that it received a new element";
  }

  // Cause the thread to quit:
  *obj += [&obj] { obj->Stop(); };
  obj->Wait();
}
示例#13
0
void CoreJob::DispatchAllAndClearCurrent(void) {
  CurrentContextPusher pshr(GetContext());
  for(;;) {
    // Trivially run down the queue as long as we're in the pool:
    this->DispatchAllEvents();

    // Check the size of the queue.  Could be that someone added something
    // between when we finished looping, and when we obtained the lock, and
    // we don't want to exit our pool if that has happened.
    std::lock_guard<std::mutex> lk(m_dispatchLock);
		if(AreAnyDispatchersReady())
			continue;

		// Indicate that we're tearing down and will be done very soon.  This is
		// a signal to consumers that a call to m_curEvent.wait() will be nearly
		// non-blocking.
		m_curEventInTeardown = true;
    m_queueUpdated.notify_all();
    break;
  }
}