Quellcodebibliothek Statistik Leitseite products/Sources/formale Sprachen/C/Firefox/netwerk/wifi/gtest/   (Browser von der Mozilla Stiftung Version 136.0.1©)  Datei vom 10.2.2025 mit Größe 13 kB image not shown  

Quelle  TestWifiMonitor.cpp   Sprache: C

 
/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
/* vim: set ts=8 sts=2 et sw=2 tw=80: */
/* This Source Code Form is subject to the terms of the Mozilla Public
 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
 * You can obtain one at http://mozilla.org/MPL/2.0/. */


#include "gtest/gtest.h"
#include "gmock/gmock.h"
#include "nsIWifiListener.h"
#include "nsWifiMonitor.h"
#include "nsWifiAccessPoint.h"
#include "WifiScanner.h"
#include "nsCOMPtr.h"
#include "mozilla/Preferences.h"
#include "mozilla/Services.h"
#include "nsIObserverService.h"
#include "nsINetworkLinkService.h"
#include "mozilla/SpinEventLoopUntil.h"
#include "nsNetCID.h"
#include "nsServiceManagerUtils.h"

#if defined(XP_WIN) && defined(_M_IX86)
#  include <objbase.h>  // STDMETHODCALLTYPE
#endif

// Tests that wifi scanning happens on the right network change events,
// and that wifi-scan polling is operable on mobile networks.

using ::testing::AtLeast;
using ::testing::Cardinality;
using ::testing::Exactly;
using ::testing::MockFunction;
using ::testing::Sequence;

static mozilla::LazyLogModule gLog("TestWifiMonitor");
#define LOGI(x) MOZ_LOG(gLog, mozilla::LogLevel::Info, x)
#define LOGD(x) MOZ_LOG(gLog, mozilla::LogLevel::Debug, x)

namespace mozilla {

// Timeout if update not received from wifi scanner thread.
static const uint32_t kWifiScanTestResultTimeoutMs = 100;
static const uint32_t kTestWifiScanIntervalMs = 10;

// ID counter, used to make sure each call to GetAccessPointsFromWLAN
// returns "new" access points.
static int gCurrentId = 0;

static uint32_t gNumScanResults = 0;

struct LinkTypeMobility {
  const char* mLinkType;
  bool mIsMobile;
};

class MockWifiScanner : public WifiScanner {
 public:
  MOCK_METHOD(nsresult, GetAccessPointsFromWLAN,
              (nsTArray<RefPtr<nsIWifiAccessPoint>> & aAccessPoints),
              (override));
};

class MockWifiListener : public nsIWifiListener {
  virtual ~MockWifiListener() = default;

 public:
  NS_DECL_THREADSAFE_ISUPPORTS
#if defined(XP_WIN) && defined(_M_IX86)
  MOCK_METHOD(nsresult, OnChange,
              (const nsTArray<RefPtr<nsIWifiAccessPoint>>& accessPoints),
              (override, Calltype(STDMETHODCALLTYPE)));
  MOCK_METHOD(nsresult, OnError, (nsresult error),
              (override, Calltype(STDMETHODCALLTYPE)));
#else
  MOCK_METHOD(nsresult, OnChange,
              (const nsTArray<RefPtr<nsIWifiAccessPoint>>& accessPoints),
              (override));
  MOCK_METHOD(nsresult, OnError, (nsresult error), (override));
#endif
};

NS_IMPL_ISUPPORTS(MockWifiListener, nsIWifiListener)

class TestWifiMonitor : public ::testing::Test {
 public:
  TestWifiMonitor() {
    mObs = mozilla::services::GetObserverService();
    MOZ_RELEASE_ASSERT(mObs);

    nsresult rv;
    nsCOMPtr<nsINetworkLinkService> nls =
        do_GetService(NS_NETWORK_LINK_SERVICE_CONTRACTID, &rv);
    EXPECT_TRUE(NS_SUCCEEDED(rv));
    EXPECT_TRUE(nls);
    rv = nls->GetLinkType(&mOrigLinkType);
    EXPECT_TRUE(NS_SUCCEEDED(rv));
    rv = nls->GetIsLinkUp(&mOrigIsLinkUp);
    EXPECT_TRUE(NS_SUCCEEDED(rv));
    rv = nls->GetLinkStatusKnown(&mOrigLinkStatusKnown);
    EXPECT_TRUE(NS_SUCCEEDED(rv));

    // Reduce wifi-polling interval.  0 turns polling off.
    mOldScanInterval = Preferences::GetInt(WIFI_SCAN_INTERVAL_MS_PREF);
    Preferences::SetInt(WIFI_SCAN_INTERVAL_MS_PREF, kTestWifiScanIntervalMs);
  }

  ~TestWifiMonitor() {
    Preferences::SetInt(WIFI_SCAN_INTERVAL_MS_PREF, mOldScanInterval);

    // Restore network link type
    const char* linkType = nullptr;
    switch (mOrigLinkType) {
      case nsINetworkLinkService::LINK_TYPE_UNKNOWN:
        linkType = NS_NETWORK_LINK_TYPE_UNKNOWN;
        break;
      case nsINetworkLinkService::LINK_TYPE_ETHERNET:
        linkType = NS_NETWORK_LINK_TYPE_ETHERNET;
        break;
      case nsINetworkLinkService::LINK_TYPE_USB:
        linkType = NS_NETWORK_LINK_TYPE_USB;
        break;
      case nsINetworkLinkService::LINK_TYPE_WIFI:
        linkType = NS_NETWORK_LINK_TYPE_WIFI;
        break;
      case nsINetworkLinkService::LINK_TYPE_MOBILE:
        linkType = NS_NETWORK_LINK_TYPE_MOBILE;
        break;
      case nsINetworkLinkService::LINK_TYPE_WIMAX:
        linkType = NS_NETWORK_LINK_TYPE_WIMAX;
        break;
    }
    EXPECT_TRUE(linkType);
    mObs->NotifyObservers(nullptr, NS_NETWORK_LINK_TYPE_TOPIC,
                          NS_ConvertUTF8toUTF16(linkType).get());

    const char* linkStatus = nullptr;
    if (mOrigLinkStatusKnown) {
      if (mOrigIsLinkUp) {
        linkStatus = NS_NETWORK_LINK_DATA_UP;
      } else {
        linkStatus = NS_NETWORK_LINK_DATA_DOWN;
      }
    } else {
      linkStatus = NS_NETWORK_LINK_DATA_UNKNOWN;
    }
    EXPECT_TRUE(linkStatus);
    mObs->NotifyObservers(nullptr, NS_NETWORK_LINK_TOPIC,
                          NS_ConvertUTF8toUTF16(linkStatus).get());
  }

 protected:
  bool WaitForScanResults() {
    // Wait for kWifiScanTestResultTimeoutMs to allow async calls to complete.
    bool timedout = false;
    RefPtr<CancelableRunnable> timer = NS_NewCancelableRunnableFunction(
        "WaitForScanResults Timeout", [&] { timedout = true; });
    NS_DelayedDispatchToCurrentThread(do_AddRef(timer),
                                      kWifiScanTestResultTimeoutMs);

    mozilla::SpinEventLoopUntil("TestWifiMonitor::WaitForScanResults"_ns,
                                [&]() { return timedout; });

    timer->Cancel();
    return true;
  }

  void CreateObjects() {
    mWifiMonitor = MakeRefPtr<nsWifiMonitor>(MakeUnique<MockWifiScanner>());
    EXPECT_TRUE(!mWifiMonitor->IsPolling());

    // Start with ETHERNET network type to avoid always polling at test start.
    mObs->NotifyObservers(
        nullptr, NS_NETWORK_LINK_TYPE_TOPIC,
        NS_ConvertUTF8toUTF16(NS_NETWORK_LINK_TYPE_ETHERNET).get());

    mWifiListener = new MockWifiListener();
    LOGI(("monitor: %p | scanner: %p | listener: %p", mWifiMonitor.get(),
          mWifiMonitor->mWifiScanner.get(), mWifiListener.get()));
  }

  void DestroyObjects() {
    ::testing::Mock::VerifyAndClearExpectations(
        mWifiMonitor->mWifiScanner.get());
    ::testing::Mock::VerifyAndClearExpectations(mWifiListener.get());

    // Manually disconnect observers so that the monitor can be destroyed.
    // In the browser, this would be done on xpcom-shutdown but that is sent
    // after the tests run, which is too late to avoid a gtest memory-leak
    // error.
    mWifiMonitor->Close();

    mWifiMonitor = nullptr;
    mWifiListener = nullptr;
    gCurrentId = 0;
  }

  void StartWatching(bool aRequestPolling) {
    LOGD(("StartWatching | aRequestPolling: %s | nScanResults: %u",
          aRequestPolling ? "true" : "false", gNumScanResults));
    EXPECT_TRUE(NS_SUCCEEDED(
        mWifiMonitor->StartWatching(mWifiListener, aRequestPolling)));
    WaitForScanResults();
  }

  void NotifyOfNetworkEvent(const char* aTopic, const char16_t* aData) {
    LOGD(("NotifyOfNetworkEvent: (%s, %s) | nScanResults: %u", aTopic,
          NS_ConvertUTF16toUTF8(aData).get(), gNumScanResults));
    EXPECT_TRUE(NS_SUCCEEDED(mObs->NotifyObservers(nullptr, aTopic, aData)));
    WaitForScanResults();
  }

  void StopWatching() {
    LOGD(("StopWatching | nScanResults: %u", gNumScanResults));
    EXPECT_TRUE(NS_SUCCEEDED(mWifiMonitor->StopWatching(mWifiListener)));
    WaitForScanResults();
  }

  struct MockCallSequences {
    Sequence mGetAccessPointsSeq;
    Sequence mOnChangeSeq;
    Sequence mOnErrorSeq;
  };

  void AddMockObjectChecks(const Cardinality& aScanCardinality,
                           MockCallSequences& aSeqs) {
    // Only add WillRepeatedly handler if scans is more than 0, to avoid a
    // VERY LOUD gtest warning.
    if (aScanCardinality.IsSaturatedByCallCount(0)) {
      EXPECT_CALL(
          *static_cast<MockWifiScanner*>(mWifiMonitor->mWifiScanner.get()),
          GetAccessPointsFromWLAN)
          .Times(aScanCardinality)
          .InSequence(aSeqs.mGetAccessPointsSeq);

      EXPECT_CALL(*mWifiListener, OnChange)
          .Times(aScanCardinality)
          .InSequence(aSeqs.mOnChangeSeq);
    } else {
      EXPECT_CALL(
          *static_cast<MockWifiScanner*>(mWifiMonitor->mWifiScanner.get()),
          GetAccessPointsFromWLAN)
          .Times(aScanCardinality)
          .InSequence(aSeqs.mGetAccessPointsSeq)
          .WillRepeatedly(
              [](nsTArray<RefPtr<nsIWifiAccessPoint>>& aAccessPoints) {
                EXPECT_TRUE(!NS_IsMainThread());
                EXPECT_TRUE(aAccessPoints.IsEmpty());
                nsWifiAccessPoint* ap = new nsWifiAccessPoint();
                // Signal will be unique so we won't match the prior access
                // point list.
                ap->mSignal = gCurrentId++;
                aAccessPoints.AppendElement(RefPtr(ap));
                return NS_OK;
              });

      EXPECT_CALL(*mWifiListener, OnChange)
          .Times(aScanCardinality)
          .InSequence(aSeqs.mOnChangeSeq)
          .WillRepeatedly(
              [](const nsTArray<RefPtr<nsIWifiAccessPoint>>& aAccessPoints) {
                EXPECT_TRUE(NS_IsMainThread());
                EXPECT_EQ(aAccessPoints.Length(), 1u);
                ++gNumScanResults;
                return NS_OK;
              });
    }

    EXPECT_CALL(*mWifiListener, OnError).Times(0).InSequence(aSeqs.mOnErrorSeq);
  }

  void AddStartWatchingCheck(bool aShouldPoll, MockCallSequences& aSeqs) {
    AddMockObjectChecks(aShouldPoll ? AtLeast(1) : Exactly(1), aSeqs);
  }

  void AddNetworkEventCheck(const Cardinality& aScanCardinality,
                            MockCallSequences& aSeqs) {
    AddMockObjectChecks(aScanCardinality, aSeqs);
  }

  void AddStopWatchingCheck(bool aShouldPoll, MockCallSequences& aSeqs) {
    // When polling, we may get stray scan + OnChange calls asynchronously
    // before stopping.  We may also get scan calls after stopping.
    // We check that the calls actually stopped in ConfirmStoppedCheck.
    AddMockObjectChecks(aShouldPoll ? AtLeast(0) : Exactly(0), aSeqs);
  }

  void AddConfirmStoppedCheck(MockCallSequences& aSeqs) {
    AddMockObjectChecks(Exactly(0), aSeqs);
  }

  // A Checkpoint is just a mocked function taking an int.  It will serve
  // as a temporal barrier that requires all expectations before it to be
  // satisfied and retired (meaning they won't be used in matches anymore).
  class Checkpoint {
   public:
    void Check(uint32_t aId, MockCallSequences& aSeqs) {
      EXPECT_CALL(mFn, Call(aId))
          .InSequence(aSeqs.mGetAccessPointsSeq, aSeqs.mOnChangeSeq,
                      aSeqs.mOnErrorSeq);
    }

    void Reach(uint32_t aId) { mFn.Call(aId); }

   private:
    MockFunction<void(uint32_t)> mFn;
  };

  // A single test is StartWatching, NotifyOfNetworkEvent, and StopWatching.
  void RunSingleTest(bool aRequestPolling, bool aShouldPoll,
                     const Cardinality& aScanCardinality, const char* aTopic,
                     const char16_t* aData) {
    LOGI(("RunSingleTest: <%s, %s> | requestPolling: %s | shouldPoll: %s",
          aTopic, NS_ConvertUTF16toUTF8(aData).get(),
          aRequestPolling ? "true" : "false", aShouldPoll ? "true" : "false"));
    MOZ_RELEASE_ASSERT(aShouldPoll || !aRequestPolling);

    CreateObjects();

    Checkpoint checkpoint;
    {
      // gmock expectations are asynchronous by default.  Sequence objects
      // are used here to require that expectations occur in the specified
      // (partial) order.
      MockCallSequences seqs;

      AddStartWatchingCheck(aShouldPoll, seqs);
      checkpoint.Check(1, seqs);

      AddNetworkEventCheck(aScanCardinality, seqs);
      checkpoint.Check(2, seqs);

      AddStopWatchingCheck(aShouldPoll, seqs);
      checkpoint.Check(3, seqs);

      AddConfirmStoppedCheck(seqs);
    }

    // Now run the test on the mock objects.
    StartWatching(aRequestPolling);
    checkpoint.Reach(1);
    EXPECT_EQ(mWifiMonitor->IsPolling(), aRequestPolling);

    NotifyOfNetworkEvent(aTopic, aData);
    checkpoint.Reach(2);
    EXPECT_EQ(mWifiMonitor->IsPolling(), aShouldPoll);

    StopWatching();
    checkpoint.Reach(3);
    EXPECT_TRUE(!mWifiMonitor->IsPolling());

    // Wait for extraneous calls as a way to confirm it has stopped.
    WaitForScanResults();

    DestroyObjects();
  }

  void CheckMessages(bool aRequestPolling) {
    // NS_NETWORK_LINK_TOPIC messages should cause a new scan.
    const char* kLinkTopicDatas[] = {
        NS_NETWORK_LINK_DATA_UP, NS_NETWORK_LINK_DATA_DOWN,
        NS_NETWORK_LINK_DATA_CHANGED, NS_NETWORK_LINK_DATA_UNKNOWN};

    for (const auto& data : kLinkTopicDatas) {
      RunSingleTest(aRequestPolling, aRequestPolling,
                    aRequestPolling ? AtLeast(2) : Exactly(1),
                    NS_NETWORK_LINK_TOPIC, NS_ConvertUTF8toUTF16(data).get());
    }

    // NS_NETWORK_LINK_TYPE_TOPIC should cause wifi scan polling iff the topic
    // says we have switched to a mobile network (LINK_TYPE_MOBILE or
    // LINK_TYPE_WIMAX) or we are polling the wifi-scanner (aShouldPoll).
    const LinkTypeMobility kLinkTypeTopicDatas[] = {
        {NS_NETWORK_LINK_TYPE_UNKNOWN, true /* mIsMobile */},
        {NS_NETWORK_LINK_TYPE_ETHERNET, false},
        {NS_NETWORK_LINK_TYPE_USB, false},
        {NS_NETWORK_LINK_TYPE_WIFI, false},
        {NS_NETWORK_LINK_TYPE_WIMAX, true},
        {NS_NETWORK_LINK_TYPE_MOBILE, true}};

    for (const auto& data : kLinkTypeTopicDatas) {
      bool shouldPoll = (aRequestPolling || data.mIsMobile);
      RunSingleTest(aRequestPolling, shouldPoll,
                    shouldPoll ? AtLeast(2) : Exactly(0),
                    NS_NETWORK_LINK_TYPE_TOPIC,
                    NS_ConvertUTF8toUTF16(data.mLinkType).get());
    }
  }

  RefPtr<nsWifiMonitor> mWifiMonitor;
  nsCOMPtr<nsIObserverService> mObs;

  RefPtr<MockWifiListener> mWifiListener;

  int mOldScanInterval;
  uint32_t mOrigLinkType = 0;
  bool mOrigIsLinkUp = false;
  bool mOrigLinkStatusKnown = false;
};

TEST_F(TestWifiMonitor, WifiScanNoPolling) { CheckMessages(false); }

TEST_F(TestWifiMonitor, WifiScanPolling) { CheckMessages(true); }

}  // namespace mozilla

Messung V0.5
C=91 H=97 G=93

¤ Dauer der Verarbeitung: 0.31 Sekunden  (vorverarbeitet)  ¤

*© Formatika GbR, Deutschland






Wurzel

Suchen

Beweissystem der NASA

Beweissystem Isabelle

NIST Cobol Testsuite

Cephes Mathematical Library

Wiener Entwicklungsmethode

Haftungshinweis

Die Informationen auf dieser Webseite wurden nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit, noch Qualität der bereit gestellten Informationen zugesichert.

Bemerkung:

Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.