blob: bacb3979bd77a8b8b29b3e5d18b7ca7703da0afa [file] [log] [blame]
// Copyright 2008-2009 Google Inc.
//
// 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 <stdlib.h>
#include "base/scoped_ptr.h"
#include "omaha/common/event_handler.h"
#include "omaha/common/reactor.h"
#include "omaha/common/scoped_any.h"
#include "omaha/testing/unit_test.h"
namespace omaha {
// TODO(omaha): rename EventHandler to EventHandlerInterface.
// Creates and registers two waitable timers with the reactor. They go off
// randomly until the reactor stops handling events.
class ReactorTest
: public testing::Test,
public EventHandler {
protected:
ReactorTest() : cnt_(0) {}
virtual void SetUp() {
// Timer handles are with auto reset for simplicity.
reset(timer1_, ::CreateWaitableTimer(NULL, false, NULL));
reset(timer2_, ::CreateWaitableTimer(NULL, false, NULL));
reset(event_done_, ::CreateEvent(NULL, true, false, NULL));
ASSERT_TRUE(timer1_);
ASSERT_TRUE(timer2_);
ASSERT_TRUE(event_done_);
// We only need the thread handle to queue an empty APC to it.
reset(main_thread_, ::OpenThread(THREAD_ALL_ACCESS,
false,
::GetCurrentThreadId()));
ASSERT_TRUE(main_thread_);
}
virtual void TearDown() {
}
// EventHandler.
virtual void HandleEvent(HANDLE h);
// Empty APC to stop the reactor.
static void _stdcall Stop(ULONG_PTR) {}
// Returns an integer value in the [0, 10) range.
static int GetSmallInt() {
unsigned int val = 0;
rand_s(&val);
return val % 10;
}
Reactor reactor_;
scoped_timer timer1_;
scoped_timer timer2_;
scoped_event event_done_;
scoped_handle main_thread_;
LONG cnt_;
static const LONG ReactorTest::kMaxCount = 10;
};
const LONG ReactorTest::kMaxCount;
void ReactorTest::HandleEvent(HANDLE h) {
EXPECT_TRUE(h);
if (h == get(event_done_)) {
ASSERT_TRUE(::QueueUserAPC(&ReactorTest::Stop,
get(main_thread_),
0));
} else if (h == get(timer1_) || h == get(timer2_)) {
// Check the handles auto reset correctly.
EXPECT_EQ(::WaitForSingleObject(h, 0), WAIT_TIMEOUT);
if (::InterlockedIncrement(&cnt_) > kMaxCount) {
ASSERT_TRUE(::SetEvent(get(event_done_)));
} else {
ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(h));
unsigned int val = 0;
ASSERT_EQ(rand_s(&val), 0);
val %= 10;
// Set the timer to fire; negative values indicate relative time.
LARGE_INTEGER due_time_100ns = {0};
due_time_100ns.QuadPart = -(static_cast<int>(val) * 10 * 1000);
ASSERT_TRUE(::SetWaitableTimer(h, &due_time_100ns, 0, NULL, NULL, false));
}
}
}
// Registers the handles, primes the timers, and handles events.
TEST_F(ReactorTest, HandleEvents) {
ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(event_done_), this, 0));
ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer1_), this, 0));
ASSERT_HRESULT_SUCCEEDED(reactor_.RegisterHandle(get(timer2_), this, 0));
LARGE_INTEGER due_time_100ns = {0};
ASSERT_TRUE(SetWaitableTimer(get(timer1_),
&due_time_100ns,
0,
NULL,
NULL,
false));
ASSERT_TRUE(SetWaitableTimer(get(timer2_),
&due_time_100ns,
0,
NULL,
NULL,
false));
ASSERT_HRESULT_SUCCEEDED(reactor_.HandleEvents());
ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer2_)));
ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(timer1_)));
ASSERT_HRESULT_SUCCEEDED(reactor_.UnregisterHandle(get(event_done_)));
}
} // namespace omaha