<commit_before># Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import os

from telemetry import decorators

from telemetry.core import exceptions
from telemetry.core import forwarders
from telemetry.core import util
from telemetry.core.backends.chrome import chrome_browser_backend
from telemetry.core.forwarders import cros_forwarder

class CrOSBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
  # Some developers' workflow includes running the Chrome process from
  # /usr/local/... instead of the default location. We have to check for both
  # paths in order to support this workflow.
  CHROME_PATHS = ['/opt/google/chrome/chrome ',
                  '/usr/local/opt/google/chrome/chrome ']

  def __init__(self, browser_type, browser_options, cri, is_guest,
               extensions_to_load):
    super(CrOSBrowserBackend, self).__init__(
        is_content_shell=False, supports_extensions=not is_guest,
        browser_options=browser_options,
        output_profile_path=None, extensions_to_load=extensions_to_load)

    from telemetry.core.backends.chrome import chrome_browser_options
    assert isinstance(browser_options,
                      chrome_browser_options.CrosBrowserOptions)

    # Initialize fields so that an explosion during init doesn't break in Close.
    self._browser_type = browser_type
    self._cri = cri
    self._is_guest = is_guest
    self._forwarder = None

    self.wpr_port_pairs = forwarders.PortPairs(
        http=forwarders.PortPair(self.wpr_port_pairs.http.local_port,
                                 self._cri.GetRemotePort()),
        https=forwarders.PortPair(self.wpr_port_pairs.https.local_port,
                                  self._cri.GetRemotePort()),
        dns=None)
    self._remote_debugging_port = self._cri.GetRemotePort()
    self._port = self._remote_debugging_port

    self._SetBranchNumber(self._GetChromeVersion())

    self._login_ext_dir = None
    if not self._use_oobe_login_for_testing:
      self._login_ext_dir = os.path.join(os.path.dirname(__file__),
                                         'chromeos_login_ext')

      # Push a dummy login extension to the device.
      # This extension automatically logs in test user specified by
      # self.browser_options.username.
      # Note that we also perform this copy locally to ensure that
      # the owner of the extensions is set to chronos.
      logging.info('Copying dummy login extension to the device')
      cri.PushFile(self._login_ext_dir, '/tmp/')
      self._login_ext_dir = '/tmp/chromeos_login_ext'
      cri.Chown(self._login_ext_dir)

    # Copy extensions to temp directories on the device.
    # Note that we also perform this copy locally to ensure that
    # the owner of the extensions is set to chronos.
    for e in extensions_to_load:
      output = cri.RunCmdOnDevice(['mktemp', '-d', '/tmp/extension_XXXXX'])
      extension_dir = output[0].rstrip()
      cri.PushFile(e.path, extension_dir)
      cri.Chown(extension_dir)
      e.local_path = os.path.join(extension_dir, os.path.basename(e.path))

    # Ensure the UI is running and logged out.
    self._RestartUI()
    util.WaitFor(self.IsBrowserRunning, 20)

    # Delete test user's cryptohome vault (user data directory).
    if not self.browser_options.dont_override_profile:
      self._cri.RunCmdOnDevice(['cryptohome', '--action=remove', '--force',
                                '--user=%s' % self.browser_options.username])
    if self.browser_options.profile_dir:
      cri.RmRF(self.profile_directory)
      cri.PushFile(self.browser_options.profile_dir + '/Default',
                   self.profile_directory)
      cri.Chown(self.profile_directory)

  def GetBrowserStartupArgs(self):
    args = super(CrOSBrowserBackend, self).GetBrowserStartupArgs()
    args.extend([
            '--enable-smooth-scrolling',
            '--enable-threaded-compositing',
            '--enable-per-tile-painting',
            '--force-compositing-mode',
            # Disables the start page, as well as other external apps that can
            # steal focus or make measurements inconsistent.
            '--disable-default-apps',
            # Skip user image selection screen, and post login screens.
            '--oobe-skip-postlogin',
            # Allow devtools to connect to chrome.
            '--remote-debugging-port=%i' % self._remote_debugging_port,
            # Open a maximized window.
            '--start-maximized',
            # TODO(achuith): Re-enable this flag again before multi-profiles
            # will become enabled by default to have telemetry mileage on it.
            # '--multi-profiles',
            # Debug logging for login flake (crbug.com/263527).
            '--vmodule=*/browser/automation/*=2,*/chromeos/net/*=2,'
                '*/chromeos/login/*=2,*/extensions/*=2,'
                '*/device_policy_decoder_chromeos.cc=2'])

    if self._is_guest:
      args.extend([
          # Jump to the login screen, skipping network selection, eula, etc.
          '--login-screen=login',
          # Skip hwid check, for VMs and pre-MP lab devices.
          '--skip-hwid-check'
      ])
    elif not self._use_oobe_login_for_testing:
      # This extension bypasses gaia and logs us in.
      logging.info('Using --auth-ext-path=%s to login', self._login_ext_dir)
      args.append('--auth-ext-path=%s' % self._login_ext_dir)

    return args

  def _GetSessionManagerPid(self, procs):
    """Returns the pid of the session_manager process, given the list of
    processes."""
    for pid, process, _, _ in procs:
      if process.startswith('/sbin/session_manager '):
        return pid
    return None

  def _GetChromeProcess(self):
    """Locates the the main chrome browser process.

    Chrome on cros is usually in /opt/google/chrome, but could be in
    /usr/local/ for developer workflows - debug chrome is too large to fit on
    rootfs.

    Chrome spawns multiple processes for renderers. pids wrap around after they
    are exhausted so looking for the smallest pid is not always correct. We
    locate the session_manager's pid, and look for the chrome process that's an
    immediate child. This is the main browser process.
    """
    procs = self._cri.ListProcesses()
    session_manager_pid = self._GetSessionManagerPid(procs)
    if not session_manager_pid:
      return None

    # Find the chrome process that is the child of the session_manager.
    for pid, process, ppid, _ in procs:
      if ppid != session_manager_pid:
        continue
      for path in self.CHROME_PATHS:
        if process.startswith(path):
          return {'pid': pid, 'path': path, 'args': process}
    return None

  def _GetChromeVersion(self):
    result = util.WaitFor(self._GetChromeProcess, timeout=30)
    assert result and result['path']
    (version, _) = self._cri.RunCmdOnDevice([result['path'], '--version'])
    assert version
    return version

  @property
  def pid(self):
    result = self._GetChromeProcess()
    if result and 'pid' in result:
      return result['pid']
    return None

  @property
  def browser_directory(self):
    result = self._GetChromeProcess()
    if result and 'path' in result:
      return os.path.dirname(result['path'])
    return None

  @property
  def profile_directory(self):
    return '/home/chronos/Default'

  @property
  def hwid(self):
    return self._cri.RunCmdOnDevice(['/usr/bin/crossystem', 'hwid'])[0]

  @property
  def _use_oobe_login_for_testing(self):
    """Oobe.LoginForTesting was introduced after branch 1599."""
    return self.chrome_branch_number > 1599

  def GetRemotePort(self, port):
    if self._cri.local:
      return port
    return self._cri.GetRemotePort()

  def __del__(self):
    self.Close()

  def Start(self):
    # Escape all commas in the startup arguments we pass to Chrome
    # because dbus-send delimits array elements by commas
    startup_args = [a.replace(',', '\\,') for a in self.GetBrowserStartupArgs()]

    # Restart Chrome with the login extension and remote debugging.
    logging.info('Restarting Chrome with flags and login')
    args = ['dbus-send', '--system', '--type=method_call',
            '--dest=org.chromium.SessionManager',
            '/org/chromium/SessionManager',
            'org.chromium.SessionManagerInterface.EnableChromeTesting',
            'boolean:true',
            'array:string:"%s"' % ','.join(startup_args)]
    self._cri.RunCmdOnDevice(args)

    if not self._cri.local:
      self._port = util.GetUnreservedAvailableLocalPort()
      self._forwarder = self.forwarder_factory.Create(
          forwarders.PortPairs(
              http=forwarders.PortPair(self._port, self._remote_debugging_port),
              https=None,
              dns=None), forwarding_flag='L')

    try:
      self._WaitForBrowserToComeUp(wait_for_extensions=False)
      self._PostBrowserStartupInitialization()
    except:
      import traceback
      traceback.print_exc()
      self.Close()
      raise

    # chrome_branch_number is set in _PostBrowserStartupInitialization.
    # Without --skip-hwid-check (introduced in crrev.com/203397), devices/VMs
    # will be stuck on the bad hwid screen.
    if self.chrome_branch_number <= 1500 and not self.hwid:
      raise exceptions.LoginException(
          'Hardware id not set on device/VM. --skip-hwid-check not supported '
          'with chrome branches 1500 or earlier.')

    util.WaitFor(lambda: self.oobe_exists, 10)

    if self.browser_options.auto_login:
      if self._is_guest:
        pid = self.pid
        self._NavigateGuestLogin()
        # Guest browsing shuts down the current browser and launches an
        # incognito browser in a separate process, which we need to wait for.
        util.WaitFor(lambda: pid != self.pid, 10)
        self._WaitForBrowserToComeUp()
      else:
        self._NavigateLogin()

    logging.info('Browser is up!')

  def Close(self):
    super(CrOSBrowserBackend, self).Close()

    self._RestartUI() # Logs out.

    if self._forwarder:
      self._forwarder.Close()
      self._forwarder = None

    if self._login_ext_dir:
      self._cri.RmRF(self._login_ext_dir)
      self._login_ext_dir = None

    if self._cri:
      for e in self._extensions_to_load:
        self._cri.RmRF(os.path.dirname(e.local_path))

    self._cri = None

  @property
  @decorators.Cache
  def forwarder_factory(self):
    return cros_forwarder.CrOsForwarderFactory(self._cri)

  def IsBrowserRunning(self):
    return bool(self.pid)

  def GetStandardOutput(self):
    return 'Cannot get standard output on CrOS'

  def GetStackTrace(self):
    return 'Cannot get stack trace on CrOS'

  def _RestartUI(self):
    if self._cri:
      logging.info('(Re)starting the ui (logs the user out)')
      if self._cri.IsServiceRunning('ui'):
        self._cri.RunCmdOnDevice(['restart', 'ui'])
      else:
        self._cri.RunCmdOnDevice(['start', 'ui'])

  @property
  def oobe(self):
    return self.misc_web_contents_backend.GetOobe()

  @property
  def oobe_exists(self):
    return self.misc_web_contents_backend.oobe_exists

  def _SigninUIState(self):
    """Returns the signin ui state of the oobe. HIDDEN: 0, GAIA_SIGNIN: 1,
    ACCOUNT_PICKER: 2, WRONG_HWID_WARNING: 3, MANAGED_USER_CREATION_FLOW: 4.
    These values are in
    chrome/browser/resources/chromeos/login/display_manager.js
    """
    return self.oobe.EvaluateJavaScript('''
      loginHeader = document.getElementById('login-header-bar')
      if (loginHeader) {
        loginHeader.signinUIState_;
      }
    ''')

  def _HandleUserImageSelectionScreen(self):
    """If we're stuck on the user image selection screen, we click the ok
    button.
    """
    oobe = self.oobe
    if oobe:
      try:
        oobe.EvaluateJavaScript("""
            var ok = document.getElementById("ok-button");
            if (ok) {
              ok.click();
            }
        """)
      except (exceptions.TabCrashException):
        pass

  def _IsLoggedIn(self):
    """Returns True if we're logged in (cryptohome has mounted), and the oobe
    has been dismissed."""
    if self.chrome_branch_number <= 1547:
      self._HandleUserImageSelectionScreen()
    return (self._cri.IsCryptohomeMounted(self.browser_options.username) and
            not self.oobe_exists)

  def _StartupWindow(self):
    """Closes the startup window, which is an extension on official builds,
    and a webpage on chromiumos"""
    startup_window_ext_id = 'honijodknafkokifofgiaalefdiedpko'
    return (self.extension_backend[startup_window_ext_id]
        if startup_window_ext_id in self.extension_backend
        else self.tab_list_backend.Get(0, None))

  def _WaitForSigninScreen(self):
    """Waits for oobe to be on the signin or account picker screen."""
    def OnAccountPickerScreen():
      signin_state = self._SigninUIState()
      # GAIA_SIGNIN or ACCOUNT_PICKER screens.
      return signin_state == 1 or signin_state == 2
    try:
      util.WaitFor(OnAccountPickerScreen, 60)
    except util.TimeoutException:
      self._cri.TakeScreenShot('guest-screen')
      raise exceptions.LoginException('Timed out waiting for signin screen, '
                                      'signin state %d' % self._SigninUIState())

  def _ClickBrowseAsGuest(self):
    """Click the Browse As Guest button on the account picker screen. This will
    restart the browser, and we could have a tab crash or a browser crash."""
    try:
      self.oobe.EvaluateJavaScript("""
          var guest = document.getElementById("guest-user-button");
          if (guest) {
            guest.click();
          }
      """)
    except (exceptions.TabCrashException,
            exceptions.BrowserConnectionGoneException):
      pass

  def _WaitForGuestFsMounted(self):
    """Waits for the guest user to be mounted as guestfs"""
    guest_path = self._cri.CryptohomePath('$guest')
    util.WaitFor(lambda: (self._cri.FilesystemMountedAt(guest_path) ==
                          'guestfs'), 20)

  def _NavigateGuestLogin(self):
    """Navigates through oobe login screen as guest"""
    if not self.oobe_exists:
      raise exceptions.LoginException('Oobe missing')
    self._WaitForSigninScreen()
    self._ClickBrowseAsGuest()
    self._WaitForGuestFsMounted()

  def _NavigateLogin(self):
    """Navigates through oobe login screen"""
    if self._use_oobe_login_for_testing:
      logging.info('Invoking Oobe.loginForTesting')
      if not self.oobe_exists:
        raise exceptions.LoginException('Oobe missing')
      oobe = self.oobe
      util.WaitFor(lambda: oobe.EvaluateJavaScript(
          'typeof Oobe !== \'undefined\''), 10)

      if oobe.EvaluateJavaScript(
          'typeof Oobe.loginForTesting == \'undefined\''):
        raise exceptions.LoginException('Oobe.loginForTesting js api missing')

      oobe.ExecuteJavaScript(
          'Oobe.loginForTesting(\'%s\', \'%s\');'
              % (self.browser_options.username, self.browser_options.password))

    try:
      util.WaitFor(self._IsLoggedIn, 60)
    except util.TimeoutException:
      self._cri.TakeScreenShot('login-screen')
      raise exceptions.LoginException('Timed out going through login screen')

    # Wait for extensions to load.
    try:
      self._WaitForBrowserToComeUp()
    except util.TimeoutException:
      logging.error('Chrome args: %s' % self._GetChromeProcess()['args'])
      self._cri.TakeScreenShot('extension-timeout')
      raise

    if self.chrome_branch_number < 1500:
      # Wait for the startup window, then close it. Startup window doesn't exist
      # post-M27. crrev.com/197900
      util.WaitFor(self._StartupWindow, 20).Close()
    else:
      # Workaround for crbug.com/329271, crbug.com/334726.
      retries = 3
      while not len(self.tab_list_backend):
        try:
          # Open a new window/tab.
          tab = self.tab_list_backend.New(timeout=30)
          tab.Navigate('about:blank', timeout=10)
        except (exceptions.TabCrashException, util.TimeoutException,
                IndexError):
          retries -= 1
          logging.warn('TabCrashException/TimeoutException in '
                       'new tab creation/navigation, '
                       'remaining retries %d' % retries)
          if not retries:
            raise
<commit_msg>Remove support for old (pre-M32) versions of chrome.<commit_after># Copyright 2013 The Chromium Authors. All rights reserved.
# Use of this source code is governed by a BSD-style license that can be
# found in the LICENSE file.

import logging
import os

from telemetry import decorators

from telemetry.core import exceptions
from telemetry.core import forwarders
from telemetry.core import util
from telemetry.core.backends.chrome import chrome_browser_backend
from telemetry.core.forwarders import cros_forwarder

class CrOSBrowserBackend(chrome_browser_backend.ChromeBrowserBackend):
  # Some developers' workflow includes running the Chrome process from
  # /usr/local/... instead of the default location. We have to check for both
  # paths in order to support this workflow.
  CHROME_PATHS = ['/opt/google/chrome/chrome ',
                  '/usr/local/opt/google/chrome/chrome ']

  def __init__(self, browser_type, browser_options, cri, is_guest,
               extensions_to_load):
    super(CrOSBrowserBackend, self).__init__(
        is_content_shell=False, supports_extensions=not is_guest,
        browser_options=browser_options,
        output_profile_path=None, extensions_to_load=extensions_to_load)

    from telemetry.core.backends.chrome import chrome_browser_options
    assert isinstance(browser_options,
                      chrome_browser_options.CrosBrowserOptions)

    # Initialize fields so that an explosion during init doesn't break in Close.
    self._browser_type = browser_type
    self._cri = cri
    self._is_guest = is_guest
    self._forwarder = None

    self.wpr_port_pairs = forwarders.PortPairs(
        http=forwarders.PortPair(self.wpr_port_pairs.http.local_port,
                                 self._cri.GetRemotePort()),
        https=forwarders.PortPair(self.wpr_port_pairs.https.local_port,
                                  self._cri.GetRemotePort()),
        dns=None)
    self._remote_debugging_port = self._cri.GetRemotePort()
    self._port = self._remote_debugging_port

    self._SetBranchNumber(self._GetChromeVersion())

    # Copy extensions to temp directories on the device.
    # Note that we also perform this copy locally to ensure that
    # the owner of the extensions is set to chronos.
    for e in extensions_to_load:
      output = cri.RunCmdOnDevice(['mktemp', '-d', '/tmp/extension_XXXXX'])
      extension_dir = output[0].rstrip()
      cri.PushFile(e.path, extension_dir)
      cri.Chown(extension_dir)
      e.local_path = os.path.join(extension_dir, os.path.basename(e.path))

    # Ensure the UI is running and logged out.
    self._RestartUI()
    util.WaitFor(self.IsBrowserRunning, 20)

    # Delete test user's cryptohome vault (user data directory).
    if not self.browser_options.dont_override_profile:
      self._cri.RunCmdOnDevice(['cryptohome', '--action=remove', '--force',
                                '--user=%s' % self.browser_options.username])
    if self.browser_options.profile_dir:
      cri.RmRF(self.profile_directory)
      cri.PushFile(self.browser_options.profile_dir + '/Default',
                   self.profile_directory)
      cri.Chown(self.profile_directory)

  def GetBrowserStartupArgs(self):
    args = super(CrOSBrowserBackend, self).GetBrowserStartupArgs()
    args.extend([
            '--enable-smooth-scrolling',
            '--enable-threaded-compositing',
            '--enable-per-tile-painting',
            '--force-compositing-mode',
            # Disables the start page, as well as other external apps that can
            # steal focus or make measurements inconsistent.
            '--disable-default-apps',
            # Skip user image selection screen, and post login screens.
            '--oobe-skip-postlogin',
            # Allow devtools to connect to chrome.
            '--remote-debugging-port=%i' % self._remote_debugging_port,
            # Open a maximized window.
            '--start-maximized',
            # TODO(achuith): Re-enable this flag again before multi-profiles
            # will become enabled by default to have telemetry mileage on it.
            # '--multi-profiles',
            # Debug logging for login flake (crbug.com/263527).
            '--vmodule=*/browser/automation/*=2,*/chromeos/net/*=2,'
                '*/chromeos/login/*=2,*/extensions/*=2,'
                '*/device_policy_decoder_chromeos.cc=2'])

    if self._is_guest:
      args.extend([
          # Jump to the login screen, skipping network selection, eula, etc.
          '--login-screen=login',
          # Skip hwid check, for VMs and pre-MP lab devices.
          '--skip-hwid-check'
      ])
    return args

  def _GetSessionManagerPid(self, procs):
    """Returns the pid of the session_manager process, given the list of
    processes."""
    for pid, process, _, _ in procs:
      if process.startswith('/sbin/session_manager '):
        return pid
    return None

  def _GetChromeProcess(self):
    """Locates the the main chrome browser process.

    Chrome on cros is usually in /opt/google/chrome, but could be in
    /usr/local/ for developer workflows - debug chrome is too large to fit on
    rootfs.

    Chrome spawns multiple processes for renderers. pids wrap around after they
    are exhausted so looking for the smallest pid is not always correct. We
    locate the session_manager's pid, and look for the chrome process that's an
    immediate child. This is the main browser process.
    """
    procs = self._cri.ListProcesses()
    session_manager_pid = self._GetSessionManagerPid(procs)
    if not session_manager_pid:
      return None

    # Find the chrome process that is the child of the session_manager.
    for pid, process, ppid, _ in procs:
      if ppid != session_manager_pid:
        continue
      for path in self.CHROME_PATHS:
        if process.startswith(path):
          return {'pid': pid, 'path': path, 'args': process}
    return None

  def _GetChromeVersion(self):
    result = util.WaitFor(self._GetChromeProcess, timeout=30)
    assert result and result['path']
    (version, _) = self._cri.RunCmdOnDevice([result['path'], '--version'])
    assert version
    return version

  @property
  def pid(self):
    result = self._GetChromeProcess()
    if result and 'pid' in result:
      return result['pid']
    return None

  @property
  def browser_directory(self):
    result = self._GetChromeProcess()
    if result and 'path' in result:
      return os.path.dirname(result['path'])
    return None

  @property
  def profile_directory(self):
    return '/home/chronos/Default'

  def GetRemotePort(self, port):
    if self._cri.local:
      return port
    return self._cri.GetRemotePort()

  def __del__(self):
    self.Close()

  def Start(self):
    # Escape all commas in the startup arguments we pass to Chrome
    # because dbus-send delimits array elements by commas
    startup_args = [a.replace(',', '\\,') for a in self.GetBrowserStartupArgs()]

    # Restart Chrome with the login extension and remote debugging.
    logging.info('Restarting Chrome with flags and login')
    args = ['dbus-send', '--system', '--type=method_call',
            '--dest=org.chromium.SessionManager',
            '/org/chromium/SessionManager',
            'org.chromium.SessionManagerInterface.EnableChromeTesting',
            'boolean:true',
            'array:string:"%s"' % ','.join(startup_args)]
    self._cri.RunCmdOnDevice(args)

    if not self._cri.local:
      self._port = util.GetUnreservedAvailableLocalPort()
      self._forwarder = self.forwarder_factory.Create(
          forwarders.PortPairs(
              http=forwarders.PortPair(self._port, self._remote_debugging_port),
              https=None,
              dns=None), forwarding_flag='L')

    try:
      self._WaitForBrowserToComeUp(wait_for_extensions=False)
      self._PostBrowserStartupInitialization()
    except:
      import traceback
      traceback.print_exc()
      self.Close()
      raise

    util.WaitFor(lambda: self.oobe_exists, 10)

    if self.browser_options.auto_login:
      if self._is_guest:
        pid = self.pid
        self._NavigateGuestLogin()
        # Guest browsing shuts down the current browser and launches an
        # incognito browser in a separate process, which we need to wait for.
        util.WaitFor(lambda: pid != self.pid, 10)
        self._WaitForBrowserToComeUp()
      else:
        self._NavigateLogin()

    logging.info('Browser is up!')

  def Close(self):
    super(CrOSBrowserBackend, self).Close()

    self._RestartUI() # Logs out.

    if self._forwarder:
      self._forwarder.Close()
      self._forwarder = None

    if self._cri:
      for e in self._extensions_to_load:
        self._cri.RmRF(os.path.dirname(e.local_path))

    self._cri = None

  @property
  @decorators.Cache
  def forwarder_factory(self):
    return cros_forwarder.CrOsForwarderFactory(self._cri)

  def IsBrowserRunning(self):
    return bool(self.pid)

  def GetStandardOutput(self):
    return 'Cannot get standard output on CrOS'

  def GetStackTrace(self):
    return 'Cannot get stack trace on CrOS'

  def _RestartUI(self):
    if self._cri:
      logging.info('(Re)starting the ui (logs the user out)')
      if self._cri.IsServiceRunning('ui'):
        self._cri.RunCmdOnDevice(['restart', 'ui'])
      else:
        self._cri.RunCmdOnDevice(['start', 'ui'])

  @property
  def oobe(self):
    return self.misc_web_contents_backend.GetOobe()

  @property
  def oobe_exists(self):
    return self.misc_web_contents_backend.oobe_exists

  def _SigninUIState(self):
    """Returns the signin ui state of the oobe. HIDDEN: 0, GAIA_SIGNIN: 1,
    ACCOUNT_PICKER: 2, WRONG_HWID_WARNING: 3, MANAGED_USER_CREATION_FLOW: 4.
    These values are in
    chrome/browser/resources/chromeos/login/display_manager.js
    """
    return self.oobe.EvaluateJavaScript('''
      loginHeader = document.getElementById('login-header-bar')
      if (loginHeader) {
        loginHeader.signinUIState_;
      }
    ''')

  def _IsLoggedIn(self):
    """Returns True if we're logged in (cryptohome has mounted), and the oobe
    has been dismissed."""
    return (self._cri.IsCryptohomeMounted(self.browser_options.username) and
            not self.oobe_exists)

  def _WaitForSigninScreen(self):
    """Waits for oobe to be on the signin or account picker screen."""
    def OnAccountPickerScreen():
      signin_state = self._SigninUIState()
      # GAIA_SIGNIN or ACCOUNT_PICKER screens.
      return signin_state == 1 or signin_state == 2
    try:
      util.WaitFor(OnAccountPickerScreen, 60)
    except util.TimeoutException:
      self._cri.TakeScreenShot('guest-screen')
      raise exceptions.LoginException('Timed out waiting for signin screen, '
                                      'signin state %d' % self._SigninUIState())

  def _ClickBrowseAsGuest(self):
    """Click the Browse As Guest button on the account picker screen. This will
    restart the browser, and we could have a tab crash or a browser crash."""
    try:
      self.oobe.EvaluateJavaScript("""
          var guest = document.getElementById("guest-user-button");
          if (guest) {
            guest.click();
          }
      """)
    except (exceptions.TabCrashException,
            exceptions.BrowserConnectionGoneException):
      pass

  def _WaitForGuestFsMounted(self):
    """Waits for the guest user to be mounted as guestfs"""
    guest_path = self._cri.CryptohomePath('$guest')
    util.WaitFor(lambda: (self._cri.FilesystemMountedAt(guest_path) ==
                          'guestfs'), 20)

  def _NavigateGuestLogin(self):
    """Navigates through oobe login screen as guest"""
    if not self.oobe_exists:
      raise exceptions.LoginException('Oobe missing')
    self._WaitForSigninScreen()
    self._ClickBrowseAsGuest()
    self._WaitForGuestFsMounted()

  def _NavigateLogin(self):
    """Navigates through oobe login screen"""
    logging.info('Invoking Oobe.loginForTesting')
    if not self.oobe_exists:
      raise exceptions.LoginException('Oobe missing')
    oobe = self.oobe
    util.WaitFor(lambda: oobe.EvaluateJavaScript(
        'typeof Oobe !== \'undefined\''), 10)

    if oobe.EvaluateJavaScript(
        'typeof Oobe.loginForTesting == \'undefined\''):
      raise exceptions.LoginException('Oobe.loginForTesting js api missing')

    oobe.ExecuteJavaScript(
        'Oobe.loginForTesting(\'%s\', \'%s\');'
            % (self.browser_options.username, self.browser_options.password))

    try:
      util.WaitFor(self._IsLoggedIn, 60)
    except util.TimeoutException:
      self._cri.TakeScreenShot('login-screen')
      raise exceptions.LoginException('Timed out going through login screen')

    # Wait for extensions to load.
    try:
      self._WaitForBrowserToComeUp()
    except util.TimeoutException:
      logging.error('Chrome args: %s' % self._GetChromeProcess()['args'])
      self._cri.TakeScreenShot('extension-timeout')
      raise

    # Workaround for crbug.com/329271, crbug.com/334726.
    retries = 3
    while not len(self.tab_list_backend):
      try:
        # Open a new window/tab.
        tab = self.tab_list_backend.New(timeout=30)
        tab.Navigate('about:blank', timeout=10)
      except (exceptions.TabCrashException, util.TimeoutException,
              IndexError):
        retries -= 1
        logging.warn('TabCrashException/TimeoutException in '
                     'new tab creation/navigation, '
                     'remaining retries %d' % retries)
        if not retries:
          raise
<|endoftext|>


<commit_before># Copyright (C) 2017 Google Inc.
# Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>

"""Test Access Control List"""

from ggrc.models import all_models
from integration.ggrc import TestCase
from integration.ggrc.models import factories
from integration.ggrc.models.factories import random_str
from integration.ggrc.api_helper import Api

class TestAccessControlList(TestCase):
  """TestAccessControlList"""

  def setUp(self):
    super(TestAccessControlList, self).setUp()
    self.api = Api()
    self.person = factories.PersonFactory()
    self.control = factories.ControlFactory()
    self.acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.second_acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.acl = factories.AccessControlListFactory(
        object=self.control,
        ac_role_id=self.acr.id,
        person=self.person
    )

  def _acl_json(self, role_id, person_id):
    """Helper function for setting acl json"""
    return {
        "ac_role_id": role_id,
        "person": {
            "type": "Person",
            "id": person_id
        }
    }

  def test_object_roles(self):
    """Test if roles are fetched with the object"""
    id_, person_id = self.acr.id, self.person.id
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)

    assert "access_control_list" in response.json["control"], \
        "Access Control List not a property in {}".format(
            response.json["control"].keys())

    ac_list = response.json["control"]["access_control_list"]
    assert len(ac_list) == 1, "{}".format(len(ac_list))

    assert ac_list[0]["ac_role_id"] == id_, \
        "ac_role_id not properly set {}".format(ac_list[0].get("ac_role_id"))
    assert ac_list[0]["person"]["id"] == person_id, \
        "Person stub not properly set {}".format(ac_list[0]["person"])

  def test_post_object_roles(self):
    """Test if roles are stored correctly when POSTed with the object"""
    id_, person_id = self.acr.id, self.person.id
    title = random_str(prefix="Control - ")
    response = self.api.post(all_models.Control, {
        "control": {
            "title": title,
            "type": "Control",
            "context": None,
            "access_control_list": [
                self._acl_json(id_, person_id)
            ]
        },
    })
    assert response.status_code == 201, \
        "Control with acl not created successfully {}".format(response.status)

    acl = response.json["control"]["access_control_list"]
    assert len(acl) == 1, \
        "Access control list did not get saved {}".format(acl)

    assert acl[0]["id"] > 0, \
        "Acces control list did not set an id"

    assert acl[0]["ac_role_id"] == id_, \
        "Access control list does not include the saved role id"

    assert acl[0]["person"]["id"] == person_id, \
        "Access control list does not include person id"

  def test_put_object_roles(self):
    """Test if PUTing object roles saves them correctly"""
    id_2, person_id = self.second_acr.id, self.person.id

    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'].append(self._acl_json(id_2, person_id))
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 2, \
        "Access control list not correctly updated {}".format(acl)

  def test_put_removing_roles(self):
    """Test if PUTing an empty list removes object roles correct"""
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'] = []
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 0, \
        "Access control list not empty {}".format(acl)
<commit_msg>Fix method could be a function lint warning<commit_after># Copyright (C) 2017 Google Inc.
# Licensed under http://www.apache.org/licenses/LICENSE-2.0 <see LICENSE file>

"""Test Access Control List"""

from ggrc.models import all_models
from integration.ggrc import TestCase
from integration.ggrc.models import factories
from integration.ggrc.models.factories import random_str
from integration.ggrc.api_helper import Api

def _acl_json(role_id, person_id):
  """Helper function for setting acl json"""
  return {
      "ac_role_id": role_id,
      "person": {
          "type": "Person",
          "id": person_id
      }
  }

class TestAccessControlList(TestCase):
  """TestAccessControlList"""

  def setUp(self):
    super(TestAccessControlList, self).setUp()
    self.api = Api()
    self.person = factories.PersonFactory()
    self.control = factories.ControlFactory()
    self.acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.second_acr = factories.AccessControlRoleFactory(
        object_type="Control",
        read=True
    )
    self.acl = factories.AccessControlListFactory(
        object=self.control,
        ac_role_id=self.acr.id,
        person=self.person
    )

  def test_object_roles(self):
    """Test if roles are fetched with the object"""
    id_, person_id = self.acr.id, self.person.id
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)

    assert "access_control_list" in response.json["control"], \
        "Access Control List not a property in {}".format(
            response.json["control"].keys())

    ac_list = response.json["control"]["access_control_list"]
    assert len(ac_list) == 1, "{}".format(len(ac_list))

    assert ac_list[0]["ac_role_id"] == id_, \
        "ac_role_id not properly set {}".format(ac_list[0].get("ac_role_id"))
    assert ac_list[0]["person"]["id"] == person_id, \
        "Person stub not properly set {}".format(ac_list[0]["person"])

  def test_post_object_roles(self):
    """Test if roles are stored correctly when POSTed with the object"""
    id_, person_id = self.acr.id, self.person.id
    title = random_str(prefix="Control - ")
    response = self.api.post(all_models.Control, {
        "control": {
            "title": title,
            "type": "Control",
            "context": None,
            "access_control_list": [
                _acl_json(id_, person_id)
            ]
        },
    })
    assert response.status_code == 201, \
        "Control with acl not created successfully {}".format(response.status)

    acl = response.json["control"]["access_control_list"]
    assert len(acl) == 1, \
        "Access control list did not get saved {}".format(acl)

    assert acl[0]["id"] > 0, \
        "Acces control list did not set an id"

    assert acl[0]["ac_role_id"] == id_, \
        "Access control list does not include the saved role id"

    assert acl[0]["person"]["id"] == person_id, \
        "Access control list does not include person id"

  def test_put_object_roles(self):
    """Test if PUTing object roles saves them correctly"""
    id_2, person_id = self.second_acr.id, self.person.id

    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'].append(_acl_json(id_2, person_id))
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 2, \
        "Access control list not correctly updated {}".format(acl)

  def test_put_removing_roles(self):
    """Test if PUTing an empty list removes object roles correct"""
    response = self.api.get(all_models.Control, self.control.id)
    assert response.status_code == 200, \
        "Failed to fetch created control {}".format(response.status)
    control = response.json['control']
    control['access_control_list'] = []
    response = self.api.put(self.control, {"control": control})
    assert response.status_code == 200, \
        "PUTing control failed {}".format(response.status)
    acl = response.json['control']['access_control_list']
    assert len(acl) == 0, \
        "Access control list not empty {}".format(acl)
<|endoftext|>


<commit_before>from . import Storage

def test_contains(tmpdir):
    storage = Storage(str(tmpdir))
    name = "foo"
    # check if it is not there yet
    assert name not in storage
    with storage.create(name, 0) as item:
        # we just want it created, no need to write sth into it
        pass
    # check if it is there
    assert name in storage
    storage.remove(name)
    # check if it is gone
    assert name not in storage
<commit_msg>test for name iteration in storage<commit_after>from . import Storage

def test_contains(tmpdir):
    storage = Storage(str(tmpdir))
    name = "foo"
    # check if it is not there yet
    assert name not in storage
    with storage.create(name, 0) as item:
        # we just want it created, no need to write sth into it
        pass
    # check if it is there
    assert name in storage
    storage.remove(name)
    # check if it is gone
    assert name not in storage

def test_iter(tmpdir):
    storage = Storage(str(tmpdir))
    # nothing there yet
    assert list(storage) == []
    names = ["foo", "bar", "baz", ]
    for name in names:
        with storage.create(name, 0) as item:
            # we just want it created, no need to write sth into it
            pass
    assert set(list(storage)) == set(names)

<|endoftext|>


<commit_before># CB: this file is difficult to understand because it's been built up
# over a long time. Now that it's clearer what we want it to achieve,
# I could simplify it significantly.

# A complication is that as the buildbot setup has changed, the shell
# command that is checked for the timings has changed number. This
# means the timing data can change directory and filename. Therefore,
# this script cannot be used to get all historical data in one
# go. There's a MIN_BUILD variable that specifies the first build to
# check. That can be changed together with the filename_pattern
# variable to do chunks of the historical data, if desired. Once the
# script has processed data, it's stored in a pickle, so the data
# doesn't need to be retrieved again. As it is, we have a timings
# pickle on doozy that has quite a lot of historical data (i.e. I have
# changed MIN_BUILD and filename_pattern as time has gone on, to keep
# up to date with changes to the buildbot config).

import sys
import re
import pickle
from glob import glob

from sys import argv

#logfile = 'LOG'
script = "lissom_oo_or.ty"

# Replace this mechanism with bars under the x-axis, so that
# ranges can be annotated.
annotations = {
    (8100,66.5):((0,0),"A"),
    (8600,58):((0,4),"B"),
    (8250,53.5):((0,0),"C"),
    (8395,54.3):((20,-2),"D"),
    (8100,56.5):((-20,-2),"E"),
    (8425,55):((0,2),"F")
    }
# CB: the above's just approx for now; needs updating.

annotations_key = {'A':(0.0,'something'),
                   'B':(0.0,'something else'),
                   'C':(0.0,'another thing')}

# CB: in progress - obviously the page construction should
# be separated out, etc
def write_page():
    locn = "/home/ceball/buildbot/buildmaster/public_html/p/"
    imgfile = "lissom_oo_or_250_svnversion.png"

    key = "
"
    for k,v in annotations_key.items():
        key+="
%s	%s	%s
"%(k,v[0],v[1])
    key+="
"

    s = "

%s
"%(locn+imgfile,key)

    f = open(locn+"running.html",'w')
    f.write(s)
    f.close()

V=re.compile(r'[0-9]*-log')
def get_build_no(logfilename):
    return int(V.findall(logfilename)[0].rstrip('-log'))

def create_timings(i_am_sure=False):
    if i_am_sure:
        timings = {}
        f = open('/home/ceball/buildbot/timings.pkl','w')
        pickle.dump(timings,f,0)
        f.close()

def create_startups(i_am_sure=False):
    if i_am_sure:
        startups = {}
        f = open('/home/ceball/buildbot/startups.pkl','w')
        pickle.dump(startups,f,0)
        f.close()

def get_timings():
    f = open('/home/ceball/buildbot/timings.pkl')
    timings = pickle.load(f)
    f.close()
    return timings

def save_timings(timings):
    f = open('/home/ceball/buildbot/timings.pkl','w')
    pickle.dump(timings,f,0)
    f.close()

def get_startups():
    f = open('/home/ceball/buildbot/startups.pkl')
    startups = pickle.load(f)
    f.close()
    return startups

def save_startups(startups):
    f = open('/home/ceball/buildbot/startups.pkl','w')
    pickle.dump(startups,f,0)
    f.close()

# exclude these builds
exclusions = []
exclusions.append(153) # doc why this is excluded
exclusions.append(425) # ran with wrong no. of iterations

def get_date_version_time(logfile,timings=None,startups=None):

    build = get_build_no(logfile)

    f = open(logfile)
    all_lines = f.readlines()
    f.close()

    ok = ok2 = False

    datei=versioni=timingi=startupi=None

    i = 0;
    for line in all_lines:
        if line.find("Running at")>=0:

            datei=i
        elif line.find("svnversion")>=0:

            versioni=i
        elif line.startswith("[examples/%s]"%script):
            timingi=i

        elif line.find("[examples/%s startup]"%script)>=0:
            startupi=i

        elif line.find("Results from examples/%s have not changed."%script)>=0:
            ok2=True
        elif line.find('program finished')>=0:
            ok=True

        i+=1;

    if not ok:
        print "...build %s currently incomplete"%build
        return None

    if not ok2:
        print "...speed test invalid because results didn't match"
        if timings:
            timings[script][build] = None
        if startups:
            startups[script][build] = None
        return None

    if datei is None or versioni is None or timingi is None or startupi is None:
        print "...not all data available - build didn't complete?"
        if timings:
            timings[script][build] = None
        if startups:
            startups[script][build] = None
        return None

    datel= all_lines[datei]
    d=re.compile(r'at [0-9]*')
    date = float(d.findall(datel)[0][3::])

    versionl = all_lines[versioni]
    v=re.compile(r'n [0-9]*')
    version = int(v.findall(versionl)[0][2::])

    timel = all_lines[timingi]
    t=re.compile(r'Now: [0-9.]* ')
    start,stop = t.search(timel).span()
    timing = float(timel[start+5:stop-1])

    cpusel = all_lines[timingi+1]
    start,stop = cpusel.index('elapsed')+8,cpusel.index('%CPU')
    cpu_usage = float(cpusel[start:stop])

    startupl = all_lines[startupi]
    t=re.compile(r'Now: [0-9.]* ')
    start,stop = t.search(startupl).span()
    startup = float(startupl[start+5:stop-1])

    startcpusel = all_lines[startupi+1]

    try:
        start,stop = startcpusel.index('elapsed')+8,startcpusel.index('%CPU')
        startcpusage = float(startcpusel[start:stop])
    except ValueError:
        startcpusage = 99  # HACK: for cases where it's missing, assume 99!

    if timings:

        if cpu_usage>95:
            timings[script][build] = (date,version,timing,cpu_usage)
        else:
            print "...build %s had %s percent cpu during timing (not >95)"%(build,cpu_usage)
            timings[script][build] = None

    if startups:

        if startcpusage>95:
            startups[script][build] = (date,version,startup,startcpusage)
        else:
            print "...build %s had %s percent cpu during startup (not >95)"%(build,startcpusage)
            timings[script][build] = None

    return (build,date,version,timing,startup,cpu_usage)

MIN_BUILD=153 # where to start analysis
filename_pattern = '*-log-shell_3-stdio'
def update_timings(location="/home/ceball/buildbot/buildmaster/slow-tests_x86_ubuntu7.04/"):

    timings = get_timings()

    if script not in timings:
        timings[script]={}

    startups = get_startups()

    if script not in startups:
        startups[script]={}

    filenames = glob(location+filename_pattern)
    for filename in filenames:

        build = get_build_no(filename)

        if build>=MIN_BUILD:

	    do_timings=do_startups=False

            if build not in timings[script] and build not in exclusions:
                print "Adding timing for build...",build
		do_timings=True
            elif build in exclusions and build not in timings[script]:
                print "Build %s excluded; timing skipped."%build
                timings[script][build]=None

            if build not in startups[script] and build not in exclusions:
                print "Adding startup time for build...",build
            	do_startups=True
            elif build in exclusions and build not in startups[script]:
                print "Build %s excluded; startup timing skipped."%build
                startups[script][build]=None

	    if do_timings and do_startups:
                get_date_version_time(filename,timings,startups)
            if do_timings and not do_startups:
                get_date_version_time(filename,timings,None)
            if not do_timings and do_startups:
                get_date_version_time(filename,None,startups)

    save_timings(timings)
    save_startups(startups)
    #print timings

def plot_timings():
    timings=get_timings()
    t=timings['lissom_oo_or.ty']
    tytle="lissom_oo_or.ty, 250 iterations"
    filename="/home/ceball/buildbot/buildmaster/public_html/p/lissom_oo_or_250"
    plott(t,tytle,filename)

def plot_startups():
    timings=get_startups()
    t=timings['lissom_oo_or.ty']
    tytle="lissom_oo_or.ty, startup"
    filename="/home/ceball/buildbot/buildmaster/public_html/p/lissom_oo_or_startup"
    plott(t,tytle,filename)

import matplotlib;matplotlib.use('Agg')

def sgn(x):
    return +1 if x>=0.0 else -1

def plott(t,tytle,filename):

    from pylab import title,xlabel,ylabel,savefig,figure,annotate,figtext

    builds=[]
    versions=[]
    times=[]
    for build,data in t.items():
        if data is not None:
            builds.append(build)
            versions.append(data[1])
            times.append(data[2]*data[3]/99.0)

    from topo.commands.pylabplots import vectorplot
    figure()
    vectorplot(times,versions,style='bx')

    title(tytle)
    xlabel("svnversion")
    ylabel("time /s")

    for k,v in annotations.items():
        if v[0]==(0,0):
            arrowprops=None
        else:
            arrowprops={'width':0.25,'frac':0.05,'headwidth':5}

        #CEBALERT:necessary cos of bug in matplotlib where arrow can\t be vertical or horizontal?
        xshift=sgn(v[0][0])*max(abs(v[0][0]),0.01)
        yshift=sgn(v[0][1])*max(abs(v[0][1]),0.01)

        annotate(v[1],k,xytext=(k[0]+xshift,k[1]+yshift),arrowprops=arrowprops)

    savefig(filename+"_svnversion.png")

    figure()
    vectorplot(times,builds,style='bx')

    title("lissom_oo_or.ty, 250 iterations")
    xlabel("build")
    ylabel("time /s")

##     key = ""
##     for k,v in annotations_key.items():
##         key+="%s: %s\n"%(k,v)

##     figtext(0,0,key)

    savefig(filename+"_buildno.png")

## if __name__=='__main__':

##     if len(sys.argv)>1:
##         if sys.argv[1]=='update':
##             update_timings()
<commit_msg>Fixed error in path to image.<commit_after># CB: this file is difficult to understand because it's been built up
# over a long time. Now that it's clearer what we want it to achieve,
# I could simplify it significantly.

# A complication is that as the buildbot setup has changed, the shell
# command that is checked for the timings has changed number. This
# means the timing data can change directory and filename. Therefore,
# this script cannot be used to get all historical data in one
# go. There's a MIN_BUILD variable that specifies the first build to
# check. That can be changed together with the filename_pattern
# variable to do chunks of the historical data, if desired. Once the
# script has processed data, it's stored in a pickle, so the data
# doesn't need to be retrieved again. As it is, we have a timings
# pickle on doozy that has quite a lot of historical data (i.e. I have
# changed MIN_BUILD and filename_pattern as time has gone on, to keep
# up to date with changes to the buildbot config).

import sys
import re
import pickle
from glob import glob

from sys import argv

#logfile = 'LOG'
script = "lissom_oo_or.ty"

# Replace this mechanism with bars under the x-axis, so that
# ranges can be annotated.
annotations = {
    (8100,66.5):((0,0),"A"),
    (8600,58):((0,4),"B"),
    (8250,53.5):((0,0),"C"),
    (8395,54.3):((20,-2),"D"),
    (8100,56.5):((-20,-2),"E"),
    (8425,55):((0,2),"F")
    }
# CB: the above's just approx for now; needs updating.

annotations_key = {'A':(0.0,'something'),
                   'B':(0.0,'something else'),
                   'C':(0.0,'another thing')}

# CB: in progress - obviously the page construction should
# be separated out, etc
def write_page():
    locn = "/home/ceball/buildbot/buildmaster/public_html/p/"
    imgfile = "lissom_oo_or_250_svnversion.png"

    key = "
"
    for k,v in annotations_key.items():
        key+="
%s	%s	%s
"%(k,v[0],v[1])
    key+="
"

    s = "

%s
"%(imgfile,key)

    f = open(locn+"running.html",'w')
    f.write(s)
    f.close()

V=re.compile(r'[0-9]*-log')
def get_build_no(logfilename):
    return int(V.findall(logfilename)[0].rstrip('-log'))

def create_timings(i_am_sure=False):
    if i_am_sure:
        timings = {}
        f = open('/home/ceball/buildbot/timings.pkl','w')
        pickle.dump(timings,f,0)
        f.close()

def create_startups(i_am_sure=False):
    if i_am_sure:
        startups = {}
        f = open('/home/ceball/buildbot/startups.pkl','w')
        pickle.dump(startups,f,0)
        f.close()

def get_timings():
    f = open('/home/ceball/buildbot/timings.pkl')
    timings = pickle.load(f)
    f.close()
    return timings

def save_timings(timings):
    f = open('/home/ceball/buildbot/timings.pkl','w')
    pickle.dump(timings,f,0)
    f.close()

def get_startups():
    f = open('/home/ceball/buildbot/startups.pkl')
    startups = pickle.load(f)
    f.close()
    return startups

def save_startups(startups):
    f = open('/home/ceball/buildbot/startups.pkl','w')
    pickle.dump(startups,f,0)
    f.close()

# exclude these builds
exclusions = []
exclusions.append(153) # doc why this is excluded
exclusions.append(425) # ran with wrong no. of iterations

def get_date_version_time(logfile,timings=None,startups=None):

    build = get_build_no(logfile)

    f = open(logfile)
    all_lines = f.readlines()
    f.close()

    ok = ok2 = False

    datei=versioni=timingi=startupi=None

    i = 0;
    for line in all_lines:
        if line.find("Running at")>=0:

            datei=i
        elif line.find("svnversion")>=0:

            versioni=i
        elif line.startswith("[examples/%s]"%script):
            timingi=i

        elif line.find("[examples/%s startup]"%script)>=0:
            startupi=i

        elif line.find("Results from examples/%s have not changed."%script)>=0:
            ok2=True
        elif line.find('program finished')>=0:
            ok=True

        i+=1;

    if not ok:
        print "...build %s currently incomplete"%build
        return None

    if not ok2:
        print "...speed test invalid because results didn't match"
        if timings:
            timings[script][build] = None
        if startups:
            startups[script][build] = None
        return None

    if datei is None or versioni is None or timingi is None or startupi is None:
        print "...not all data available - build didn't complete?"
        if timings:
            timings[script][build] = None
        if startups:
            startups[script][build] = None
        return None

    datel= all_lines[datei]
    d=re.compile(r'at [0-9]*')
    date = float(d.findall(datel)[0][3::])

    versionl = all_lines[versioni]
    v=re.compile(r'n [0-9]*')
    version = int(v.findall(versionl)[0][2::])

    timel = all_lines[timingi]
    t=re.compile(r'Now: [0-9.]* ')
    start,stop = t.search(timel).span()
    timing = float(timel[start+5:stop-1])

    cpusel = all_lines[timingi+1]
    start,stop = cpusel.index('elapsed')+8,cpusel.index('%CPU')
    cpu_usage = float(cpusel[start:stop])

    startupl = all_lines[startupi]
    t=re.compile(r'Now: [0-9.]* ')
    start,stop = t.search(startupl).span()
    startup = float(startupl[start+5:stop-1])

    startcpusel = all_lines[startupi+1]

    try:
        start,stop = startcpusel.index('elapsed')+8,startcpusel.index('%CPU')
        startcpusage = float(startcpusel[start:stop])
    except ValueError:
        startcpusage = 99  # HACK: for cases where it's missing, assume 99!

    if timings:

        if cpu_usage>95:
            timings[script][build] = (date,version,timing,cpu_usage)
        else:
            print "...build %s had %s percent cpu during timing (not >95)"%(build,cpu_usage)
            timings[script][build] = None

    if startups:

        if startcpusage>95:
            startups[script][build] = (date,version,startup,startcpusage)
        else:
            print "...build %s had %s percent cpu during startup (not >95)"%(build,startcpusage)
            timings[script][build] = None

    return (build,date,version,timing,startup,cpu_usage)

MIN_BUILD=153 # where to start analysis
filename_pattern = '*-log-shell_3-stdio'
def update_timings(location="/home/ceball/buildbot/buildmaster/slow-tests_x86_ubuntu7.04/"):

    timings = get_timings()

    if script not in timings:
        timings[script]={}

    startups = get_startups()

    if script not in startups:
        startups[script]={}

    filenames = glob(location+filename_pattern)
    for filename in filenames:

        build = get_build_no(filename)

        if build>=MIN_BUILD:

	    do_timings=do_startups=False

            if build not in timings[script] and build not in exclusions:
                print "Adding timing for build...",build
		do_timings=True
            elif build in exclusions and build not in timings[script]:
                print "Build %s excluded; timing skipped."%build
                timings[script][build]=None

            if build not in startups[script] and build not in exclusions:
                print "Adding startup time for build...",build
            	do_startups=True
            elif build in exclusions and build not in startups[script]:
                print "Build %s excluded; startup timing skipped."%build
                startups[script][build]=None

	    if do_timings and do_startups:
                get_date_version_time(filename,timings,startups)
            if do_timings and not do_startups:
                get_date_version_time(filename,timings,None)
            if not do_timings and do_startups:
                get_date_version_time(filename,None,startups)

    save_timings(timings)
    save_startups(startups)
    #print timings

def plot_timings():
    timings=get_timings()
    t=timings['lissom_oo_or.ty']
    tytle="lissom_oo_or.ty, 250 iterations"
    filename="/home/ceball/buildbot/buildmaster/public_html/p/lissom_oo_or_250"
    plott(t,tytle,filename)

def plot_startups():
    timings=get_startups()
    t=timings['lissom_oo_or.ty']
    tytle="lissom_oo_or.ty, startup"
    filename="/home/ceball/buildbot/buildmaster/public_html/p/lissom_oo_or_startup"
    plott(t,tytle,filename)

import matplotlib;matplotlib.use('Agg')

def sgn(x):
    return +1 if x>=0.0 else -1

def plott(t,tytle,filename):

    from pylab import title,xlabel,ylabel,savefig,figure,annotate,figtext

    builds=[]
    versions=[]
    times=[]
    for build,data in t.items():
        if data is not None:
            builds.append(build)
            versions.append(data[1])
            times.append(data[2]*data[3]/99.0)

    from topo.commands.pylabplots import vectorplot
    figure()
    vectorplot(times,versions,style='bx')

    title(tytle)
    xlabel("svnversion")
    ylabel("time /s")

    for k,v in annotations.items():
        if v[0]==(0,0):
            arrowprops=None
        else:
            arrowprops={'width':0.25,'frac':0.05,'headwidth':5}

        #CEBALERT:necessary cos of bug in matplotlib where arrow can\t be vertical or horizontal?
        xshift=sgn(v[0][0])*max(abs(v[0][0]),0.01)
        yshift=sgn(v[0][1])*max(abs(v[0][1]),0.01)

        annotate(v[1],k,xytext=(k[0]+xshift,k[1]+yshift),arrowprops=arrowprops)

    savefig(filename+"_svnversion.png")

    figure()
    vectorplot(times,builds,style='bx')

    title("lissom_oo_or.ty, 250 iterations")
    xlabel("build")
    ylabel("time /s")

##     key = ""
##     for k,v in annotations_key.items():
##         key+="%s: %s\n"%(k,v)

##     figtext(0,0,key)

    savefig(filename+"_buildno.png")

## if __name__=='__main__':

##     if len(sys.argv)>1:
##         if sys.argv[1]=='update':
##             update_timings()
<|endoftext|>


<commit_before>from c2corg_api.models.waypoint import WAYPOINT_TYPE
from c2corg_api.scripts.migration.documents.document import DEFAULT_QUALITY
from c2corg_api.scripts.migration.documents.waypoints.waypoint import \
    MigrateWaypoints

class MigrateParkings(MigrateWaypoints):

    def get_name(self):
        return 'parking'

    def get_count_query(self):
        return (
            'select count(*) '
            'from app_parkings_archives pa join parkings p on pa.id = p.id '
            'where p.redirects_to is null;'
        )

    def get_query(self):
        return (
            'select '
            '   pa.id, pa.document_archive_id, pa.is_latest_version, '
            '   pa.elevation, pa.is_protected, pa.redirects_to, '
            '   ST_Force2D(ST_SetSRID(pa.geom, 3857)) geom,'
            '   pa.public_transportation_rating, pa.snow_clearance_rating, '
            '   pa.lowest_elevation, pa.public_transportation_types '
            'from app_parkings_archives pa join parkings p on pa.id = p.id '
            'where p.redirects_to is null '
            'order by pa.id, pa.document_archive_id;'
        )

    def get_count_query_locales(self):
        return (
            'select count(*) '
            'from app_parkings_i18n_archives pa '
            '  join parkings p on pa.id = p.id '
            'where p.redirects_to is null;'
        )

    def get_query_locales(self):
        return (
            'select '
            '   pa.id, pa.document_i18n_archive_id, pa.is_latest_version, '
            '   pa.name, pa.description, '
            '   pa.public_transportation_description, '
            '   pa.snow_clearance_comment, pa.accommodation, pa.culture '
            'from app_parkings_i18n_archives pa '
            '  join parkings p on pa.id = p.id '
            'where p.redirects_to is null '
            'order by pa.id, pa.culture, pa.document_i18n_archive_id;'
        )

    def get_document(self, document_in, version):
        return dict(
            document_id=document_in.id,
            type=WAYPOINT_TYPE,
            version=version,
            waypoint_type='access',
            protected=document_in.is_protected,
            redirects_to=document_in.redirects_to,
            elevation=document_in.elevation,
            elevation_min=document_in.lowest_elevation,
            public_transportation_rating=self.convert_type(
                document_in.public_transportation_rating,
                MigrateParkings.public_transportation_ratings),
            snow_clearance_rating=self.convert_type(
                document_in.snow_clearance_rating,
                MigrateParkings.snow_clearance_ratings),
            public_transportation_types=self.convert_types(
                document_in.public_transportation_types,
                MigrateParkings.public_transportation_types, [0]),
            quality=DEFAULT_QUALITY
        )

    def get_document_locale(self, document_in, version):
        description = self.convert_tags(document_in.description)
        description, summary = self.extract_summary(description)
        return dict(
            document_id=document_in.id,
            id=document_in.document_i18n_archive_id,
            type=WAYPOINT_TYPE,
            version=version,
            lang=document_in.culture,
            title=document_in.name,
            description=self.merge_text(
                description, self.convert_tags(document_in.accommodation)),
            summary=summary,
            access=self.convert_tags(
                document_in.public_transportation_description),
            access_period=self.convert_tags(document_in.snow_clearance_comment)
        )

    public_transportation_ratings = {
        '1': 'good service',
        '2': 'poor service',
        '3': 'no service',
        '4': 'nearby service',
        '5': 'seasonal service'
    }

    snow_clearance_ratings = {
        '1': 'often',
        '2': 'sometimes',
        '3': 'naturally',
        '4': 'non_applicable'
    }

    public_transportation_types = {
        '1': 'train',
        '2': 'bus',
        '3': 'service_on_demand',
        '4': 'boat',
        '9': 'cable_car'
    }
<commit_msg>Add title for accomodation section during migration<commit_after>from c2corg_api.models.waypoint import WAYPOINT_TYPE
from c2corg_api.scripts.migration.documents.document import DEFAULT_QUALITY
from c2corg_api.scripts.migration.documents.waypoints.waypoint import \
    MigrateWaypoints

class MigrateParkings(MigrateWaypoints):

    def get_name(self):
        return 'parking'

    def get_count_query(self):
        return (
            'select count(*) '
            'from app_parkings_archives pa join parkings p on pa.id = p.id '
            'where p.redirects_to is null;'
        )

    def get_query(self):
        return (
            'select '
            '   pa.id, pa.document_archive_id, pa.is_latest_version, '
            '   pa.elevation, pa.is_protected, pa.redirects_to, '
            '   ST_Force2D(ST_SetSRID(pa.geom, 3857)) geom,'
            '   pa.public_transportation_rating, pa.snow_clearance_rating, '
            '   pa.lowest_elevation, pa.public_transportation_types '
            'from app_parkings_archives pa join parkings p on pa.id = p.id '
            'where p.redirects_to is null '
            'order by pa.id, pa.document_archive_id;'
        )

    def get_count_query_locales(self):
        return (
            'select count(*) '
            'from app_parkings_i18n_archives pa '
            '  join parkings p on pa.id = p.id '
            'where p.redirects_to is null;'
        )

    def get_query_locales(self):
        return (
            'select '
            '   pa.id, pa.document_i18n_archive_id, pa.is_latest_version, '
            '   pa.name, pa.description, '
            '   pa.public_transportation_description, '
            '   pa.snow_clearance_comment, pa.accommodation, pa.culture '
            'from app_parkings_i18n_archives pa '
            '  join parkings p on pa.id = p.id '
            'where p.redirects_to is null '
            'order by pa.id, pa.culture, pa.document_i18n_archive_id;'
        )

    def get_document(self, document_in, version):
        return dict(
            document_id=document_in.id,
            type=WAYPOINT_TYPE,
            version=version,
            waypoint_type='access',
            protected=document_in.is_protected,
            redirects_to=document_in.redirects_to,
            elevation=document_in.elevation,
            elevation_min=document_in.lowest_elevation,
            public_transportation_rating=self.convert_type(
                document_in.public_transportation_rating,
                MigrateParkings.public_transportation_ratings),
            snow_clearance_rating=self.convert_type(
                document_in.snow_clearance_rating,
                MigrateParkings.snow_clearance_ratings),
            public_transportation_types=self.convert_types(
                document_in.public_transportation_types,
                MigrateParkings.public_transportation_types, [0]),
            quality=DEFAULT_QUALITY
        )

    def get_document_locale(self, document_in, version):
        description = self.convert_tags(document_in.description)
        description, summary = self.extract_summary(description)

        description = self._add_accomodation(
            description,
            self.convert_tags(document_in.accommodation),
            document_in.culture)

        return dict(
            document_id=document_in.id,
            id=document_in.document_i18n_archive_id,
            type=WAYPOINT_TYPE,
            version=version,
            lang=document_in.culture,
            title=document_in.name,
            description=description,
            summary=summary,
            access=self.convert_tags(
                document_in.public_transportation_description),
            access_period=self.convert_tags(document_in.snow_clearance_comment)
        )

    def __add_accomodation(self, description, accommodation, lang):
        if accommodation:
            header = self._translate_accomodation(lang)
            accommodation = '## ' + header + '\n' + accommodation
        return self.merge_text(description, accommodation)

    def _translate_accomodation(self, lang):
        return MigrateParkings.accomodation_translations[lang]

    accomodation_translations = {
        'ca': 'Allotjament, restauració i patrimoni cultural proper',
        'de': 'In der Nähe liegende Ess-, Trink- und Übernachtungsmöglichkeiten, sowie Kulturgüter',  # noqa
        'en': 'Nearby accomodation, restaurants and cultural heritage',
        'es': 'Alojamiento y comida en las cercanías',
        'eu': 'Inguruetako lo eta jateko tokiak',
        'fr': 'Hébergement, restauration et patrimoine culturel à proximité',
        'it': 'Vitto, alloggio nelle vicinanze e patrimonio culturale'
    }

    public_transportation_ratings = {
        '1': 'good service',
        '2': 'poor service',
        '3': 'no service',
        '4': 'nearby service',
        '5': 'seasonal service'
    }

    snow_clearance_ratings = {
        '1': 'often',
        '2': 'sometimes',
        '3': 'naturally',
        '4': 'non_applicable'
    }

    public_transportation_types = {
        '1': 'train',
        '2': 'bus',
        '3': 'service_on_demand',
        '4': 'boat',
        '9': 'cable_car'
    }
<|endoftext|>


<commit_before>"""logging facilities

The way to use this is as follows:

* each module declares its own logger, using:

    from .logger import create_logger
    logger = create_logger()

* then each module uses logger.info/warning/debug/etc according to the
  level it believes is appropriate:

    logger.debug('some intricate details you usually do not care about')
    logger.info('verbose progress information')
    logger.warning('some non-error condition that must always be reported')
    logger.error('a fatal error')

  ... and so on. see the `logging documentation
  <https://docs.python.org/3/howto/logging.html#when-to-use-logging>`_
  for more information

* console interaction happens on stderr, that include interactive
  reporting functions like `help`, `info` and `list`

* ...except ``input()`` is special, because we can't control the
  stream it is using, unfortunately. we assume that it won't clutter
  stdout, because interaction would be broken then anyways

* advanced verbosity filters, based on what i described in
  https://github.com/borgbackup/borg/pull/233#issuecomment-145100222
  may eventually be implemented
"""

import inspect
import logging
import sys

def setup_logging(args, stream=None):
    """setup logging module according to the arguments provided

    this sets up a stream handler logger on stderr (by default, if no
    stream is provided) and verbosity levels.
    """
    logging.raiseExceptions = False
    l = logging.getLogger('')
    sh = logging.StreamHandler(stream)
    # other formatters will probably want this, but let's remove
    # clutter on stderr
    #sh.setFormatter(logging.Formatter('%(name)s: %(message)s'))
    l.addHandler(sh)
    levels = { None: logging.WARNING,
       0: logging.WARNING,
       1: logging.INFO,
       2: logging.DEBUG }
    # default to WARNING, -v goes to INFO and -vv to DEBUG
    l.setLevel(levels[args.verbose])
    return sh,

def find_parent_module():
    """find the name of a the first module calling this module

    if we cannot find it, we return the current module's name
    (__name__) instead.
    """
    try:
        frame = inspect.currentframe().f_back
        module = inspect.getmodule(frame)
        while module is None or module.__name__ == __name__:
            frame = frame.f_back
            module = inspect.getmodule(frame)
        return module.__name__
    except AttributeError:
        # somehow we failed to find our module
        # return the logger module name by default
        return __name__

def create_logger(name=None):
    """create a Logger object with the proper path, which is returned by
    find_parent_module() by default, or is provided on the commandline

    this is really a shortcut for:

        logger = logging.getLogger(__name__)

    we use it to avoid errors and provide a more standard API.
    """
    return logging.getLogger(name or find_parent_module())
<commit_msg>fix typo<commit_after>"""logging facilities

The way to use this is as follows:

* each module declares its own logger, using:

    from .logger import create_logger
    logger = create_logger()

* then each module uses logger.info/warning/debug/etc according to the
  level it believes is appropriate:

    logger.debug('some intricate details you usually do not care about')
    logger.info('verbose progress information')
    logger.warning('some non-error condition that must always be reported')
    logger.error('a fatal error')

  ... and so on. see the `logging documentation
  <https://docs.python.org/3/howto/logging.html#when-to-use-logging>`_
  for more information

* console interaction happens on stderr, that includes interactive
  reporting functions like `help`, `info` and `list`

* ...except ``input()`` is special, because we can't control the
  stream it is using, unfortunately. we assume that it won't clutter
  stdout, because interaction would be broken then anyways

* advanced verbosity filters, based on what i described in
  https://github.com/borgbackup/borg/pull/233#issuecomment-145100222
  may eventually be implemented
"""

import inspect
import logging
import sys

def setup_logging(args, stream=None):
    """setup logging module according to the arguments provided

    this sets up a stream handler logger on stderr (by default, if no
    stream is provided) and verbosity levels.
    """
    logging.raiseExceptions = False
    l = logging.getLogger('')
    sh = logging.StreamHandler(stream)
    # other formatters will probably want this, but let's remove
    # clutter on stderr
    #sh.setFormatter(logging.Formatter('%(name)s: %(message)s'))
    l.addHandler(sh)
    levels = { None: logging.WARNING,
       0: logging.WARNING,
       1: logging.INFO,
       2: logging.DEBUG }
    # default to WARNING, -v goes to INFO and -vv to DEBUG
    l.setLevel(levels[args.verbose])
    return sh,

def find_parent_module():
    """find the name of a the first module calling this module

    if we cannot find it, we return the current module's name
    (__name__) instead.
    """
    try:
        frame = inspect.currentframe().f_back
        module = inspect.getmodule(frame)
        while module is None or module.__name__ == __name__:
            frame = frame.f_back
            module = inspect.getmodule(frame)
        return module.__name__
    except AttributeError:
        # somehow we failed to find our module
        # return the logger module name by default
        return __name__

def create_logger(name=None):
    """create a Logger object with the proper path, which is returned by
    find_parent_module() by default, or is provided via the commandline

    this is really a shortcut for:

        logger = logging.getLogger(__name__)

    we use it to avoid errors and provide a more standard API.
    """
    return logging.getLogger(name or find_parent_module())
<|endoftext|>


<commit_before>import traceback

import datetime

import crypto
import user_function
import utils

linkRegister = '[register](http://www.reddit.com/message/compose?to=sodogetiptest&subject=%2Bregister&message=%2Bregister)'

def register_user(rpc, msg):
    if not user_function.user_exist(msg.author.name):
        address = rpc.getnewaddress()
        if address:
            msg.reply(msg.author.name + ' registered, your address is ' + address)
            user_function.add_user(msg.author.name, address)

            user_function.add_to_history(msg.author.name, "", "", "", "register")
            pending_tips(rpc, msg)
        else:
            print 'Error during register !'
    else:
        print msg.author.name + ' are already registered '
        msg.reply('You are already registered ')

def pending_tips(rpc, msg):
    # check if user have pending tips
    pending_tips = user_function.get_user_pending_tip(msg.author.name)
    if pending_tips != False:
        for tip in pending_tips:
            # check if it's not too old & replay tipping
            limit_date = datetime.datetime.now() - datetime.timedelta(days=3)

            if (datetime.datetime.strptime(tip['time'], '%Y-%m-%dT%H:%M:%S.%f') < limit_date):
                print "replay tipping - %s send %s for %s  " % (tip['sender'], tip['amount'], msg.author.name)
                crypto.tip_user(rpc, tip['sender'], msg.author.name, tip['amount'])
            else:
                print "delete old tipping - %s send %s for %s  " % (tip['sender'], tip['amount'], msg.author.name)

        user_function.remove_pending_tip(msg.author.name)
    else:
        print ("no pendding tipping for %s " % msg.author.name)

def balance_user(rpc, msg):
    if user_function.user_exist(msg.author.name):
        balance = crypto.get_user_balance(rpc, msg.author.name)
        print('user %s balance = %s' % (msg.author.name, balance))
        value_usd = utils.get_coin_value(balance)
        msg.reply('Your balance : ' + str(balance) + ' ( ' + str(value_usd) + '$ ) ')
    else:
        print('user %s not registered ' % (msg.author.name))
        msg.reply('You need %s before' % linkRegister)

def info_user(rpc, msg):
    if user_function.user_exist(msg.author.name):
        user_function.get_user_info(msg)
    else:
        msg.reply('You need %s before' % linkRegister)

def withdraw_user(rpc, msg):
    split_message = msg.body.strip().split()

    if user_function.user_exist(msg.author.name):
        sender_address = user_function.get_user_address(msg.author.name)
        amount = split_message[1]
        user_balance = crypto.get_user_balance(rpc, msg.author.name)
        if int(amount) >= user_balance:
            print('user %s not have enough to withdraw this amount (%s), balance = %s' % (
                msg.author.name, amount, user_balance))
            msg.reply('+/u/%s your balance is too low for this withdraw ' % msg.author.name)
        else:
            if utils.check_amount_valid(amount):
                receiver_address = split_message[4]
                try:
                    if crypto.send_to(rpc, sender_address, receiver_address, amount, True):
                        user_function.add_to_history(msg.author.name, sender_address, receiver_address, amount,
                                                     "withdraw")
                        msg.reply('Withdraw : ' + str(amount) + ' to ' + receiver_address)

                except:
                    traceback.print_exc()
            else:
                print('You must use valid amount')
                msg.reply('You must use valid amount')
    else:
        msg.reply('You need %s before' % linkRegister)

def tip_user(rpc, msg):
    print('An user mention detected ')
    split_message = msg.body.strip().split()
    tip_index = split_message.index('+/u/sodogetiptest')

    if split_message[tip_index] == '+/u/sodogetiptest' and split_message[tip_index + 2] == 'doge':
        amount = split_message[tip_index + 1]

        if utils.check_amount_valid(amount):
            parent_comment = msg.parent()
            if user_function.user_exist(msg.author.name):

                # check we have enough
                user_balance = crypto.get_user_balance(rpc, msg.author.name)
                if int(amount) >= user_balance:
                    print('user %s not have enough to tip this amount (%s), balance = %s' % (
                        msg.author.name, amount, user_balance))
                    msg.reply('+/u/%s your balance is too low for this tip ' % msg.author.name)
                else:

                    # check user have address before tip
                    if user_function.user_exist(parent_comment.author.name):
                        if crypto.tip_user(rpc, msg.author.name, parent_comment.author.name, amount):
                            user_function.add_to_history(msg.author.name, msg.author.name, parent_comment.author.name,
                                                         amount,
                                                         "tip")

                            print '%s tip %s to %s' % (msg.author.name, str(amount), parent_comment.author.name)
                            # if user have 'verify' in this command he will have confirmation
                            if split_message.count('verify') or int(amount) >= 1000:
                                msg.reply('+/u/%s tip %s to %s' % (msg.author.name, str(amount),
                                                                   parent_comment.author.name))
                    else:
                        user_function.save_unregistered_tip(msg.author.name, parent_comment.author.name, amount)
                        user_function.add_to_history(msg.author.name, msg.author.name, parent_comment.author.name,
                                                     amount,
                                                     "tip", False)
                        print('user %s not registered' % parent_comment.author.name)
                        msg.reply(
                            '+/u/%s need %s before can be tipped (tip saved during 3 day)' % (
                                parent_comment.author.name, linkRegister)
                        )
            else:
                msg.reply('You need %s before' % linkRegister)
        else:
            print('You must use valid amount')
            msg.reply('You must use valid amount')
<commit_msg>fix case sensitivity on tips<commit_after>import traceback

import datetime

import crypto
import user_function
import utils

linkRegister = '[register](http://www.reddit.com/message/compose?to=sodogetiptest&subject=%2Bregister&message=%2Bregister)'

def register_user(rpc, msg):
    if not user_function.user_exist(msg.author.name):
        address = rpc.getnewaddress()
        if address:
            msg.reply(msg.author.name + ' registered, your address is ' + address)
            user_function.add_user(msg.author.name, address)

            user_function.add_to_history(msg.author.name, "", "", "", "register")
            pending_tips(rpc, msg)
        else:
            print 'Error during register !'
    else:
        print msg.author.name + ' are already registered '
        msg.reply('You are already registered ')

def pending_tips(rpc, msg):
    # check if user have pending tips
    pending_tips = user_function.get_user_pending_tip(msg.author.name)
    if pending_tips != False:
        for tip in pending_tips:
            # check if it's not too old & replay tipping
            limit_date = datetime.datetime.now() - datetime.timedelta(days=3)

            if (datetime.datetime.strptime(tip['time'], '%Y-%m-%dT%H:%M:%S.%f') < limit_date):
                print "replay tipping - %s send %s for %s  " % (tip['sender'], tip['amount'], msg.author.name)
                crypto.tip_user(rpc, tip['sender'], msg.author.name, tip['amount'])
            else:
                print "delete old tipping - %s send %s for %s  " % (tip['sender'], tip['amount'], msg.author.name)

        user_function.remove_pending_tip(msg.author.name)
    else:
        print ("no pendding tipping for %s " % msg.author.name)

def balance_user(rpc, msg):
    if user_function.user_exist(msg.author.name):
        balance = crypto.get_user_balance(rpc, msg.author.name)
        print('user %s balance = %s' % (msg.author.name, balance))
        value_usd = utils.get_coin_value(balance)
        msg.reply('Your balance : ' + str(balance) + ' ( ' + str(value_usd) + '$ ) ')
    else:
        print('user %s not registered ' % (msg.author.name))
        msg.reply('You need %s before' % linkRegister)

def info_user(rpc, msg):
    if user_function.user_exist(msg.author.name):
        user_function.get_user_info(msg)
    else:
        msg.reply('You need %s before' % linkRegister)

def withdraw_user(rpc, msg):
    split_message = msg.body.strip().split()

    if user_function.user_exist(msg.author.name):
        sender_address = user_function.get_user_address(msg.author.name)
        amount = split_message[1]
        user_balance = crypto.get_user_balance(rpc, msg.author.name)
        if int(amount) >= user_balance:
            print('user %s not have enough to withdraw this amount (%s), balance = %s' % (
                msg.author.name, amount, user_balance))
            msg.reply('+/u/%s your balance is too low for this withdraw ' % msg.author.name)
        else:
            if utils.check_amount_valid(amount):
                receiver_address = split_message[4]
                try:
                    if crypto.send_to(rpc, sender_address, receiver_address, amount, True):
                        user_function.add_to_history(msg.author.name, sender_address, receiver_address, amount,
                                                     "withdraw")
                        msg.reply('Withdraw : ' + str(amount) + ' to ' + receiver_address)

                except:
                    traceback.print_exc()
            else:
                print('You must use valid amount')
                msg.reply('You must use valid amount')
    else:
        msg.reply('You need %s before' % linkRegister)

def tip_user(rpc, msg):
    print('An user mention detected ')
    split_message = msg.body.strip().split()
    tip_index = split_message.index('+/u/sodogetiptest')

    if lower.split_message[tip_index] == '+/u/sodogetiptest' and lower.split_message[tip_index + 2] == 'doge':
        amount = split_message[tip_index + 1]

        if utils.check_amount_valid(amount):
            parent_comment = msg.parent()
            if user_function.user_exist(msg.author.name):

                # check we have enough
                user_balance = crypto.get_user_balance(rpc, msg.author.name)
                if int(amount) >= user_balance:
                    print('user %s not have enough to tip this amount (%s), balance = %s' % (
                        msg.author.name, amount, user_balance))
                    msg.reply('+/u/%s your balance is too low for this tip ' % msg.author.name)
                else:

                    # check user have address before tip
                    if user_function.user_exist(parent_comment.author.name):
                        if crypto.tip_user(rpc, msg.author.name, parent_comment.author.name, amount):
                            user_function.add_to_history(msg.author.name, msg.author.name, parent_comment.author.name,
                                                         amount,
                                                         "tip")

                            print '%s tip %s to %s' % (msg.author.name, str(amount), parent_comment.author.name)
                            # if user have 'verify' in this command he will have confirmation
                            if lower.split_message.count('verify') or int(amount) >= 1000:
                                msg.reply('+/u/%s tip %s to %s' % (msg.author.name, str(amount),
                                                                   parent_comment.author.name))
                    else:
                        user_function.save_unregistered_tip(msg.author.name, parent_comment.author.name, amount)
                        user_function.add_to_history(msg.author.name, msg.author.name, parent_comment.author.name,
                                                     amount,
                                                     "tip", False)
                        print('user %s not registered' % parent_comment.author.name)
                        msg.reply(
                            '+/u/%s need %s before can be tipped (tip saved during 3 day)' % (
                                parent_comment.author.name, linkRegister)
                        )
            else:
                msg.reply('You need %s before' % linkRegister)
        else:
            print('You must use valid amount')
            msg.reply('You must use valid amount')
<|endoftext|>