apmanager: monitor events from hostapd control interface

Monitor hostapd control interface for unsolicited event notifications,
such as station connect and disconnect events.

BUG=chromium:431759
TEST=USE="asan clang" FEATURES=test emerge-$BOARD apmanager
Manual Test:
1. Setup an AP service using apmanager.
2. Connect a client to the AP, verify that "Station connected" message is
   in "/var/log/message".
3. Disconnect the client from the AP, verify that "Station disconnect"
   message is in "/var/log/message".

Change-Id: I7410411c43db9670d7ae5e4cf4f9d83a2a2c6337
Reviewed-on: https://chromium-review.googlesource.com/240548
Trybot-Ready: Zeping Qiu <zqiu@chromium.org>
Tested-by: Zeping Qiu <zqiu@chromium.org>
Reviewed-by: Paul Stewart <pstew@chromium.org>
Commit-Queue: Zeping Qiu <zqiu@chromium.org>
diff --git a/hostapd_monitor_unittest.cc b/hostapd_monitor_unittest.cc
new file mode 100644
index 0000000..44f0304
--- /dev/null
+++ b/hostapd_monitor_unittest.cc
@@ -0,0 +1,104 @@
+// Copyright 2014 The Chromium OS Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "apmanager/hostapd_monitor.h"
+
+#include <base/bind.h>
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+#include <shill/net/io_handler.h>
+
+#include "apmanager/mock_event_dispatcher.h"
+
+using base::Bind;
+using base::Unretained;
+using ::testing::_;
+
+namespace {
+  const char kStationMac[] = "00:11:22:33:44:55";
+  const char kHostapdEventStationConnected[] =
+      "<2>AP-STA-CONNECTED 00:11:22:33:44:55";
+  const char kHostapdEventStationDisconnected[] =
+      "<2>AP-STA-DISCONNECTED 00:11:22:33:44:55";
+}  // namespace
+
+namespace apmanager {
+
+class HostapdEventCallbackObserver {
+ public:
+  HostapdEventCallbackObserver()
+      : event_callback_(
+          Bind(&HostapdEventCallbackObserver::OnEventCallback,
+               Unretained(this))) {}
+  virtual ~HostapdEventCallbackObserver() {}
+
+  MOCK_METHOD2(OnEventCallback,
+               void(HostapdMonitor::Event event, const std::string& data));
+
+  const HostapdMonitor::EventCallback event_callback() {
+    return event_callback_;
+  }
+
+ private:
+  HostapdMonitor::EventCallback event_callback_;
+
+  DISALLOW_COPY_AND_ASSIGN(HostapdEventCallbackObserver);
+};
+
+class HostapdMonitorTest : public testing::Test {
+ public:
+  HostapdMonitorTest()
+      : hostapd_monitor_(observer_.event_callback(), "", ""),
+        event_dispatcher_(MockEventDispatcher::GetInstance()) {}
+
+  virtual void SetUp() {
+    hostapd_monitor_.event_dispatcher_ = event_dispatcher_;
+  }
+
+  void Start() {
+    hostapd_monitor_.Start();
+  }
+
+  void ParseMessage(shill::InputData* data) {
+    hostapd_monitor_.ParseMessage(data);
+  }
+
+ protected:
+  HostapdEventCallbackObserver observer_;
+  HostapdMonitor hostapd_monitor_;
+  MockEventDispatcher* event_dispatcher_;
+};
+
+TEST_F(HostapdMonitorTest, Start) {
+  EXPECT_CALL(*event_dispatcher_, PostTask(_)).Times(1);
+  Start();
+
+  // Monitor already started, nothing to be done.
+  EXPECT_CALL(*event_dispatcher_, PostTask(_)).Times(0);
+  Start();
+}
+
+TEST_F(HostapdMonitorTest, StationConnected) {
+  shill::InputData data;
+  data.buf = reinterpret_cast<unsigned char*>(
+      const_cast<char*>(kHostapdEventStationConnected));
+  data.len = strlen(kHostapdEventStationConnected);
+  EXPECT_CALL(observer_,
+              OnEventCallback(HostapdMonitor::kStationConnected,
+                              kStationMac)).Times(1);
+  ParseMessage(&data);
+}
+
+TEST_F(HostapdMonitorTest, StationDisconnected) {
+  shill::InputData data;
+  data.buf = reinterpret_cast<unsigned char*>(
+      const_cast<char*>(kHostapdEventStationDisconnected));
+  data.len = strlen(kHostapdEventStationDisconnected);
+  EXPECT_CALL(observer_,
+              OnEventCallback(HostapdMonitor::kStationDisconnected,
+                              kStationMac)).Times(1);
+  ParseMessage(&data);
+}
+
+}  // namespace apmanager