shill: Fleshes-out ScanSession enough to initiate a wifi scan.
This CL adds the code required to initiate wifi scan. This expects
wpa_supplicant to deal with the kernel's response. The code does not,
yet, initiate a scan. It just, now, contains what it needs to do so.
BUG=chromium:222088
TEST=unittest
Change-Id: Ibf8294bac455a61b3328a1db4079e0f939c9df6d
Reviewed-on: https://gerrit.chromium.org/gerrit/49272
Reviewed-by: Wade Guthrie <wdg@chromium.org>
Tested-by: Wade Guthrie <wdg@chromium.org>
Commit-Queue: David James <davidjames@chromium.org>
diff --git a/attribute_list.cc b/attribute_list.cc
index 33e1b95..849259d 100644
--- a/attribute_list.cc
+++ b/attribute_list.cc
@@ -29,10 +29,7 @@
bool AttributeList::CreateAttribute(
int id, AttributeList::NewFromIdMethod factory) {
- if (ContainsKey(attributes_, id)) {
- LOG(ERROR) << "Trying to re-add attribute: " << id;
- return false;
- }
+ LOG_IF(INFO, ContainsKey(attributes_, id)) << "Re-adding attribute: " << id;
attributes_[id] = AttributePointer(factory.Run(id));
return true;
}
diff --git a/byte_string.cc b/byte_string.cc
index ea22637..f521e90 100644
--- a/byte_string.cc
+++ b/byte_string.cc
@@ -5,10 +5,14 @@
#include "shill/byte_string.h"
#include <netinet/in.h>
+#include <string.h>
+
+#include <algorithm>
#include <base/string_number_conversions.h>
using std::distance;
+using std::min;
using std::string;
using std::vector;
@@ -193,4 +197,14 @@
}
}
+// static
+bool ByteString::IsLessThan(const ByteString &lhs, const ByteString &rhs) {
+ size_t byte_count = min(lhs.GetLength(), rhs.GetLength());
+ int result = memcmp(lhs.GetConstData(), rhs.GetConstData(), byte_count);
+ if (result == 0) {
+ return byte_count == lhs.GetLength();
+ }
+ return result < 0;
+}
+
} // namespace shill
diff --git a/byte_string.h b/byte_string.h
index 1ba945a..73c83d2 100644
--- a/byte_string.h
+++ b/byte_string.h
@@ -108,6 +108,8 @@
// not cause a copy).
void RemovePrefix(size_t offset);
+ static bool IsLessThan(const ByteString &lhs, const ByteString &rhs);
+
private:
typedef std::vector<unsigned char> Vector;
diff --git a/netlink_manager.h b/netlink_manager.h
index a0072c0..a65ad6b 100644
--- a/netlink_manager.h
+++ b/netlink_manager.h
@@ -59,8 +59,6 @@
#ifndef SHILL_NETLINK_MANAGER_H_
#define SHILL_NETLINK_MANAGER_H_
-#include <gtest/gtest_prod.h> // for FRIEND_TEST
-
#include <list>
#include <map>
#include <set>
@@ -69,7 +67,10 @@
#include <base/basictypes.h>
#include <base/bind.h>
#include <base/lazy_instance.h>
+#include <base/memory/scoped_ptr.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include "shill/io_handler.h"
#include "shill/netlink_message.h"
struct nlmsghdr;
@@ -79,7 +80,6 @@
class Error;
class EventDispatcher;
struct InputData;
-class IOHandler;
class NetlinkSocket;
// NetlinkManager is a singleton that coordinates sending netlink messages to,
diff --git a/nl80211_message.cc b/nl80211_message.cc
index 9f53b69..738e0e4 100644
--- a/nl80211_message.cc
+++ b/nl80211_message.cc
@@ -618,6 +618,18 @@
const uint8_t TriggerScanMessage::kCommand = NL80211_CMD_TRIGGER_SCAN;
const char TriggerScanMessage::kCommandString[] = "NL80211_CMD_TRIGGER_SCAN";
+TriggerScanMessage::TriggerScanMessage()
+ : Nl80211Message(kCommand, kCommandString) {
+ attributes()->CreateAttribute(
+ NL80211_ATTR_IFINDEX, Bind(&NetlinkAttribute::NewNl80211AttributeFromId));
+ attributes()->CreateAttribute(
+ NL80211_ATTR_SCAN_FREQUENCIES,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId));
+ attributes()->CreateAttribute(
+ NL80211_ATTR_SCAN_SSIDS,
+ Bind(&NetlinkAttribute::NewNl80211AttributeFromId));
+}
+
const uint8_t UnprotDeauthenticateMessage::kCommand =
NL80211_CMD_UNPROT_DEAUTHENTICATE;
const char UnprotDeauthenticateMessage::kCommandString[] =
diff --git a/nl80211_message.h b/nl80211_message.h
index d9526a8..d6ed7af 100644
--- a/nl80211_message.h
+++ b/nl80211_message.h
@@ -411,7 +411,7 @@
static const uint8_t kCommand;
static const char kCommandString[];
- TriggerScanMessage() : Nl80211Message(kCommand, kCommandString) {}
+ TriggerScanMessage();
private:
DISALLOW_COPY_AND_ASSIGN(TriggerScanMessage);
diff --git a/scan_session.cc b/scan_session.cc
index 737a432..67f2131 100644
--- a/scan_session.cc
+++ b/scan_session.cc
@@ -6,40 +6,76 @@
#include <algorithm>
#include <set>
+#include <string>
#include <vector>
+#include <base/bind.h>
+#include <base/memory/weak_ptr.h>
#include <base/stl_util.h>
+#include <base/stringprintf.h>
+#include "shill/event_dispatcher.h"
#include "shill/logging.h"
+#include "shill/netlink_manager.h"
+#include "shill/nl80211_attribute.h"
+#include "shill/nl80211_message.h"
+using base::Bind;
+using base::StringPrintf;
using std::set;
+using std::string;
using std::vector;
namespace shill {
+const float ScanSession::kAllFrequencies = 1.1;
+const uint64_t ScanSession::kScanRetryDelayMilliseconds = 100; // Arbitrary.
+const size_t ScanSession::kScanRetryCount = 10;
+
ScanSession::ScanSession(
- const WiFiProvider::FrequencyCountList &connected_frequency_list,
- const vector<uint16_t> &unconnected_frequency_list)
- : frequency_list_(connected_frequency_list),
+ NetlinkManager *netlink_manager,
+ EventDispatcher *dispatcher,
+ const WiFiProvider::FrequencyCountList &previous_frequencies,
+ const set<uint16_t> &available_frequencies,
+ uint32_t ifindex,
+ const FractionList &fractions,
+ int min_frequencies,
+ int max_frequencies,
+ OnScanFailed on_scan_failed)
+ : weak_ptr_factory_(this),
+ netlink_manager_(netlink_manager),
+ dispatcher_(dispatcher),
+ frequency_list_(previous_frequencies),
total_connections_(0),
total_connects_provided_(0),
- total_fraction_wanted_(0.0) {
- SLOG(WiFi, 7) << "Frequency connections vector:";
+ total_fraction_wanted_(0.0),
+ wifi_interface_index_(ifindex),
+ ssids_(ByteString::IsLessThan),
+ fractions_(fractions),
+ min_frequencies_(min_frequencies),
+ max_frequencies_(max_frequencies),
+ on_scan_failed_(on_scan_failed),
+ scan_tries_left_(kScanRetryCount + 1) {
sort(frequency_list_.begin(), frequency_list_.end(),
&ScanSession::CompareFrequencyCount);
+ // Add to |frequency_list_| all the frequencies from |available_frequencies|
+ // that aren't in |previous_frequencies|.
set<uint16_t> seen_frequencies;
- for (const auto freq_conn : frequency_list_) {
- SLOG(WiFi, 7) << " freq[" << freq_conn.frequency << "] = "
- << freq_conn.connection_count;
+ for (const auto &freq_conn : frequency_list_) {
seen_frequencies.insert(freq_conn.frequency);
total_connections_ += freq_conn.connection_count;
}
-
- for (const auto freq : unconnected_frequency_list) {
+ for (const auto freq : available_frequencies) {
if (!ContainsKey(seen_frequencies, freq)) {
frequency_list_.push_back(WiFiProvider::FrequencyCount(freq, 0));
}
}
+
+ SLOG(WiFi, 7) << "Frequency connections vector:";
+ for (const auto &freq_conn : frequency_list_) {
+ SLOG(WiFi, 7) << " freq[" << freq_conn.frequency << "] = "
+ << freq_conn.connection_count;
+ }
}
ScanSession::~ScanSession() {}
@@ -51,7 +87,7 @@
vector<uint16_t> ScanSession::GetScanFrequencies(float fraction_wanted,
size_t min_frequencies,
size_t max_frequencies) {
- DCHECK(fraction_wanted >= 0);
+ DCHECK_GE(fraction_wanted, 0);
total_fraction_wanted_ += fraction_wanted;
float total_connects_wanted = total_fraction_wanted_ * total_connections_;
@@ -77,6 +113,109 @@
return frequencies;
}
+void ScanSession::InitiateScan() {
+ float fraction_wanted = kAllFrequencies;
+ if (!fractions_.empty()) {
+ fraction_wanted = fractions_.front();
+ fractions_.pop_front();
+ }
+ current_scan_frequencies_ = GetScanFrequencies(fraction_wanted,
+ min_frequencies_,
+ max_frequencies_);
+ DoScan(current_scan_frequencies_);
+}
+
+void ScanSession::ReInitiateScan() {
+ DoScan(current_scan_frequencies_);
+}
+
+void ScanSession::DoScan(const vector<uint16_t> &scan_frequencies) {
+ TriggerScanMessage trigger_scan;
+ trigger_scan.attributes()->SetU32AttributeValue(NL80211_ATTR_IFINDEX,
+ wifi_interface_index_);
+ AttributeListRefPtr frequency_list;
+ if (!trigger_scan.attributes()->GetNestedAttributeList(
+ NL80211_ATTR_SCAN_FREQUENCIES, &frequency_list) || !frequency_list) {
+ LOG(FATAL) << "Couldn't get NL80211_ATTR_SCAN_FREQUENCIES.";
+ }
+ trigger_scan.attributes()->SetNestedAttributeHasAValue(
+ NL80211_ATTR_SCAN_FREQUENCIES);
+
+ SLOG(WiFi, 7) << "We have requested scan frequencies:";
+ string attribute_name;
+ int i = 0;
+ for (const auto freq : scan_frequencies) {
+ SLOG(WiFi, 7) << " " << freq;
+ attribute_name = StringPrintf("Frequency-%d", i);
+ frequency_list->CreateU32Attribute(i, attribute_name.c_str());
+ frequency_list->SetU32AttributeValue(i, freq);
+ ++i;
+ }
+
+ if (!ssids_.empty()) {
+ AttributeListRefPtr ssid_list;
+ if (!trigger_scan.attributes()->GetNestedAttributeList(
+ NL80211_ATTR_SCAN_SSIDS, &ssid_list) || !ssid_list) {
+ LOG(FATAL) << "Couldn't get NL80211_ATTR_SCAN_SSIDS attribute.";
+ }
+ trigger_scan.attributes()->SetNestedAttributeHasAValue(
+ NL80211_ATTR_SCAN_SSIDS);
+ int i = 0;
+ string attribute_name;
+ for (const auto &ssid : ssids_) {
+ attribute_name = StringPrintf("NL80211_ATTR_SSID_%d", i);
+ ssid_list->CreateRawAttribute(i, attribute_name.c_str());
+ ssid_list->SetRawAttributeValue(i, ssid);
+ ++i;
+ }
+ // Add an empty one at the end so we ask for a broadcast in addition to
+ // the specific SSIDs.
+ attribute_name = StringPrintf("NL80211_ATTR_SSID_%d", i);
+ ssid_list->CreateRawAttribute(i, attribute_name.c_str());
+ ssid_list->SetRawAttributeValue(i, ByteString());
+ }
+ netlink_manager_->SendMessage(&trigger_scan,
+ Bind(&ScanSession::OnTriggerScanResponse,
+ weak_ptr_factory_.GetWeakPtr()));
+}
+
+void ScanSession::OnTriggerScanResponse(const NetlinkMessage &netlink_message) {
+ if (netlink_message.message_type() != NLMSG_ERROR) {
+ LOG(WARNING) << "Didn't expect _this_ message, here:";
+ netlink_message.Print(0, 0);
+ on_scan_failed_.Run();
+ return;
+ }
+
+ const ErrorAckMessage *error_ack_message =
+ dynamic_cast<const ErrorAckMessage *>(&netlink_message);
+ if (error_ack_message->error()) {
+ LOG(ERROR) << __func__ << ": Message failed: "
+ << error_ack_message->ToString();
+ if (error_ack_message->error() == EBUSY) {
+ if (--scan_tries_left_ == 0) {
+ LOG(ERROR) << "Retried progressive scan " << kScanRetryCount
+ << " times and failed each time. Giving up.";
+ on_scan_failed_.Run();
+ scan_tries_left_ = kScanRetryCount + 1;
+ return;
+ }
+ SLOG(WiFi, 3) << __func__ << " - trying again";
+ dispatcher_->PostDelayedTask(Bind(&ScanSession::ReInitiateScan,
+ weak_ptr_factory_.GetWeakPtr()),
+ kScanRetryDelayMilliseconds);
+ return;
+ }
+ on_scan_failed_.Run();
+ } else {
+ SLOG(WiFi, 6) << __func__ << ": Message ACKed";
+ }
+}
+
+void ScanSession::AddSsid(const ByteString &ssid) {
+ ssids_.insert(ssid);
+}
+
// static
bool ScanSession::CompareFrequencyCount(
const WiFiProvider::FrequencyCount &first,
diff --git a/scan_session.h b/scan_session.h
index ce8d881..5d897af 100644
--- a/scan_session.h
+++ b/scan_session.h
@@ -5,30 +5,26 @@
#ifndef SHILL_SCAN_SESSION_H_
#define SHILL_SCAN_SESSION_H_
+#include <deque>
+#include <set>
#include <vector>
#include <base/basictypes.h>
+#include <base/callback.h>
+#include <base/memory/weak_ptr.h>
+#include <gtest/gtest_prod.h> // for FRIEND_TEST
+#include "shill/byte_string.h"
#include "shill/wifi_provider.h"
namespace shill {
-// Contains the state of a progressive wifi scan (for example, a list of the
-// requested frequencies and an indication of which of those still need to be
-// scanned). A wifi scan using ScanSession can transpire across multiple
-// requests, each one encompassing a different set of frequencies.
-//
-// Use this as follows (note, this is shown as synchronous code for clarity
-// but it really should be implemented as asynchronous code):
-//
-// ScanSession scan_session(frequencies_seen_ever, all_scan_frequencies_);
-// while (scan_session.HasMoreFrequencies()) {
-// scan_session.InitiateScan(scan_session.GetScanFrequencies(
-// kScanFraction, kMinScanFrequencies, kMaxScanFrequencies));
-// // Wait for scan results.
-// }
-//
-// The sequence for a single scan is:
+class EventDispatcher;
+class NetlinkManager;
+class NetlinkMessage;
+
+// |ScanSession| sends requests to the kernel to scan WiFi frequencies for
+// access points. The sequence for a single scan is as follows:
//
// +-------------+ +--------+
// | ScanSession | | Kernel |
@@ -43,35 +39,103 @@
// |<-- NL80211_CMD_NEW_SCAN_RESULTS (reply, unicast, NLM_F_MULTI) -|
// | |
//
-// ScanSession::OnNewScanBroadcast handles the broadcast
-// NL80211_CMD_NEW_SCAN_RESULTS by issuing a NL80211_CMD_GET_SCAN and
-// installing OnNewScanUnicast to handle the unicast
-// NL80211_CMD_NEW_SCAN_RESULTS.
+// Scanning WiFi frequencies for access points takes a long time (on the order
+// of 100ms per frequency and the kernel doesn't return the result until the
+// answers are ready for all the frequencies in the batch). Given this,
+// scanning all frequencies in one batch takes a very long time.
+//
+// A ScanSession is used to distribute a scan across multiple requests (hoping
+// that a successful connection will result from an early request thereby
+// obviating the need for the remainder of the scan). A ScanSession can be
+// used as follows (note, this is shown as synchronous code for clarity
+// but it really should be implemented as asynchronous code):
+//
+// ScanSession::FractionList scan_fractions;
+// scan_fractions.push_back(<some value>);
+// ...
+// scan_fractions.push_back(<some value>);
+// ScanSession scan_session(netlink_manager_, dispatcher(),
+// frequencies_seen_ever, all_scan_frequencies_,
+// interface_index(), scan_fractions,
+// kMinScanFrequencies, kMaxScanFrequencies,
+// on_scan_failed);
+// while (scan_session.HasMoreFrequencies()) {
+// scan_session.InitiateScan();
+// // Wait for scan results. In the current WiFi code, this means wait
+// // until |WiFi::ScanDone| is called.
+// }
class ScanSession {
public:
- // The frequency lists provide the frequencies that are returned by
- // |GetScanFrequencies|. Frequencies are taken, first, from the connected
- // list (in order of the number of connections per frequency -- high before
- // low) and then from the unconnected list (in the order provided).
- ScanSession(const WiFiProvider::FrequencyCountList &connected_frequency_list,
- const std::vector<uint16_t> &unconnected_frequency_list);
+ typedef base::Closure OnScanFailed;
+ typedef std::deque<float> FractionList;
+ // Used as a fraction in |FractionList| to indicate that future scans in
+ // this session should not be limited to a subset of the frequencies we've
+ // already seen.
+ static const float kAllFrequencies;
+
+ // Sets up a new progressive scan session. Uses |netlink_manager| to send
+ // NL80211_CMD_TRIGGER_SCAN messages to the kernel (uses |dispatcher| to
+ // reissue those commands if a send request returns EBUSY). Multiple scans
+ // for APs on wifi device |ifindex| are issued (one for each call to
+ // |InitiateScan|) on wifi frequencies taken from the union of unique
+ // frequencies in |previous_frequencies| and |available_frequencies| (most
+ // commonly seen frequencies before less commonly seen ones followed by
+ // never-before seen frequencies, the latter in an unspecified order).
+ //
+ // Each scan takes a greater percentile (described by the values in
+ // |fractions|) of the previously seen frequencies (but no less than
+ // |min_frequencies| and no more than |max_frequencies|). After all
+ // previously seen frequencies have been requested, each |InitiateScan|
+ // scans the next |max_frequencies| until all |available_frequencies| have
+ // been exhausted.
+ //
+ // If a scan request to the kernel returns an error, |on_scan_failed| is
+ // called. The caller can reissue the scan by calling |ReInitiateScan| or
+ // abort the scan session by deleting the |ScanSession| object.
+ ScanSession(NetlinkManager *netlink_manager,
+ EventDispatcher *dispatcher,
+ const WiFiProvider::FrequencyCountList &previous_frequencies,
+ const std::set<uint16_t> &available_frequencies,
+ uint32_t ifindex,
+ const FractionList &fractions,
+ int min_frequencies,
+ int max_frequencies,
+ OnScanFailed on_scan_failed);
virtual ~ScanSession();
// Returns true if |ScanSession| contains unscanned frequencies.
bool HasMoreFrequencies() const;
- // Scanning WiFi frequencies for access points takes a long time (on the
- // order of 100ms per frequency and the kernel doesn't return the result until
- // the answers are ready for all the frequencies in the batch). Given this,
- // scanning all frequencies in one batch takes a very long time.
- // |GetScanFrequencies| is intended to be called multiple times in order to
- // get a number of small batches of frequencies to scan. Frequencies most
- // likely to yield a successful connection (based on previous connections)
- // are returned first followed by less-likely frequencies followed, finally,
- // by frequencies to which this machine hasn't connected before.
- //
+ // Adds an SSID to the list of things for which to scan. Useful for hidden
+ // SSIDs.
+ void AddSsid(const ByteString &ssid);
+
+ // Start a wifi scan of the next set of frequencies (derived from the
+ // constructor's parameters) after saving those frequencies for the potential
+ // need to reinitiate a scan.
+ virtual void InitiateScan();
+
+ // Re-issues the previous scan (i.e., it uses the same frequency list as the
+ // previous scan). Other classes may use this when |on_scan_failed| is
+ // called. Called by |OnTriggerScanResponse| when the previous attempt to do
+ // a scan fails.
+ void ReInitiateScan();
+
+ private:
+ friend class ScanSessionTest;
+ // Milliseconds to wait before retrying a failed scan.
+ static const uint64_t kScanRetryDelayMilliseconds;
+ // Number of times to retry a failed scan before giving up and calling
+ // |on_scan_failed_|.
+ static const size_t kScanRetryCount;
+
+ // Assists with sorting the |previous_frequencies| passed to the
+ // constructor.
+ static bool CompareFrequencyCount(const WiFiProvider::FrequencyCount &first,
+ const WiFiProvider::FrequencyCount &second);
+
// |GetScanFrequencies| gets the next set of WiFi scan frequencies. Returns
// at least |min_frequencies| (unless fewer frequencies remain from previous
// calls) and no more than |max_frequencies|. Inside these constraints,
@@ -97,13 +161,20 @@
size_t min_frequencies,
size_t max_frequencies);
- private:
- friend class ScanSessionTest;
+ // Does the real work of initiating a scan by sending an
+ // NL80211_CMD_TRIGGER_SCAN message to the kernel and installing a handler for
+ // any response (which only happens in the error case).
+ void DoScan(const std::vector<uint16_t> &scan_frequencies);
- // Assists with sorting the |connected_frequency_list| passed to the
- // constructor.
- static bool CompareFrequencyCount(const WiFiProvider::FrequencyCount &first,
- const WiFiProvider::FrequencyCount &second);
+ // Handles any unicast response to NL80211_CMD_TRIGGER_SCAN (which is,
+ // likely, an error -- when things work, we get an
+ // NL80211_CMD_NEW_SCAN_RESULTS broadcast message).
+ void OnTriggerScanResponse(const NetlinkMessage &message);
+
+ base::WeakPtrFactory<ScanSession> weak_ptr_factory_;
+
+ NetlinkManager *netlink_manager_;
+ EventDispatcher *dispatcher_;
// List of frequencies, sorted by the number of successful connections for
// each frequency.
@@ -111,6 +182,14 @@
size_t total_connections_;
size_t total_connects_provided_;
float total_fraction_wanted_;
+ std::vector<uint16_t> current_scan_frequencies_;
+ uint32_t wifi_interface_index_;
+ std::set<ByteString, bool(*)(const ByteString &, const ByteString &)> ssids_;
+ FractionList fractions_;
+ size_t min_frequencies_;
+ size_t max_frequencies_;
+ OnScanFailed on_scan_failed_;
+ size_t scan_tries_left_;
DISALLOW_COPY_AND_ASSIGN(ScanSession);
};
diff --git a/scan_session_unittest.cc b/scan_session_unittest.cc
index e789cde..4022416 100644
--- a/scan_session_unittest.cc
+++ b/scan_session_unittest.cc
@@ -8,11 +8,9 @@
#include <set>
#include <vector>
-#include <base/memory/scoped_ptr.h>
#include <gmock/gmock.h>
#include <gtest/gtest.h>
-#include "shill/manager.h"
#include "shill/mock_netlink_manager.h"
#include "shill/netlink_manager.h"
@@ -20,8 +18,6 @@
using std::vector;
using testing::_;
using testing::ContainerEq;
-using testing::Invoke;
-using testing::Return;
using testing::Test;
namespace shill {
@@ -54,40 +50,47 @@
kExpectedFreq2412
};
-// A number larger than 1 to make sure that ScanSession doesn't just snag up
-// to 100 percent and stop.
-static float kEverything = 1.1;
-
class ScanSessionTest : public Test {
public:
// Test set of "all the other frequencies this device can support" in
// sorted order.
- ScanSession *ConfigureScanSession() {
- WiFiProvider::FrequencyCountList connected_frequencies =
- GetScanFrequencies();
-
- vector<uint16_t> unconnected_frequencies(
- kUnconnectedFrequencies,
- kUnconnectedFrequencies + arraysize(kUnconnectedFrequencies));
- ScanSession *scan_session(new ScanSession(connected_frequencies,
- unconnected_frequencies));
- return scan_session;
- }
-
- WiFiProvider::FrequencyCountList GetScanFrequencies() const {
- WiFiProvider::FrequencyCountList freq_connects_list(
+ ScanSessionTest() {
+ WiFiProvider::FrequencyCountList connected_frequencies(
kConnectedFrequencies,
kConnectedFrequencies + arraysize(kConnectedFrequencies));
- return freq_connects_list;
+
+ set<uint16_t> unconnected_frequencies(
+ kUnconnectedFrequencies,
+ kUnconnectedFrequencies + arraysize(kUnconnectedFrequencies));
+ const int kArbitraryMinimum = 1;
+ const int kArbitraryMaximum = std::numeric_limits<int>::max();
+ ScanSession::OnScanFailed null_error_handler;
+ scan_session_.reset(new ScanSession(&netlink_manager_,
+ NULL,
+ connected_frequencies,
+ unconnected_frequencies,
+ 0,
+ ScanSession::FractionList(),
+ kArbitraryMinimum,
+ kArbitraryMaximum,
+ null_error_handler));
}
+ virtual std::vector<uint16_t> GetScanFrequencies(float scan_fraction,
+ size_t min_frequencies,
+ size_t max_frequencies) {
+ return scan_session_->GetScanFrequencies(scan_fraction, min_frequencies,
+ max_frequencies);
+ }
+ ScanSession *scan_session() { return scan_session_.get(); }
+
private:
+ scoped_ptr<ScanSession> scan_session_;
MockNetlinkManager netlink_manager_;
};
// Test that we can get a bunch of frequencies up to a specified fraction.
TEST_F(ScanSessionTest, FractionTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 83% of the connected values.
@@ -96,10 +99,9 @@
expected.push_back(kExpectedFreq5640);
expected.push_back(kExpectedFreq5600);
expected.push_back(kExpectedFreq5580);
- result = scan_session->GetScanFrequencies(
- .83, 1, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(.83, 1, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// Get the next 4 values.
@@ -107,30 +109,29 @@
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5560);
expected.push_back(kExpectedFreq5620);
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- result = scan_session->GetScanFrequencies(kEverything, 1, 4);
+ expected.push_back(kExpectedFreq2412);
+ expected.push_back(kExpectedFreq2417);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 1, 4);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the remaining list.
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
- expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(
- kEverything, 20, std::numeric_limits<size_t>::max());
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 20,
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get a bunch of frequencies up to a specified fraction,
// followed by another group up to a specified fraction.
TEST_F(ScanSessionTest, TwoFractionsTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 60% of the connected values.
@@ -138,10 +139,9 @@
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5640);
expected.push_back(kExpectedFreq5600);
- result = scan_session->GetScanFrequencies(
- .60, 0, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(.60, 0, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// Get the next 32% of the connected values.
@@ -149,33 +149,31 @@
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5580);
expected.push_back(kExpectedFreq5560);
- result = scan_session->GetScanFrequencies(
- .32, 0, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(.32, 0, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the remaining list.
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5620);
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(
- kEverything, std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max());
+ expected.push_back(kExpectedFreq2417);
+ expected.push_back(kExpectedFreq2422);
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies,
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get a bunch of frequencies up to a minimum count, even
// when the requested fraction has already been reached.
TEST_F(ScanSessionTest, MinTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 3 previously seen values.
@@ -184,42 +182,39 @@
expected.push_back(kExpectedFreq5640);
expected.push_back(kExpectedFreq5600);
expected.push_back(kExpectedFreq5580);
- result = scan_session->GetScanFrequencies(
- .30, 3, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(.30, 3, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// Get the next value by requensting a minimum of 1.
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5560);
- result = scan_session->GetScanFrequencies(
- 0.0, 1, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(0.0, 1, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the remaining list.
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5620);
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(
- kEverything, std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max());
+ expected.push_back(kExpectedFreq2417);
+ expected.push_back(kExpectedFreq2422);
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies,
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get up to a specified maximum number of frequencies.
TEST_F(ScanSessionTest, MaxTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 7 values (crosses seen/unseen boundary).
@@ -230,30 +225,29 @@
expected.push_back(kExpectedFreq5580);
expected.push_back(kExpectedFreq5560);
expected.push_back(kExpectedFreq5620);
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- result = scan_session->GetScanFrequencies(kEverything, 1, 7);
+ expected.push_back(kExpectedFreq2412);
+ expected.push_back(kExpectedFreq2417);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 1, 7);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the remaining list.
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
- expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(
- kEverything, 20, std::numeric_limits<size_t>::max());
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 20,
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get exactly the seen frequencies and exactly the unseen
// ones.
TEST_F(ScanSessionTest, ExactTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 5 values -- exectly on the seen/unseen border.
@@ -264,28 +258,27 @@
expected.push_back(kExpectedFreq5580);
expected.push_back(kExpectedFreq5560);
expected.push_back(kExpectedFreq5620);
- result = scan_session->GetScanFrequencies(kEverything, 5, 5);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 5, 5);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the last 5.
{
vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(kEverything, 5, 5);
+ expected.push_back(kExpectedFreq2417);
+ expected.push_back(kExpectedFreq2422);
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies, 5, 5);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get everything in one read.
TEST_F(ScanSessionTest, AllOneReadTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5640);
@@ -293,23 +286,22 @@
expected.push_back(kExpectedFreq5580);
expected.push_back(kExpectedFreq5560);
expected.push_back(kExpectedFreq5620);
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
expected.push_back(kExpectedFreq2412);
+ expected.push_back(kExpectedFreq2417);
+ expected.push_back(kExpectedFreq2422);
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
vector<uint16_t> result;
- result = scan_session->GetScanFrequencies(
- kEverything, std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(ScanSession::kAllFrequencies,
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
// Test that we can get all the previously seen frequencies (and only the
// previously seen frequencies) via the requested fraction.
TEST_F(ScanSessionTest, EverythingFractionTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
// Get the first 100% of the connected values.
@@ -320,103 +312,101 @@
expected.push_back(kExpectedFreq5580);
expected.push_back(kExpectedFreq5560);
expected.push_back(kExpectedFreq5620);
- result = scan_session->GetScanFrequencies(
- 1.0, 0, std::numeric_limits<size_t>::max());
+ result = GetScanFrequencies(1.0, 0, std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
// And, get the remaining list.
{
vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2432);
- expected.push_back(kExpectedFreq2427);
- expected.push_back(kExpectedFreq2422);
- expected.push_back(kExpectedFreq2417);
expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(
- kEverything, std::numeric_limits<size_t>::max(),
- std::numeric_limits<size_t>::max());
+ expected.push_back(kExpectedFreq2417);
+ expected.push_back(kExpectedFreq2422);
+ expected.push_back(kExpectedFreq2427);
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(ScanSession::kAllFrequencies,
+ std::numeric_limits<size_t>::max(),
+ std::numeric_limits<size_t>::max());
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}
// Test that we can get each value individually.
TEST_F(ScanSessionTest, IndividualReadsTest) {
- scoped_ptr<ScanSession> scan_session(ConfigureScanSession());
vector<uint16_t> result;
static const float kArbitraryFraction = 0.83;
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5640);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5600);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5580);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5560);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq5620);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
- }
- {
- vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2432);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
- EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
- }
- {
- vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2427);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
- EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
- }
- {
- vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2422);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
- EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
- }
- {
- vector<uint16_t> expected;
- expected.push_back(kExpectedFreq2417);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
- EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_TRUE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
}
{
vector<uint16_t> expected;
expected.push_back(kExpectedFreq2412);
- result = scan_session->GetScanFrequencies(kArbitraryFraction, 1, 1);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
EXPECT_THAT(result, ContainerEq(expected));
- EXPECT_FALSE(scan_session->HasMoreFrequencies());
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
+ }
+ {
+ vector<uint16_t> expected;
+ expected.push_back(kExpectedFreq2417);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
+ EXPECT_THAT(result, ContainerEq(expected));
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
+ }
+ {
+ vector<uint16_t> expected;
+ expected.push_back(kExpectedFreq2422);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
+ EXPECT_THAT(result, ContainerEq(expected));
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
+ }
+ {
+ vector<uint16_t> expected;
+ expected.push_back(kExpectedFreq2427);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
+ EXPECT_THAT(result, ContainerEq(expected));
+ EXPECT_TRUE(scan_session()->HasMoreFrequencies());
+ }
+ {
+ vector<uint16_t> expected;
+ expected.push_back(kExpectedFreq2432);
+ result = GetScanFrequencies(kArbitraryFraction, 1, 1);
+ EXPECT_THAT(result, ContainerEq(expected));
+ EXPECT_FALSE(scan_session()->HasMoreFrequencies());
}
}