Closed Bug 902741 Opened 11 years ago Closed 11 years ago

[Test][System] Unit test for WiFi

Categories

(Firefox OS Graveyard :: Gaia::System, defect)

ARM
Gonk (Firefox OS)
defect
Not set
normal

Tracking

(Not tracked)

RESOLVED FIXED

People

(Reporter: alive, Assigned: chsienlee)

References

Details

Attachments

(1 file)

200 bytes, text/html
alive
: review+
Details
We need to test WifiManager in system.
Attached file pull-request
Attachment #793865 - Flags: review?(alive)
Attachment #793865 - Attachment filename: file_902741.txt → file_902741.html
Attachment #793865 - Attachment mime type: text/plain → text/html
Comment on attachment 793865 [details]
pull-request

I'm writing down my expect in how to write tests for this module, and I expect you could find out the worthy-to-be-test part on your own afterwards.

'use strict';

var Wifi = {
  wifiWakeLocked: false,

# Read the code below, this variable is sometimes true, sometimes to be false. What's the factor to cause this? Find out the possible cases to test Wifi.wifiWakeLocked is updated correctly.

  wifiEnabled: true,

# This one is the same.

  wifiDisabledByWakelock: false,

# The same

  // Without an wifi wake lock, wait for screenOffTimeout milliseconds
  // to turn wifi off after the conditions are met.
  // If it's set to 0, wifi will never be turn off.
  screenOffTimeout: 0,

  // if Wifi is enabled but disconnected, try to scan for networks every
  // kScanInterval ms.
  kScanInterval: 20 * 1000,

# this one seems like a constant. And it's not used anymore.

  _scanTimer: null,

# I don't know we should test this or not so far. So keep it in mind.

  init: function wf_init() {
    if (!window.navigator.mozSettings)
      return;

    if (!window.navigator.mozWifiManager)
      return;

    window.addEventListener('screenchange', this);

# Testable point:
# Test Wifi.handleEvent({type: 'screenchange', detail: {....});

    var battery = window.navigator.battery;
    battery.addEventListener('chargingchange', this);

# Testable point:
# Test Wifi.handleEvent({type: 'chargingchange', detail: {....});

    // If wifi is turned off by us and phone got rebooted,
    // bring wifi back.

# Another testable point, judge from this comment.
# So we need to test wifi is turned on again if (1) rebooted and (2) turned off by wifi module ourself.

    var name = 'wifi.disabled_by_wakelock';
    var req = SettingsListener.getSettingsLock().get(name);
    req.onsuccess = function gotWifiDisabledByWakelock() {
      if (!req.result[name])
        return;

      // Re-enable wifi and reset wifi.disabled_by_wakelock
      // SettingsListener.getSettingsLock() always return invalid lock
      // in our usage here.
      // See https://bugzilla.mozilla.org/show_bug.cgi?id=793239
      var lock = navigator.mozSettings.createLock();
      lock.set({ 'wifi.enabled': true });
      lock.set({ 'wifi.disabled_by_wakelock': false });
    };

    var self = this;
    var wifiManager = window.navigator.mozWifiManager;
    // when wifi is really enabled, emit event to notify QuickSettings
    wifiManager.onenabled = function onWifiEnabled() {
      var evt = document.createEvent('CustomEvent');
      evt.initCustomEvent('wifi-enabled',
        /* canBubble */ true, /* cancelable */ false, null);
      window.dispatchEvent(evt);
    };

## Test event is dispatched or not by stub WifiManager.
## **If** window.addEventListener is not usable...(I encourage you to find out why), then stub 'window's dispatchEvent and test dispatchEvent is called with correct event.

    // when wifi is really disabled, emit event to notify QuickSettings
    wifiManager.ondisabled = function onWifiDisabled() {
      var evt = document.createEvent('CustomEvent');
      evt.initCustomEvent('wifi-disabled',
        /* canBubble */ true, /* cancelable */ false, null);
      window.dispatchEvent(evt);
    };

## The same as above.

    // when wifi status change, emit event to notify StatusBar/UpdateManager
    wifiManager.onstatuschange = function onWifiDisabled() {
      var evt = document.createEvent('CustomEvent');
      evt.initCustomEvent('wifi-statuschange',
        /* canBubble */ true, /* cancelable */ false, null);
      window.dispatchEvent(evt);
    };

# The same as above.

    SettingsListener.observe(
      'wifi.screen_off_timeout', 600000, function(value) {
        self.screenOffTimeout = value;
      });

# Do we need to test this? Should be.
# Use Fake SettingsListener to test Wifi.screenOffTimeout is updated or not.

    // Track the wifi.enabled mozSettings value
    SettingsListener.observe('wifi.enabled', true, function(value) {
      if (!wifiManager && value) {
        self.wifiEnabled = false;

        // roll back the setting value to notify the UIs
        // that wifi interface is not available
        if (value) {
          SettingsListener.getSettingsLock().set({
            'wifi.enabled': false
          });
        }

        return;
      }

# The same as above, use fake Settings Listener to test Wifi.wifiEnabled is updated or not. And test 'wifi.enable' is set or not by stuf SettingsListener.getSettingsLock().

      self.wifiEnabled = value;

      clearTimeout(self._scanTimer);
      if (!value)
        return;

      // If wifi is enabled but disconnected.
      // we would need to call getNetworks() continuously
      // so we could join known wifi network
      self._scanTimer = setInterval(function wifi_scan() {
        if (wifiManager.connection.status == 'disconnected')
          wifiManager.getNetworks();
      });

# Use stub to test wifiManager.getNetworks is called or not.
    });

    var power = navigator.mozPower;
    power.addWakeLockListener(function wifi_handleWakeLock(topic, state) {
      if (topic !== 'wifi')
        return;

      self.wifiWakeLocked = (state == 'locked-foreground' ||
                             state == 'locked-background');

      self.maybeToggleWifi();
    });

# Use mock mozPower to test the wake lock state.
  },

  handleEvent: function wifi_handleEvent(evt) {
    this.maybeToggleWifi();
  },

  // Check the status of screen, wifi wake lock and power source
  // and turn on/off wifi accordingly
  maybeToggleWifi: function wifi_maybeToggleWifi() {
    // Do nothing if we are being disabled.
    if (!this.screenOffTimeout)
      return;

    var battery = window.navigator.battery;
    var wifiManager = window.navigator.mozWifiManager;
    if (!battery || !wifiManager ||
        (!this.wifiEnabled && !this.wifiDisabledByWakelock))
      return;


    // Let's quietly turn off wifi if there is no wake lock and
    // the screen is off and we are not on a power source.
    if (!ScreenManager.screenEnabled &&
        !this.wifiWakeLocked && !battery.charging) {

# When you see |if| you shall know there're many cases could be tested here.
# Test ScreenManager.screenEnabled = true/false + this.wifiWakeLocked = true/false + battery.charging = true/false in different cases.

      // We don't need to do anything if wifi is not enabled currently
      if (!this.wifiEnabled)
        return;

# again another testable if. Test following is executed or not with different Wifi.wifiEnabled.

      // We still need to turn of wifi even if there is no Alarm API
      if (!navigator.mozAlarms) {
# Stub Wifi.sleep and test it's called or not by mock navigator.mozAlarms and set different value to it.
        console.warn('Turning off wifi without sleep timer because' +
          ' Alarm API is not available');
        this.sleep();

        return;
      }

      // Set System Message Handler, so we will be notified when alarm goes off.
      this.setSystemMessageHandler();

# Test setSystemMessageHandler is called or not.

      // Start with a timer, only turn off wifi till timeout.
      var date = new Date(Date.now() + this.screenOffTimeout);
      var self = this;
      var req = navigator.mozAlarms.add(date, 'ignoreTimezone', 'wifi-off');
      req.onsuccess = function wifi_offAlarmSet() {
        self._alarmId = req.result;
      };
      req.onerror = function wifi_offAlarmSetFailed() {
        console.warn('Fail to set wifi sleep timer on Alarm API. ' +
          'Turn off wifi immediately.');
        self.sleep();
      };
    }
    // ... and quietly turn it back on or cancel the timer otherwise
    else {
      if (this._alarmId) {
        navigator.mozAlarms.remove(this._alarmId);
        this._alarmId = null;
      }

      // If wifi is enabled but disconnected.
      // we would need to call getNetworks() so we could join known wifi network
      if (this.wifiEnabled && wifiManager.connection.status == 'disconnected') {
        wifiManager.getNetworks();
      }

# A little complicated but I think stub mozAlarm shall work. We could discuss how to write this if you cannot figure out anyway.

# Hello if!

      // We don't need to do anything if we didn't disable wifi at first place.
      if (!this.wifiDisabledByWakelock)
        return;

      var lock = SettingsListener.getSettingsLock();
      // turn wifi back on.
      lock.set({ 'wifi.enabled': true });

      this.wifiDisabledByWakelock = false;
      lock.set({ 'wifi.disabled_by_wakelock': false });
    }
  },

  // Quietly turn off wifi for real, set wifiDisabledByWakelock to true
  // so we will turn it back on.
  sleep: function wifi_sleep() {
    var lock = SettingsListener.getSettingsLock();

    // Actually turn off the wifi

    // The |sleep| might be triggered when an alarm comes.
    // If the CPU is in suspend mode at this moment, alarm servcie would wake
    // up the CPU to run the handler and turn it back to suspend immediately
    // |sleep| is finished. In this case, we acquire a CPU wake lock to prevent
    // the CPU goes to suspend mode before the switching is done.
    var wakeLockForWifi = navigator.requestWakeLock('cpu');
    lock.set({ 'wifi.enabled': false });
    window.addEventListener('wifi-disabled', function() {

# Use stub to mock window.addEventListener and use |stub.callsArg(index);| see http://sinonjs.org/docs/#stubs for reference.

      if (wakeLockForWifi) {

# Hello if. Stub window to set different value to it to see if wakeLockForWifi is unlocked.

        wakeLockForWifi.unlock();
        wakeLockForWifi = null;
      }
    });
    window.setTimeout(function() {
      if (wakeLockForWifi) {
        wakeLockForWifi.unlock();
        wakeLockForWifi = null;
      }
     }, 30000); //To prevent the CPU awake forever (if wifi cannot be disabled)

# See http://sinonjs.org/docs/#clock to use fake timer.

     // Remember that it was turned off by us.
     this.wifiDisabledByWakelock = true;

     // Keep this value in disk so if the phone reboots we'll
     // be able to turn the wifi back on.
     var wakeLockForSettings = navigator.requestWakeLock('cpu');

# stub is your best friend.

     var request = lock.set({ 'wifi.disabled_by_wakelock': true });
     request.onsuccess = function() { wakeLockForSettings.unlock() };
     request.onerror = request.onsuccess;

  },

  // Register for handling system message,
  // this cannot be done during |init()| because of bug 797803
  setSystemMessageHandler: function wifi_setSystemMessageHandler() {
    if (this._systemMessageHandlerRegistered)
      return;

    this._systemMessageHandlerRegistered = true;
    var self = this;
    navigator.mozSetMessageHandler('alarm', function gotAlarm(message) {

# Mock navigator.mozSetMessageHandler "and" fake message data to test sleep is called or not.

      if (message.data !== 'wifi-off')
        return;

      self.sleep();
    });
  }
};

Wifi.init();
Attachment #793865 - Flags: review?(alive)
ok, I will add lost testable point, and try to do my best, thank you.
Attachment #793865 - Flags: review?(alive)
Comment on attachment 793865 [details]
pull-request

r+ if you remove every typeof XXXX == 'function' test. It's meaningless. You shall always test things inside the function is done or not.

Thanks!
Attachment #793865 - Flags: review?(alive) → review+
Comment on attachment 793865 [details]
pull-request

Do you need my help to merge? Needinfo me when you're ready.
Hi! I have a small problem.
I tried some method, but I can't stub window.navigator.battery
When I assign a object to it, I got error message: setting a property that has only a getter
When I stub it with sinon, I got error message: Cannot stub non-existent own property battery
How can I solve dependency problem with window.navigator.battery
Attachment #793865 - Flags: review+ → review?(alive)
Comment on attachment 793865 [details]
pull-request

Please fix the misspelling words.
Attachment #793865 - Flags: review?(alive) → review+
https://github.com/mozilla-b2g/gaia/commit/15bdabeddd1b9356ff296a6550691c1427bf2589

\O/
Status: NEW → RESOLVED
Closed: 11 years ago
Resolution: --- → FIXED
You need to log in before you can comment on or make changes to this bug.

Attachment

General

Creator:
Created:
Updated:
Size: