# Copyright 2014 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.
{
'targets' : [
{
'target_name' : 'gcdwebserver',
'type': 'static_library',
'include_dirs': [
'src/GCDWebServer/Core',
'src/GCDWebServer/Requests',
'src/GCDWebServer/Responses',
],
'direct_dependent_settings': {
'include_dirs': [
'src/GCDWebServer/Core',
'src/GCDWebServer/Requests',
'src/GCDWebServer/Responses',
],
},
'xcode_settings': {
'CLANG_ENABLE_OBJC_ARC': 'YES',
},
'sources': [
'src/GCDWebServer/Core/GCDWebServer.h',
'src/GCDWebServer/Core/GCDWebServer.m',
'src/GCDWebServer/Core/GCDWebServerConnection.h',
'src/GCDWebServer/Core/GCDWebServerConnection.m',
'src/GCDWebServer/Core/GCDWebServerFunctions.h',
'src/GCDWebServer/Core/GCDWebServerFunctions.m',
'src/GCDWebServer/Core/GCDWebServerHTTPStatusCodes.h',
'src/GCDWebServer/Core/GCDWebServerPrivate.h',
'src/GCDWebServer/Core/GCDWebServerRequest.h',
'src/GCDWebServer/Core/GCDWebServerRequest.m',
'src/GCDWebServer/Core/GCDWebServerResponse.h',
'src/GCDWebServer/Core/GCDWebServerResponse.m',
'src/GCDWebServer/Requests/GCDWebServerDataRequest.h',
'src/GCDWebServer/Requests/GCDWebServerDataRequest.m',
'src/GCDWebServer/Requests/GCDWebServerFileRequest.h',
'src/GCDWebServer/Requests/GCDWebServerFileRequest.m',
'src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.h',
'src/GCDWebServer/Requests/GCDWebServerMultiPartFormRequest.m',
'src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.h',
'src/GCDWebServer/Requests/GCDWebServerURLEncodedFormRequest.m',
'src/GCDWebServer/Responses/GCDWebServerDataResponse.h',
'src/GCDWebServer/Responses/GCDWebServerDataResponse.m',
'src/GCDWebServer/Responses/GCDWebServerErrorResponse.h',
'src/GCDWebServer/Responses/GCDWebServerErrorResponse.m',
'src/GCDWebServer/Responses/GCDWebServerFileResponse.h',
'src/GCDWebServer/Responses/GCDWebServerFileResponse.m',
'src/GCDWebServer/Responses/GCDWebServerStreamedResponse.h',
'src/GCDWebServer/Responses/GCDWebServerStreamedResponse.m',
],
'link_settings': {
'libraries': [
'$(SDKROOT)/System/Library/Frameworks/CFNetwork.framework',
'$(SDKROOT)/System/Library/Frameworks/MobileCoreServices.framework',
],
'xcode_settings': {
'OTHER_LDFLAGS': [
'-lz',
],
},
},
},
],
}
#!/usr/bin/env python3
#
# Copyright 2019 - The Android Open Source Project
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
import logging
import unittest
import mock
import os
from acts.controllers import iperf_server
from acts.controllers.iperf_server import IPerfServer
from acts.controllers.iperf_server import IPerfServerOverAdb
from acts.controllers.iperf_server import IPerfServerOverSsh
# The position in the call tuple that represents the args array.
ARGS = 0
# The position in the call tuple that represents the kwargs dict.
KWARGS = 1
MOCK_LOGFILE_PATH = '/path/to/foo'
class IPerfServerModuleTest(unittest.TestCase):
"""Tests the acts.controllers.iperf_server module."""
def test_create_creates_local_iperf_server_with_int(self):
self.assertIsInstance(
iperf_server.create([12345])[0],
IPerfServer,
'create() failed to create IPerfServer for integer input.'
)
def test_create_creates_local_iperf_server_with_str(self):
self.assertIsInstance(
iperf_server.create(['12345'])[0],
IPerfServer,
'create() failed to create IPerfServer for integer input.'
)
def test_create_cannot_create_local_iperf_server_with_bad_str(self):
with self.assertRaises(ValueError):
iperf_server.create(['12345BAD_STRING'])
@mock.patch('acts.controllers.iperf_server.utils')
def test_create_creates_server_over_ssh_with_ssh_config_and_port(self, _):
self.assertIsInstance(
iperf_server.create([{'ssh_config': {'user': '', 'host': ''},
'port': ''}])[0],
IPerfServerOverSsh,
'create() failed to create IPerfServerOverSsh for a valid config.'
)
def test_create_creates_server_over_adb_with_proper_config(self):
self.assertIsInstance(
iperf_server.create([{'AndroidDevice': '53R147', 'port': 0}])[0],
IPerfServerOverAdb,
'create() failed to create IPerfServerOverAdb for a valid config.'
)
def test_create_raises_value_error_on_bad_config_dict(self):
with self.assertRaises(ValueError):
iperf_server.create([{'AndroidDevice': '53R147', 'ssh_config': {}}])
def test_get_port_from_ss_output_returns_correct_port_ipv4(self):
ss_output = ('tcp LISTEN 0 5 127.0.0.1:<PORT> *:*'
' users:(("cmd",pid=<PID>,fd=3))')
self.assertEqual(
iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>')
def test_get_port_from_ss_output_returns_correct_port_ipv6(self):
ss_output = ('tcp LISTEN 0 5 ff:ff:ff:ff:ff:ff:<PORT> *:*'
' users:(("cmd",pid=<PID>,fd=3))')
self.assertEqual(
iperf_server._get_port_from_ss_output(ss_output, '<PID>'), '<PORT>')
class IPerfServerBaseTest(unittest.TestCase):
"""Tests acts.controllers.iperf_server.IPerfServerBase."""
@mock.patch('os.makedirs')
def test_get_full_file_path_creates_parent_directory(self, mock_makedirs):
# Will never actually be created/used.
logging.log_path = '/tmp/unit_test_garbage'
server = IPerfServer('port')
full_file_path = server._get_full_file_path()
self.assertTrue(
mock_makedirs.called,
'Did not attempt to create a directory.'
)
self.assertEqual(
os.path.dirname(full_file_path),
mock_makedirs.call_args[ARGS][0],
'The parent directory of the full file path was not created.'
)
class IPerfServerTest(unittest.TestCase):
"""Tests acts.controllers.iperf_server.IPerfServer."""
PID = 123456
def setUp(self):
iperf_server._get_port_from_ss_output = lambda *_: IPerfServerTest.PID
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@mock.patch('acts.controllers.iperf_server.job')
def test_start_makes_started_true(self, mock_job, __, ___):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertTrue(server.started)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@mock.patch('acts.controllers.iperf_server.job')
def test_start_stop_makes_started_false(self, _, __, ___):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@mock.patch('acts.controllers.iperf_server.job')
def test_start_sets_current_log_file(self, _, __, ___):
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertEqual(
server._current_log_file,
MOCK_LOGFILE_PATH,
'The _current_log_file was not received from _get_full_file_path.'
)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
def test_stop_returns_current_log_file(self, _, __):
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._current_log_file = MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
'The _current_log_file was not returned by stop().'
)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.subprocess')
@mock.patch('acts.controllers.iperf_server.job')
def test_start_does_not_run_two_concurrent_processes(self, start_proc, _, __):
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server.start()
self.assertFalse(
start_proc.called,
'start() should not begin a second process if another is running.'
)
@mock.patch('acts.utils.stop_standing_subprocess')
def test_stop_exits_early_if_no_process_has_started(self, stop_proc):
server = IPerfServer('port')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = None
server.stop()
self.assertFalse(
stop_proc.called,
'stop() should not kill a process if no process is running.'
)
class IPerfServerOverSshTest(unittest.TestCase):
"""Tests acts.controllers.iperf_server.IPerfServerOverSsh."""
INIT_ARGS = [{'host': 'TEST_HOST', 'user': 'test'}, 'PORT']
@mock.patch('acts.controllers.iperf_server.connection')
def test_start_makes_started_true(self, _):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
self.assertTrue(server.started)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.connection')
def test_start_stop_makes_started_false(self, _, __):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch('builtins.open')
@mock.patch('acts.controllers.iperf_server.connection')
def test_stop_returns_expected_log_file(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
'The expected log file was not returned by stop().'
)
@mock.patch('acts.controllers.iperf_server.connection')
def test_start_does_not_run_two_concurrent_processes(self, _):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = mock.Mock()
server.start()
self.assertFalse(
server._ssh_session.run_async.called,
'start() should not begin a second process if another is running.'
)
@mock.patch('acts.utils.stop_standing_subprocess')
@mock.patch('acts.controllers.iperf_server.connection')
def test_stop_exits_early_if_no_process_has_started(self, _, __):
server = IPerfServerOverSsh(*self.INIT_ARGS)
server._ssh_session = mock.Mock()
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
server.stop()
self.assertFalse(
server._ssh_session.run_async.called,
'stop() should not kill a process if no process is running.'
)
class IPerfServerOverAdbTest(unittest.TestCase):
"""Tests acts.controllers.iperf_server.IPerfServerOverSsh."""
ANDROID_DEVICE_PROP = ('acts.controllers.iperf_server.'
'IPerfServerOverAdb._android_device')
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_makes_started_true(self, mock_ad):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
mock_ad.adb.shell.return_value = '<PID>'
server.start()
self.assertTrue(server.started)
@mock.patch('acts.libs.proc.job.run')
@mock.patch('builtins.open')
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_stop_makes_started_false(self, mock_ad, _, __):
"""Tests calling start() without calling stop() makes started True."""
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
mock_ad.adb.shell.side_effect = ['<PID>', '', '', '']
server.start()
server.stop()
self.assertFalse(server.started)
@mock.patch('acts.libs.proc.job.run')
@mock.patch('builtins.open')
@mock.patch(ANDROID_DEVICE_PROP)
def test_stop_returns_expected_log_file(self, mock_ad, _, __):
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server._iperf_process_adb_pid = '<PID>'
mock_ad.adb.shell.side_effect = ['', '', '']
log_file = server.stop()
self.assertEqual(
log_file,
MOCK_LOGFILE_PATH,
'The expected log file was not returned by stop().'
)
@mock.patch(ANDROID_DEVICE_PROP)
def test_start_does_not_run_two_concurrent_processes(self, android_device):
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_process = mock.Mock()
server.start()
self.assertFalse(
android_device.adb.shell_nb.called,
'start() should not begin a second process if another is running.'
)
@mock.patch('acts.libs.proc.job.run')
@mock.patch('builtins.open')
@mock.patch(ANDROID_DEVICE_PROP)
def test_stop_exits_early_if_no_process_has_started(self, android_device, _,
__):
server = IPerfServerOverAdb('53R147', 'PORT')
server._get_full_file_path = lambda _: MOCK_LOGFILE_PATH
server._iperf_pid = None
server.stop()
self.assertFalse(
android_device.adb.shell_nb.called,
'stop() should not kill a process if no process is running.'
)
if __name__ == '__main__':
unittest.main()
#!/usr/bin/env python
#
# Copyright 2007 Google Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
"""Tests for google.appengine.tools.devappserver2.wsgi_server."""
import errno
import json
import os
import select
import socket
import sys
import time
import unittest
import urllib2
import google
import mox
from cherrypy import wsgiserver
from google.appengine.tools.devappserver2 import wsgi_server
class TestError(Exception):
pass
class _SingleAddressWsgiServerTest(unittest.TestCase):
def setUp(self):
super(_SingleAddressWsgiServerTest, self).setUp()
self.server = wsgi_server._SingleAddressWsgiServer(('localhost', 0),
self.wsgi_application)
self.server.start()
def tearDown(self):
super(_SingleAddressWsgiServerTest, self).tearDown()
self.server.quit()
def test_serve(self):
result = urllib2.urlopen('http://localhost:%d/foo?bar=baz' %
self.server.port)
body = result.read()
environ = json.loads(body)
self.assertEqual(200, result.code)
self.assertEqual('/foo', environ['PATH_INFO'])
self.assertEqual('bar=baz', environ['QUERY_STRING'])
def wsgi_application(self, environ, start_response):
start_response('200 OK', [('Content-Type', 'application/json')])
serializable_environ = environ.copy()
del serializable_environ['wsgi.input']
del serializable_environ['wsgi.errors']
return [json.dumps(serializable_environ)]
def other_wsgi_application(self, environ, start_response):
start_response('200 OK', [('Content-Type', 'text/plain')])
return ['Hello World']
def test_set_app(self):
self.server.set_app(self.other_wsgi_application)
result = urllib2.urlopen('http://localhost:%d/foo?bar=baz' %
self.server.port)
body = result.read()
self.assertEqual(200, result.code)
self.assertEqual('Hello World', body)
def test_set_error(self):
self.server.set_error(204)
result = urllib2.urlopen('http://localhost:%d/foo?bar=baz' %
self.server.port)
self.assertEqual(204, result.code)
class SharedCherryPyThreadPoolTest(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
self.mox.StubOutWithMock(wsgi_server._THREAD_POOL, 'submit')
self.thread_pool = wsgi_server._SharedCherryPyThreadPool()
def tearDown(self):
self.mox.UnsetStubs()
def test_put(self):
connection = object()
wsgi_server._THREAD_POOL.submit(self.thread_pool._handle, connection)
self.mox.ReplayAll()
self.thread_pool.put(connection)
self.mox.VerifyAll()
self.assertEqual(set([connection]), self.thread_pool._connections)
def test_handle(self):
connection = self.mox.CreateMock(wsgiserver.HTTPConnection)
self.mox.StubOutWithMock(self.thread_pool._condition, 'notify')
self.thread_pool._connections.add(connection)
connection.communicate()
connection.close()
self.thread_pool._condition.notify()
self.mox.ReplayAll()
self.thread_pool._handle(connection)
self.mox.VerifyAll()
self.assertEqual(set(), self.thread_pool._connections)
def test_handle_with_exception(self):
connection = self.mox.CreateMock(wsgiserver.HTTPConnection)
self.mox.StubOutWithMock(self.thread_pool._condition, 'notify')
self.thread_pool._connections.add(connection)
connection.communicate().AndRaise(TestError)
connection.close()
self.thread_pool._condition.notify()
self.mox.ReplayAll()
self.assertRaises(TestError, self.thread_pool._handle, connection)
self.mox.VerifyAll()
self.assertEqual(set(), self.thread_pool._connections)
def test_stop(self):
self.mox.ReplayAll()
self.thread_pool.stop(3)
self.mox.VerifyAll()
def test_stop_no_connections(self):
self.mox.ReplayAll()
self.thread_pool.stop(0.1)
self.mox.VerifyAll()
def test_stop_with_connections(self):
connection = self.mox.CreateMock(wsgiserver.HTTPConnection)
self.thread_pool._connections.add(connection)
self.mox.StubOutWithMock(self.thread_pool, '_shutdown_connection')
self.thread_pool._shutdown_connection(connection)
self.mox.ReplayAll()
self.thread_pool.stop(1)
self.mox.VerifyAll()
def test_shutdown_connection(self):
class DummyObect(object):
pass
connection = DummyObect()
connection.rfile = DummyObect()
connection.rfile.closed = False
connection.socket = self.mox.CreateMockAnything()
connection.socket.shutdown(socket.SHUT_RD)
self.mox.ReplayAll()
self.thread_pool._shutdown_connection(connection)
self.mox.VerifyAll()
def test_shutdown_connection_rfile_already_close(self):
class DummyObect(object):
pass
connection = DummyObect()
connection.rfile = DummyObect()
connection.rfile.closed = True
connection.socket = self.mox.CreateMockAnything()
self.mox.ReplayAll()
self.thread_pool._shutdown_connection(connection)
self.mox.VerifyAll()
class SelectThreadTest(unittest.TestCase):
class _MockSocket(object):
def fileno(self):
return id(self)
def setUp(self):
self.select_thread = wsgi_server.SelectThread()
self.original_has_poll = wsgi_server._HAS_POLL
self.mox = mox.Mox()
self.mox.StubOutWithMock(select, 'select')
if hasattr(select, 'poll'):
self.mox.StubOutWithMock(select, 'poll')
self.mox.StubOutWithMock(time, 'sleep')
def tearDown(self):
self.mox.UnsetStubs()
wsgi_server._HAS_POLL = self.original_has_poll
def test_add_socket(self):
file_descriptors = self.select_thread._file_descriptors
file_descriptor_to_callback = (
self.select_thread._file_descriptor_to_callback)
file_descriptors_copy = frozenset(self.select_thread._file_descriptors)
file_descriptor_to_callback_copy = (
self.select_thread._file_descriptor_to_callback.copy())
s = self._MockSocket()
callback = object()
self.select_thread.add_socket(s, callback)
self.assertEqual(file_descriptors_copy, file_descriptors)
self.assertEqual(file_descriptor_to_callback_copy,
file_descriptor_to_callback)
self.assertEqual(frozenset([s.fileno()]),
self.select_thread._file_descriptors)
self.assertEqual({s.fileno(): callback},
self.select_thread._file_descriptor_to_callback)
def test_remove_socket(self):
s1 = self._MockSocket()
callback1 = object()
s2 = self._MockSocket()
callback2 = object()
self.select_thread._file_descriptors = frozenset([s1.fileno(), s2.fileno()])
self.select_thread._file_descriptor_to_callback = {
s1.fileno(): callback1, s2.fileno(): callback2}
file_descriptors = self.select_thread._file_descriptors
file_descriptor_to_callback = (
self.select_thread._file_descriptor_to_callback)
file_descriptors_copy = frozenset(self.select_thread._file_descriptors)
file_descriptor_to_callback_copy = (
self.select_thread._file_descriptor_to_callback.copy())
self.select_thread.remove_socket(s1)
self.assertEqual(file_descriptors_copy, file_descriptors)
self.assertEqual(file_descriptor_to_callback_copy,
file_descriptor_to_callback)
self.assertEqual(frozenset([s2.fileno()]),
self.select_thread._file_descriptors)
self.assertEqual({s2.fileno(): callback2},
self.select_thread._file_descriptor_to_callback)
def test_select_no_sockets(self):
time.sleep(1)
self.mox.ReplayAll()
self.select_thread._select()
self.mox.VerifyAll()
def test_select_no_poll(self):
wsgi_server._HAS_POLL = False
s = self._MockSocket()
callback = self.mox.CreateMockAnything()
select.select(frozenset([s.fileno()]), [], [], 1).AndReturn(
([s.fileno()], [], []))
callback()
self.mox.ReplayAll()
self.select_thread.add_socket(s, callback)
self.select_thread._select()
self.mox.VerifyAll()
@unittest.skipUnless(wsgi_server._HAS_POLL, 'requires select.poll')
def test_select_with_poll(self):
s = self._MockSocket()
callback = self.mox.CreateMockAnything()
poll = self.mox.CreateMockAnything()
select.poll().AndReturn(poll)
poll.register(s.fileno(), select.POLLIN)
poll.poll(1000).AndReturn([(s.fileno(), select.POLLIN)])
callback()
self.mox.ReplayAll()
self.select_thread.add_socket(s, callback)
self.select_thread._select()
self.mox.VerifyAll()
def test_select_not_ready_no_poll(self):
wsgi_server._HAS_POLL = False
s = self._MockSocket()
callback = self.mox.CreateMockAnything()
select.select(frozenset([s.fileno()]), [], [], 1).AndReturn(([], [], []))
self.mox.ReplayAll()
self.select_thread.add_socket(s, callback)
self.select_thread._select()
self.mox.VerifyAll()
@unittest.skipUnless(wsgi_server._HAS_POLL, 'requires select.poll')
def test_select_not_ready_with_poll(self):
s = self._MockSocket()
callback = self.mox.CreateMockAnything()
poll = self.mox.CreateMockAnything()
select.poll().AndReturn(poll)
poll.register(s.fileno(), select.POLLIN)
poll.poll(1000).AndReturn([])
self.mox.ReplayAll()
self.select_thread.add_socket(s, callback)
self.select_thread._select()
self.mox.VerifyAll()
class WsgiServerStartupTest(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
self.server = wsgi_server.WsgiServer(('localhost', 123), None)
def tearDown(self):
self.mox.UnsetStubs()
def test_start_some_fail_to_bind(self):
failing_server = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
starting_server = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
another_starting_server = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 123, socket.AF_UNSPEC, socket.SOCK_STREAM,
0, socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('foo', 'bar', 'baz')),
(None, None, None, None, (1, 2, 3, 4, 5)),
(None, None, None, None, (3, 4))])
wsgi_server._SingleAddressWsgiServer(('foo', 'bar'), None).AndReturn(
failing_server)
wsgi_server._SingleAddressWsgiServer((1, 2), None).AndReturn(
starting_server)
wsgi_server._SingleAddressWsgiServer((3, 4), None).AndReturn(
another_starting_server)
starting_server.start()
failing_server.start().AndRaise(wsgi_server.BindError)
another_starting_server.start()
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
self.assertItemsEqual([starting_server, another_starting_server],
self.server._servers)
def test_start_all_fail_to_bind(self):
failing_server = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 123, socket.AF_UNSPEC, socket.SOCK_STREAM,
0, socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('foo', 'bar', 'baz'))])
wsgi_server._SingleAddressWsgiServer(('foo', 'bar'), None).AndReturn(
failing_server)
failing_server.start().AndRaise(wsgi_server.BindError)
self.mox.ReplayAll()
self.assertRaises(wsgi_server.BindError, self.server.start)
self.mox.VerifyAll()
def test_remove_duplicates(self):
foo_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
foo2_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 123, socket.AF_UNSPEC, socket.SOCK_STREAM,
0, socket.AI_PASSIVE).AndReturn(
[(0, 0, 0, '', ('127.0.0.1', 123)),
(0, 0, 0, '', ('::1', 123, 0, 0)),
(0, 0, 0, '', ('127.0.0.1', 123))])
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 123), None).AndReturn(
foo_server)
foo_server.start()
wsgi_server._SingleAddressWsgiServer(('::1', 123), None).AndReturn(
foo2_server)
foo2_server.start()
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
def test_quit(self):
running_server = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
self.server._servers = [running_server]
running_server.quit()
self.mox.ReplayAll()
self.server.quit()
self.mox.VerifyAll()
class WsgiServerPort0StartupTest(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
self.server = wsgi_server.WsgiServer(('localhost', 0), None)
def tearDown(self):
self.mox.UnsetStubs()
def test_basic_behavior(self):
inet4_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
inet6_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('127.0.0.1', 0, 'baz')),
(None, None, None, None, ('::1', 0, 'baz'))])
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 0), None).AndReturn(
inet4_server)
inet4_server.start()
inet4_server.port = 123
wsgi_server._SingleAddressWsgiServer(('::1', 123), None).AndReturn(
inet6_server)
inet6_server.start()
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
self.assertItemsEqual([inet4_server, inet6_server],
self.server._servers)
def test_retry_eaddrinuse(self):
inet4_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
inet6_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
inet4_server_retry = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
inet6_server_retry = self.mox.CreateMock(
wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('127.0.0.1', 0, 'baz')),
(None, None, None, None, ('::1', 0, 'baz'))])
# First try
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 0), None).AndReturn(
inet4_server)
inet4_server.start()
inet4_server.port = 123
wsgi_server._SingleAddressWsgiServer(('::1', 123), None).AndReturn(
inet6_server)
inet6_server.start().AndRaise(
wsgi_server.BindError('message', (errno.EADDRINUSE, 'in use')))
inet4_server.quit()
# Retry
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 0), None).AndReturn(
inet4_server_retry)
inet4_server_retry.start()
inet4_server_retry.port = 456
wsgi_server._SingleAddressWsgiServer(('::1', 456), None).AndReturn(
inet6_server_retry)
inet6_server_retry.start()
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
self.assertItemsEqual([inet4_server_retry, inet6_server_retry],
self.server._servers)
def test_retry_limited(self):
inet4_servers = [self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
for _ in range(wsgi_server._PORT_0_RETRIES)]
inet6_servers = [self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
for _ in range(wsgi_server._PORT_0_RETRIES)]
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('127.0.0.1', 0, 'baz')),
(None, None, None, None, ('::1', 0, 'baz'))])
for offset, (inet4_server, inet6_server) in enumerate(zip(
inet4_servers, inet6_servers)):
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 0), None).AndReturn(
inet4_server)
inet4_server.start()
inet4_server.port = offset + 1
wsgi_server._SingleAddressWsgiServer(('::1', offset + 1), None).AndReturn(
inet6_server)
inet6_server.start().AndRaise(
wsgi_server.BindError('message', (errno.EADDRINUSE, 'in use')))
inet4_server.quit()
self.mox.ReplayAll()
self.assertRaises(wsgi_server.BindError, self.server.start)
self.mox.VerifyAll()
def test_ignore_other_errors(self):
inet4_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
inet6_server = self.mox.CreateMock(wsgi_server._SingleAddressWsgiServer)
self.mox.StubOutWithMock(wsgi_server, '_SingleAddressWsgiServer')
self.mox.StubOutWithMock(socket, 'getaddrinfo')
socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE).AndReturn(
[(None, None, None, None, ('127.0.0.1', 0, 'baz')),
(None, None, None, None, ('::1', 0, 'baz'))])
wsgi_server._SingleAddressWsgiServer(('127.0.0.1', 0), None).AndReturn(
inet4_server)
inet4_server.start()
inet4_server.port = 123
wsgi_server._SingleAddressWsgiServer(('::1', 123), None).AndReturn(
inet6_server)
inet6_server.start().AndRaise(
wsgi_server.BindError('message', (errno.ENOPROTOOPT, 'no protocol')))
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
self.assertItemsEqual([inet4_server],
self.server._servers)
class _SingleAddressWsgiServerStartupTest(unittest.TestCase):
def setUp(self):
self.mox = mox.Mox()
self.server = wsgi_server._SingleAddressWsgiServer(('localhost', 0), None)
def tearDown(self):
self.mox.UnsetStubs()
def test_start_port_in_use(self):
self.mox.StubOutWithMock(socket, 'getaddrinfo')
self.mox.StubOutWithMock(self.server, 'bind')
af = object()
socktype = object()
proto = object()
socket.getaddrinfo('localhost', 0, socket.AF_UNSPEC, socket.SOCK_STREAM, 0,
socket.AI_PASSIVE).AndReturn(
[(af, socktype, proto, None, None)])
self.server.bind(af, socktype, proto).AndRaise(socket.error)
self.mox.ReplayAll()
self.assertRaises(wsgi_server.BindError, self.server.start)
self.mox.VerifyAll()
def test_start(self):
# Ensure no CherryPy thread pools are started.
self.mox.StubOutWithMock(wsgiserver.ThreadPool, 'start')
self.mox.StubOutWithMock(wsgi_server._SELECT_THREAD, 'add_socket')
wsgi_server._SELECT_THREAD.add_socket(mox.IsA(socket.socket),
self.server.tick)
self.mox.ReplayAll()
self.server.start()
self.mox.VerifyAll()
def test_quit(self):
self.mox.StubOutWithMock(wsgi_server._SELECT_THREAD, 'remove_socket')
self.server.socket = object()
self.server.requests = self.mox.CreateMock(
wsgi_server._SharedCherryPyThreadPool)
wsgi_server._SELECT_THREAD.remove_socket(self.server.socket)
self.server.requests.stop(timeout=1)
self.mox.ReplayAll()
self.server.quit()
self.mox.VerifyAll()
if __name__ == '__main__':
unittest.main()
var app = {
init: function() {
if(localStorage.getItem("server")) {
app.setup_login();
} else {
app.show_server();
}
app.bind_events();
common.handle_external_links();
},
bind_events: function() {
app.bind_select_server();
app.bind_login();
app.bind_change_server();
},
bind_login: function() {
$(".btn-login").on("click", function() {
$me = $(this);
$me.prop("disabled", true);
$.ajax({
method: "POST",
url: localStorage.server + "/api/method/login",
data: {
usr: $("#usr").val(),
pwd: $("#pwd").val(),
device: "mobile"
}
}).success(function(data, status, xhr) {
localStorage.user = $("#usr").val();
var cookie_source = xhr.getResponseHeader('Set-Cookie');
localStorage.session_id = common.get_cookie("sid", cookie_source);
app.start_desk();
}).error(function() {
common.msgprint("Invalid Login");
$me.prop("disabled", false);
}).always(function() {
// $("#usr").val("");
// $("#pwd").val("");
});
return false;
});
},
bind_select_server: function() {
$(".btn-select-server").on("click", function() {
// check if erpnext / frappe server
$(this).prop("disabled", true);
var server = $("#server").val();
if(!server) {
app.retry_server();
return false;
}
if(server.substr(0, 7)!== "http://" && server.substr(0, 8)!== "https://") {
// http / https not provided
// try https
app.verify_server("https://" + server, select,
function() {
// try http
app.verify_server("http://" + server, select, app.retry_server);
}
);
} else {
app.verify_server(server, select, app.retry_server);
}
return false;
});
$(".recent-server-list").on("click", "a", function() {
$this = $(this);
$this.prop("disabled", true);
app.verify_server($this.text(), select, app.retry_server);
});
function select(server) {
localStorage.server = app.strip_trailing_slash(server);
app.save_server_in_recent(localStorage.server);
app.setup_login();
}
},
verify_server: function(server, valid, invalid) {
$.ajax({
method: "GET",
url: server + "/api/method/version",
})
.success(function(data) {
if(data.message) {
valid(server);
} else {
invalid();
};
})
.fail(function() { invalid() })
.error(function() { invalid() });
},
bind_change_server: function() {
$(".change-server").on("click", function() {
localStorage.server = "";
app.show_server(true);
return false;
});
},
strip_trailing_slash: function(server) {
return server.replace(/(http[s]?:\/\/[^\/]*)(.*)/, "$1");
},
save_server_in_recent: function(server) {
server = server.toLowerCase().trim();
var recent_servers = localStorage.recent_servers ?
JSON.parse(localStorage.recent_servers) : [];
var index = recent_servers.indexOf(server);
if(index !== -1) {
recent_servers.splice(index, 1);
}
recent_servers.push(server);
localStorage.setItem("recent_servers", JSON.stringify(recent_servers));
},
setup_login: function() {
if(localStorage.server && localStorage.session_id) {
app.if_session_valid(app.start_desk, app.show_login);
} else {
app.show_login();
}
},
show_login: function() {
$(".app").removeClass("hide");
$(".div-select-server").addClass("hide");
$(".div-login").removeClass("hide");
$(".current-server").text(localStorage.server);
},
if_session_valid: function(if_yes, if_no) {
app.set_sid_cookie();
$.ajax({
method: "GET",
crossDomain: true,
url: localStorage.server + "/api/method/ping",
}).success(function(data) {
if(data.message === "pong") {
if_yes();
} else {
if_no();
}
}).error(function() {
if_no();
});
},
set_sid_cookie: function() {
document.cookie = "sid=" + localStorage.session_id +
"; expires=Fri, 31 Dec 9999 23:59:59 GMT";
},
start_desk: function() {
window.location.href = "desk.html";
},
retry_server: function() {
common.msgprint("Does not seem like a valid server address. Please try again.");
app.show_server();
},
show_server: function(clear) {
$(".app").removeClass("hide");
$(".btn-select-server").prop("disabled", false);
$(".div-select-server").removeClass("hide");
if(clear) {
$(".div-login").addClass("hide");
}
app.show_recent_servers();
},
show_recent_servers: function() {
if(localStorage.recent_servers) {
var recent_servers = JSON.parse(localStorage.recent_servers);
recent_servers.reverse().splice(2);
var html = "<li class='text-muted'>Recent:</li>"
$.each(recent_servers, function(i, server) {
html += '<li><a>'+server+'</a></li>';
});
$('.recent-server-list').empty().append(html).removeClass('hide');
}
}
};
document.addEventListener('deviceready', app.init, false);
var __indexOf = [].indexOf || function (item) {
for (var i = 0, l = this.length; i < l; i++) {
if (i in this && this[i] === item) return i;
}
return -1;
};
var xpathStringLiteral = function (s) {
if (s.indexOf('"') === -1)
return '"' + s + '"';
if (s.indexOf("'") === -1)
return "'" + s + "'";
return 'concat("' + s.replace(/"/g, '",\'"\',"') + '")';
};
Poltergeist.Browser = (function () {
/**
* Creates the "browser" inside phantomjs
* @param owner
* @param width
* @param height
* @constructor
*/
function Browser(owner, width, height) {
this.owner = owner;
this.width = width || 1024;
this.height = height || 768;
this.pages = [];
this.js_errors = true;
this._debug = false;
this._counter = 0;
this.resetPage();
}
/**
* Resets the browser to a clean slate
* @return {Function}
*/
Browser.prototype.resetPage = function () {
var _ref;
var self = this;
_ref = [0, []];
this._counter = _ref[0];
this.pages = _ref[1];
if (this.page != null) {
if (!this.page.closed) {
if (this.page.currentUrl() !== 'about:blank') {
this.page.clearLocalStorage();
}
this.page.release();
}
phantom.clearCookies();
}
this.page = this.currentPage = new Poltergeist.WebPage;
this.page.setViewportSize({
width: this.width,
height: this.height
});
this.page.handle = "" + (this._counter++);
this.pages.push(this.page);
return this.page.onPageCreated = function (newPage) {
var page;
page = new Poltergeist.WebPage(newPage);
page.handle = "" + (self._counter++);
return self.pages.push(page);
};
};
/**
* Given a page handle id, tries to get it from the browser page list
* @param handle
* @return {WebPage}
*/
Browser.prototype.getPageByHandle = function (handle) {
var filteredPages;
//TODO: perhaps we should throw a PageNotFoundByHandle or something like that..
if (handle === null || typeof handle == "undefined") {
return null;
}
filteredPages = this.pages.filter(function (p) {
return !p.closed && p.handle === handle;
});
if (filteredPages.length === 1) {
return filteredPages[0];
}
return null;
};
/**
* Sends a debug message to the console
* @param message
* @return {*}
*/
Browser.prototype.debug = function (message) {
if (this._debug) {
return console.log("poltergeist [" + (new Date().getTime()) + "] " + message);
}
};
/**
* Given a page_id and id, gets if possible the node in such page
* @param page_id
* @param id
* @return {Poltergeist.Node}
*/
Browser.prototype.node = function (page_id, id) {
if (this.currentPage.id === page_id) {
return this.currentPage.get(id);
} else {
throw new Poltergeist.ObsoleteNode;
}
};
/**
* Returns the frameUrl related to the frame given by name
* @param frame_name
* @return {*}
*/
Browser.prototype.frameUrl = function (frame_name) {
return this.currentPage.frameUrl(frame_name);
};
/**
* This method defines the rectangular area of the web page to be rasterized when render is invoked.
* If no clipping rectangle is set, render will process the entire web page.
* @param full
* @param selector
* @return {*}
*/
Browser.prototype.set_clip_rect = function (full, selector) {
var dimensions, clipDocument, rect, clipViewport;
dimensions = this.currentPage.validatedDimensions();
clipDocument = dimensions.document;
clipViewport = dimensions.viewport;
if (full) {
rect = {
left: 0,
top: 0,
width: clipDocument.width,
height: clipDocument.height
};
} else {
if (selector != null) {
rect = this.currentPage.elementBounds(selector);
} else {
rect = {
left: 0,
top: 0,
width: clipViewport.width,
height: clipViewport.height
};
}
}
this.currentPage.setClipRect(rect);
return dimensions;
};
/**
* Kill the browser, i.e kill phantomjs current process
* @return {int}
*/
Browser.prototype.exit = function () {
return phantom.exit(0);
};
/**
* Do nothing
*/
Browser.prototype.noop = function () {
};
/**
* Throws a new Object error
*/
Browser.prototype.browser_error = function () {
throw new Error('zomg');
};
/**
* Visits a page and load its content
* @param serverResponse
* @param url
* @return {*}
*/
Browser.prototype.visit = function (serverResponse, url) {
var prevUrl;
var self = this;
this.currentPage.state = 'loading';
prevUrl = this.currentPage.source === null ? 'about:blank' : this.currentPage.currentUrl();
this.currentPage.open(url);
if (/#/.test(url) && prevUrl.split('#')[0] === url.split('#')[0]) {
this.currentPage.state = 'default';
return this.serverSendResponse({
status: 'success'
}, serverResponse);
} else {
return this.currentPage.waitState('default', function () {
if (self.currentPage.statusCode === null && self.currentPage.status === 'fail') {
return self.owner.serverSendError(new Poltergeist.StatusFailError, serverResponse);
} else {
return self.serverSendResponse({
status: self.currentPage.status
}, serverResponse);
}
});
}
};
/**
* Puts the control of the browser inside the IFRAME given by name
* @param serverResponse
* @param name
* @param timeout
* @return {*}
*/
Browser.prototype.push_frame = function (serverResponse, name, timeout) {
var _ref;
var self = this;
if (timeout == null) {
timeout = new Date().getTime() + 2000;
}
//TODO: WTF, else if after a if with return COMMON
if (_ref = this.frameUrl(name), __indexOf.call(this.currentPage.blockedUrls(), _ref) >= 0) {
return this.serverSendResponse(true, serverResponse);
} else if (this.currentPage.pushFrame(name)) {
if (this.currentPage.currentUrl() === 'about:blank') {
this.currentPage.state = 'awaiting_frame_load';
return this.currentPage.waitState('default', function () {
return self.serverSendResponse(true, serverResponse);
});
} else {
return this.serverSendResponse(true, serverResponse);
}
} else {
if (new Date().getTime() < timeout) {
return setTimeout((function () {
return self.push_frame(serverResponse, name, timeout);
}), 50);
} else {
return this.owner.serverSendError(new Poltergeist.FrameNotFound(name), serverResponse);
}
}
};
/**
* Injects a javascript into the current page
* @param serverResponse
* @param extension
* @return {*}
*/
Browser.prototype.add_extension = function (serverResponse, extension) {
//TODO: error control when the injection was not possible
this.currentPage.injectExtension(extension);
return this.serverSendResponse('success', serverResponse);
};
/**
* Returns the url we are currently in
* @param serverResponse
* @return {*}
*/
Browser.prototype.current_url = function (serverResponse) {
return this.serverSendResponse(this.currentPage.currentUrl(), serverResponse);
};
/**
* Returns the current page window name
* @param serverResponse
* @returns {*}
*/
Browser.prototype.window_name = function (serverResponse) {
return this.serverSendResponse(this.currentPage.windowName(), serverResponse);
};
/**
* Returns the status code associated to the page
* @param serverResponse
* @return {*}
*/
Browser.prototype.status_code = function (serverResponse) {
if (this.currentPage.statusCode === undefined || this.currentPage.statusCode === null) {
return this.owner.serverSendError(new Poltergeist.StatusFailError("status_code_error"), serverResponse);
}
return this.serverSendResponse(this.currentPage.statusCode, serverResponse);
};
/**
* Returns the source code of the active frame, useful for when inside an IFRAME
* @param serverResponse
* @return {*}
*/
Browser.prototype.body = function (serverResponse) {
return this.serverSendResponse(this.currentPage.content(), serverResponse);
};
/**
* Returns the source code of the page all the html
* @param serverResponse
* @return {*}
*/
Browser.prototype.source = function (serverResponse) {
return this.serverSendResponse(this.currentPage.source, serverResponse);
};
/**
* Returns the current page title
* @param serverResponse
* @return {*}
*/
Browser.prototype.title = function (serverResponse) {
return this.serverSendResponse(this.currentPage.title(), serverResponse);
};
/**
* Finds the elements that match a method of selection and a selector
* @param serverResponse
* @param method
* @param selector
* @return {*}
*/
Browser.prototype.find = function (serverResponse, method, selector) {
return this.serverSendResponse({
page_id: this.currentPage.id,
ids: this.currentPage.find(method, selector)
}, serverResponse);
};
/**
* Find elements within a given element
* @param serverResponse
* @param page_id
* @param id
* @param method
* @param selector
* @return {*}
*/
Browser.prototype.find_within = function (serverResponse, page_id, id, method, selector) {
return this.serverSendResponse(this.node(page_id, id).find(method, selector), serverResponse);
};
/**
* Returns ALL the text, visible and not visible from the given element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.all_text = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).allText(), serverResponse);
};
/**
* Returns the inner or outer html of a given id
* @param serverResponse
* @param page_id
* @param id
* @param type
* @returns Object
*/
Browser.prototype.all_html = function (serverResponse, page_id, id, type) {
return this.serverSendResponse(this.node(page_id, id).allHTML(type), serverResponse);
};
/**
* Returns only the visible text in a given element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.visible_text = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).visibleText(), serverResponse);
};
/**
* Deletes the text in a given element leaving it empty
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.delete_text = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).deleteText(), serverResponse);
};
/**
* Gets the value of a given attribute in an element
* @param serverResponse
* @param page_id
* @param id
* @param name
* @return {*}
*/
Browser.prototype.attribute = function (serverResponse, page_id, id, name) {
return this.serverSendResponse(this.node(page_id, id).getAttribute(name), serverResponse);
};
/**
* Allows the possibility to set an attribute on a given element
* @param serverResponse
* @param page_id
* @param id
* @param name
* @param value
* @returns {*}
*/
Browser.prototype.set_attribute = function (serverResponse, page_id, id, name, value) {
return this.serverSendResponse(this.node(page_id, id).setAttribute(name, value), serverResponse);
};
/**
* Allows the possibility to remove an attribute on a given element
* @param serverResponse
* @param page_id
* @param id
* @param name
* @returns {*}
*/
Browser.prototype.remove_attribute = function (serverResponse, page_id, id, name) {
return this.serverSendResponse(this.node(page_id, id).removeAttribute(name), serverResponse);
};
/**
* Returns all the attributes of a given element
* @param serverResponse
* @param page_id
* @param id
* @param name
* @return {*}
*/
Browser.prototype.attributes = function (serverResponse, page_id, id, name) {
return this.serverSendResponse(this.node(page_id, id).getAttributes(), serverResponse);
};
/**
* Returns all the way to the document level the parents of a given element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.parents = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).parentIds(), serverResponse);
};
/**
* Returns the element.value of an element given by its page and id
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.value = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).value(), serverResponse);
};
/**
* Sets the element.value of an element by the given value
* @param serverResponse
* @param page_id
* @param id
* @param value
* @return {*}
*/
Browser.prototype.set = function (serverResponse, page_id, id, value) {
this.node(page_id, id).set(value);
return this.serverSendResponse(true, serverResponse);
};
/**
* Uploads a file to an input file element
* @param serverResponse
* @param page_id
* @param id
* @param file_path
* @return {*}
*/
Browser.prototype.select_file = function (serverResponse, page_id, id, file_path) {
var node = this.node(page_id, id);
this.currentPage.beforeUpload(node.id);
this.currentPage.uploadFile('[_poltergeist_selected]', file_path);
this.currentPage.afterUpload(node.id);
return this.serverSendResponse(true, serverResponse);
};
/**
* Sets a value to the selected element (to be used in select elements)
* @param serverResponse
* @param page_id
* @param id
* @param value
* @return {*}
*/
Browser.prototype.select = function (serverResponse, page_id, id, value) {
return this.serverSendResponse(this.node(page_id, id).select(value), serverResponse);
};
/**
* Selects an option with the given value
* @param serverResponse
* @param page_id
* @param id
* @param value
* @param multiple
* @return {*}
*/
Browser.prototype.select_option = function (serverResponse, page_id, id, value, multiple) {
return this.serverSendResponse(this.node(page_id, id).select_option(value, multiple), serverResponse);
};
/**
*
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.tag_name = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).tagName(), serverResponse);
};
/**
* Tells if an element is visible or not
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.visible = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).isVisible(), serverResponse);
};
/**
* Tells if an element is disabled
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.disabled = function (serverResponse, page_id, id) {
return this.serverSendResponse(this.node(page_id, id).isDisabled(), serverResponse);
};
/**
* Evaluates a javascript and returns the outcome to the client
* This will be JSON response so your script better be returning objects that can be used
* in JSON.stringify
* @param serverResponse
* @param script
* @return {*}
*/
Browser.prototype.evaluate = function (serverResponse, script) {
return this.serverSendResponse(this.currentPage.evaluate("function() { return " + script + " }"), serverResponse);
};
/**
* Executes a javascript and goes back to the client with true if there were no errors
* @param serverResponse
* @param script
* @return {*}
*/
Browser.prototype.execute = function (serverResponse, script) {
this.currentPage.execute("function() { " + script + " }");
return this.serverSendResponse(true, serverResponse);
};
/**
* If inside a frame then we will go back to the parent
* Not defined behaviour if you pop and are not inside an iframe
* @param serverResponse
* @return {*}
*/
Browser.prototype.pop_frame = function (serverResponse) {
return this.serverSendResponse(this.currentPage.popFrame(), serverResponse);
};
/**
* Gets the window handle id by a given window name
* @param serverResponse
* @param name
* @return {*}
*/
Browser.prototype.window_handle = function (serverResponse, name) {
var handle, pageByWindowName;
if (name === null || typeof name == "undefined" || name.length === 0) {
return this.serverSendResponse(this.currentPage.handle, serverResponse);
}
handle = null;
//Lets search the handle by the given window name
var filteredPages = this.pages.filter(function (p) {
return !p.closed && p.windowName() === name;
});
//A bit of error control is always good
if (Array.isArray(filteredPages) && filteredPages.length >= 1) {
pageByWindowName = filteredPages[0];
} else {
pageByWindowName = null;
}
if (pageByWindowName !== null && typeof pageByWindowName != "undefined") {
handle = pageByWindowName.handle;
}
return this.serverSendResponse(handle, serverResponse);
};
/**
* Returns all the window handles of opened windows
* @param serverResponse
* @return {*}
*/
Browser.prototype.window_handles = function (serverResponse) {
var handles, filteredPages;
filteredPages = this.pages.filter(function (p) {
return !p.closed;
});
if (filteredPages.length > 0) {
handles = filteredPages.map(function (p) {
return p.handle;
});
if (handles.length === 0) {
handles = null;
}
} else {
handles = null;
}
return this.serverSendResponse(handles, serverResponse);
};
/**
* Tries to switch to a window given by the handle id
* @param serverResponse
* @param handle
* @return {*}
*/
Browser.prototype.switch_to_window = function (serverResponse, handle) {
var page;
var self = this;
page = this.getPageByHandle(handle);
if (page === null || typeof page == "undefined") {
throw new Poltergeist.NoSuchWindowError;
}
if (page !== this.currentPage) {
return page.waitState('default', function () {
self.currentPage = page;
return self.serverSendResponse(true, serverResponse);
});
}
return this.serverSendResponse(true, serverResponse);
};
/**
* Opens a new window where we can do stuff
* @param serverResponse
* @return {*}
*/
Browser.prototype.open_new_window = function (serverResponse) {
return this.execute(serverResponse, 'window.open()');
};
/**
* Closes the window given by handle name if possible
* @param serverResponse
* @param handle
* @return {*}
*/
Browser.prototype.close_window = function (serverResponse, handle) {
var page;
page = this.getPageByHandle(handle);
if (page === null || typeof page == "undefined") {
//TODO: should we throw error since we actually could not find the window?
return this.serverSendResponse(false, serverResponse);
}
//TODO: we have to add some control here to actually asses that the release has been done
page.release();
return this.serverSendResponse(true, serverResponse);
};
/**
* Generic mouse event on an element
* @param serverResponse
* @param page_id
* @param id
* @param name
* @return {number}
*/
Browser.prototype.mouse_event = function (serverResponse, page_id, id, name) {
var node;
var self = this;
node = this.node(page_id, id);
this.currentPage.state = 'mouse_event';
this.last_mouse_event = node.mouseEvent(name);
return setTimeout(function () {
if (self.currentPage.state === 'mouse_event') {
self.currentPage.state = 'default';
return self.serverSendResponse({
position: self.last_mouse_event
}, serverResponse);
} else {
return self.currentPage.waitState('default', function () {
return self.serverSendResponse({
position: self.last_mouse_event
}, serverResponse);
});
}
}, 5);
};
/**
* Simple click on the element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.click = function (serverResponse, page_id, id) {
return this.mouse_event(serverResponse, page_id, id, 'click');
};
/**
* Right click on the element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.right_click = function (serverResponse, page_id, id) {
return this.mouse_event(serverResponse, page_id, id, 'rightclick');
};
/**
* Double click on the element given by page and id
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.double_click = function (serverResponse, page_id, id) {
return this.mouse_event(serverResponse, page_id, id, 'doubleclick');
};
/**
* Executes a mousemove event on the page and given element
* @param serverResponse
* @param page_id
* @param id
* @return {*}
*/
Browser.prototype.hover = function (serverResponse, page_id, id) {
return this.mouse_event(serverResponse, page_id, id, 'mousemove');
};
/**
* Triggers a mouse click event on the given coordinates
* @param serverResponse
* @param x
* @param y
* @return {*}
*/
Browser.prototype.click_coordinates = function (serverResponse, x, y) {
var response;
this.currentPage.sendEvent('click', x, y);
response = {
click: {
x: x,
y: y
}
};
return this.serverSendResponse(response, serverResponse);
};
/**
* Drags one element into another, useful for nice javascript thingies
* @param serverResponse
* @param page_id
* @param id
* @param other_id
* @return {*}
*/
Browser.prototype.drag = function (serverResponse, page_id, id, other_id) {
this.node(page_id, id).dragTo(this.node(page_id, other_id));
return this.serverSendResponse(true, serverResponse);
};
/**
* Triggers an event on the given page and element
* @param serverResponse
* @param page_id
* @param id
* @param event
* @return {*}
*/
Browser.prototype.trigger = function (serverResponse, page_id, id, event) {
this.node(page_id, id).trigger(event);
return this.serverSendResponse(event, serverResponse);
};
/**
* Checks if two elements are equal on a dom level
* @param serverResponse
* @param page_id
* @param id
* @param other_id
* @return {*}
*/
Browser.prototype.equals = function (serverResponse, page_id, id, other_id) {
return this.serverSendResponse(this.node(page_id, id).isEqual(this.node(page_id, other_id)), serverResponse);
};
/**
* Resets the current page to a clean slate
* @param serverResponse
* @return {*}
*/
Browser.prototype.reset = function (serverResponse) {
this.resetPage();
return this.serverSendResponse(true, serverResponse);
};
/**
* Scrolls to a position given by the left, top coordinates
* @param serverResponse
* @param left
* @param top
* @return {*}
*/
Browser.prototype.scroll_to = function (serverResponse, left, top) {
this.currentPage.setScrollPosition({
left: left,
top: top
});
return this.serverSendResponse(true, serverResponse);
};
/**
* Sends keys to an element simulating as closest as possible what a user would do
* when typing
* @param serverResponse
* @param page_id
* @param id
* @param keys
* @return {*}
*/
Browser.prototype.send_keys = function (serverResponse, page_id, id, keys) {
var key, sequence, target, _i, _len;
target = this.node(page_id, id);
if (!target.containsSelection()) {
target.mouseEvent('click');
}
for (_i = 0, _len = keys.length; _i < _len; _i++) {
sequence = keys[_i];
key = sequence.key != null ? this.currentPage.keyCode(sequence.key) : sequence;
this.currentPage.sendEvent('keypress', key);
}
return this.serverSendResponse(true, serverResponse);
};
/**
* Sends a native phantomjs key event to element
* @param serverResponse
* @param page_id
* @param id
* @param keyEvent
* @param key
* @param modifier
*/
Browser.prototype.key_event = function (serverResponse, page_id, id, keyEvent, key, modifier) {
var keyEventModifierMap;
var keyEventModifier;
var target;
keyEventModifierMap = {
'none': 0x0,
'shift': 0x02000000,
'ctrl': 0x04000000,
'alt': 0x08000000,
'meta': 0x10000000
};
keyEventModifier = keyEventModifierMap[modifier];
target = this.node(page_id, id);
if (!target.containsSelection()) {
target.mouseEvent('click');
}
target.page.sendEvent(keyEvent, key, null, null, keyEventModifier);
return this.serverSendResponse(true, serverResponse);
};
/**
* Sends the rendered page in a base64 encoding
* @param serverResponse
* @param format
* @param full
* @param selector
* @return {*}
*/
Browser.prototype.render_base64 = function (serverResponse, format, full, selector) {
var encoded_image;
if (selector == null) {
selector = null;
}
this.set_clip_rect(full, selector);
encoded_image = this.currentPage.renderBase64(format);
return this.serverSendResponse(encoded_image, serverResponse);
};
/**
* Renders the current page entirely or a given selection
* @param serverResponse
* @param path
* @param full
* @param selector
* @return {*}
*/
Browser.prototype.render = function (serverResponse, path, full, selector) {
var dimensions;
if (selector == null) {
selector = null;
}
dimensions = this.set_clip_rect(full, selector);
this.currentPage.setScrollPosition({
left: 0,
top: 0
});
this.currentPage.render(path);
this.currentPage.setScrollPosition({
left: dimensions.left,
top: dimensions.top
});
return this.serverSendResponse(true, serverResponse);
};
/**
* Sets the paper size, useful when printing to PDF
* @param serverResponse
* @param size
* @return {*}
*/
Browser.prototype.set_paper_size = function (serverResponse, size) {
this.currentPage.setPaperSize(size);
return this.serverSendResponse(true, serverResponse);
};
/**
* Sets the zoom factor on the current page
* @param serverResponse
* @param zoom_factor
* @return {*}
*/
Browser.prototype.set_zoom_factor = function (serverResponse, zoom_factor) {
this.currentPage.setZoomFactor(zoom_factor);
return this.serverSendResponse(true, serverResponse);
};
/**
* Resizes the browser viewport, useful when testing mobile stuff
* @param serverResponse
* @param width
* @param height
* @return {*}
*/
Browser.prototype.resize = function (serverResponse, width, height) {
this.currentPage.setViewportSize({
width: width,
height: height
});
return this.serverSendResponse(true, serverResponse);
};
/**
* Gets the browser viewport size
* Because PhantomJS is headless (nothing is shown)
* viewportSize effectively simulates the size of the window like in a traditional browser.
* @param serverResponse
* @param handle
* @return {*}
*/
Browser.prototype.window_size = function (serverResponse, handle) {
//TODO: add support for window handles
return this.serverSendResponse(this.currentPage.viewportSize(), serverResponse);
};
/**
* Returns the network traffic that the current page has generated
* @param serverResponse
* @return {*}
*/
Browser.prototype.network_traffic = function (serverResponse) {
return this.serverSendResponse(this.currentPage.networkTraffic(), serverResponse);
};
/**
* Clears the accumulated network_traffic in the current page
* @param serverResponse
* @return {*}
*/
Browser.prototype.clear_network_traffic = function (serverResponse) {
this.currentPage.clearNetworkTraffic();
return this.serverSendResponse(true, serverResponse);
};
/**
* Gets the headers of the current page
* @param serverResponse
* @return {*}
*/
Browser.prototype.get_headers = function (serverResponse) {
return this.serverSendResponse(this.currentPage.getCustomHeaders(), serverResponse);
};
/**
* Set headers in the browser
* @param serverResponse
* @param headers
* @return {*}
*/
Browser.prototype.set_headers = function (serverResponse, headers) {
if (headers['User-Agent']) {
this.currentPage.setUserAgent(headers['User-Agent']);
}
this.currentPage.setCustomHeaders(headers);
return this.serverSendResponse(true, serverResponse);
};
/**
* Given an array of headers, adds them to the page
* @param serverResponse
* @param headers
* @return {*}
*/
Browser.prototype.add_headers = function (serverResponse, headers) {
var allHeaders, name, value;
allHeaders = this.currentPage.getCustomHeaders();
for (name in headers) {
if (headers.hasOwnProperty(name)) {
value = headers[name];
allHeaders[name] = value;
}
}
return this.set_headers(serverResponse, allHeaders);
};
/**
* Adds a header to the page temporary or permanently
* @param serverResponse
* @param header
* @param permanent
* @return {*}
*/
Browser.prototype.add_header = function (serverResponse, header, permanent) {
if (!permanent) {
this.currentPage.addTempHeader(header);
}
return this.add_headers(serverResponse, header);
};
/**
* Sends back the client the response headers sent from the browser when making
* the page request
* @param serverResponse
* @return {*}
*/
Browser.prototype.response_headers = function (serverResponse) {
return this.serverSendResponse(this.currentPage.responseHeaders(), serverResponse);
};
/**
* Returns the cookies of the current page being browsed
* @param serverResponse
* @return {*}
*/
Browser.prototype.cookies = function (serverResponse) {
return this.serverSendResponse(this.currentPage.cookies(), serverResponse);
};
/**
* Sets a cookie in the browser, the format of the cookies has to be the format it says
* on phantomjs documentation and as such you can set it in other domains, not on the
* current page
* @param serverResponse
* @param cookie
* @return {*}
*/
Browser.prototype.set_cookie = function (serverResponse, cookie) {
return this.serverSendResponse(phantom.addCookie(cookie), serverResponse);
};
/**
* Remove a cookie set on the current page
* @param serverResponse
* @param name
* @return {*}
*/
Browser.prototype.remove_cookie = function (serverResponse, name) {
//TODO: add error control to check if the cookie was properly deleted
this.currentPage.deleteCookie(name);
phantom.deleteCookie(name);
return this.serverSendResponse(true, serverResponse);
};
/**
* Clear the cookies in the browser
* @param serverResponse
* @return {*}
*/
Browser.prototype.clear_cookies = function (serverResponse) {
phantom.clearCookies();
return this.serverSendResponse(true, serverResponse);
};
/**
* Enables / Disables the cookies on the browser
* @param serverResponse
* @param flag
* @return {*}
*/
Browser.prototype.cookies_enabled = function (serverResponse, flag) {
phantom.cookiesEnabled = flag;
return this.serverSendResponse(true, serverResponse);
};
/**
* US19: DONE
* Sets a basic authentication credential to access a page
* THIS SHOULD BE USED BEFORE accessing a page
* @param serverResponse
* @param user
* @param password
* @return {*}
*/
Browser.prototype.set_http_auth = function (serverResponse, user, password) {
this.currentPage.setHttpAuth(user, password);
return this.serverSendResponse(true, serverResponse);
};
/**
* Sets the flag whether to fail on javascript errors or not.
* @param serverResponse
* @param value
* @return {*}
*/
Browser.prototype.set_js_errors = function (serverResponse, value) {
this.js_errors = value;
return this.serverSendResponse(true, serverResponse);
};
/**
* Sets the debug mode to boolean value
* @param serverResponse
* @param value
* @return {*}
*/
Browser.prototype.set_debug = function (serverResponse, value) {
this._debug = value;
return this.serverSendResponse(true, serverResponse);
};
/**
* Goes back in the history when possible
* @param serverResponse
* @return {*}
*/
Browser.prototype.go_back = function (serverResponse) {
var self = this;
if (this.currentPage.canGoBack()) {
this.currentPage.state = 'loading';
this.currentPage.goBack();
return this.currentPage.waitState('default', function () {
return self.serverSendResponse(true, serverResponse);
});
} else {
return this.serverSendResponse(false, serverResponse);
}
};
/**
* Reloads the page if possible
* @return {*}
*/
Browser.prototype.reload = function (serverResponse) {
var self = this;
this.currentPage.state = 'loading';
this.currentPage.reload();
return this.currentPage.waitState('default', function () {
return self.serverSendResponse(true, serverResponse);
});
};
/**
* Goes forward in the browser history if possible
* @param serverResponse
* @return {*}
*/
Browser.prototype.go_forward = function (serverResponse) {
var self = this;
if (this.currentPage.canGoForward()) {
this.currentPage.state = 'loading';
this.currentPage.goForward();
return this.currentPage.waitState('default', function () {
return self.serverSendResponse(true, serverResponse);
});
} else {
return this.serverSendResponse(false, serverResponse);
}
};
/**
* Sets the urlBlacklist for the given urls as parameters
* @return {boolean}
*/
Browser.prototype.set_url_blacklist = function (serverResponse, blackList) {
this.currentPage.urlBlacklist = Array.prototype.slice.call(blackList);
return this.serverSendResponse(true, serverResponse);
};
/**
* Runs a browser command and returns the response back to the client
* when the command has finished the execution
* @param command
* @param serverResponse
* @return {*}
*/
Browser.prototype.serverRunCommand = function (command, serverResponse) {
var commandData;
var commandArgs;
var commandName;
commandName = command.name;
commandArgs = command.args;
this.currentPage.state = 'default';
commandData = [serverResponse].concat(commandArgs);
if (typeof this[commandName] !== "function") {
//We can not run such command
throw new Poltergeist.Error();
}
return this[commandName].apply(this, commandData);
};
/**
* Sends a response back to the client who made the request
* @param response
* @param serverResponse
* @return {*}
*/
Browser.prototype.serverSendResponse = function (response, serverResponse) {
var errors;
errors = this.currentPage.errors;
this.currentPage.clearErrors();
if (errors.length > 0 && this.js_errors) {
return this.owner.serverSendError(new Poltergeist.JavascriptError(errors), serverResponse);
} else {
return this.owner.serverSendResponse(response, serverResponse);
}
};
return Browser;
})();