Skip to content

Commit

Permalink
Merge pull request #157 from gregoil/detect_server_disconnection
Browse files Browse the repository at this point in the history
Detect server disconnection
  • Loading branch information
gregoil committed Aug 11, 2019
2 parents 3f5fda1 + 01c5bd9 commit 69040f8
Show file tree
Hide file tree
Showing 3 changed files with 43 additions and 5 deletions.
7 changes: 4 additions & 3 deletions setup.py
Expand Up @@ -3,7 +3,7 @@
from setuptools import setup, find_packages


__version__ = "7.9.1"
__version__ = "7.9.2"

result_handlers = [
"db = rotest.core.result.handlers.db_handler:DBHandler",
Expand Down Expand Up @@ -34,7 +34,7 @@
url="https://github.com/gregoil/rotest",
keywords="testing system django unittest",
install_requires=[
'django>=1.8,<2.0',
'django>=1.8,<2',
'py',
'ipdbugger>=2.5',
'xlwt',
Expand All @@ -50,7 +50,7 @@
'cached_property',
'channels>=1,<2',
'websocket-client>=0.56',
'pywin32<224; sys.platform == "win32"'
'pywin32<224; sys.platform == "win32"',
],
extras_require={
':python_version=="2.7"': ['statistics'],
Expand All @@ -64,6 +64,7 @@
"pathlib2",
"flake8",
"pylint",
"waiting",
]
},
python_requires=">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*",
Expand Down
11 changes: 9 additions & 2 deletions src/rotest/management/client/websocket_client.py
@@ -1,17 +1,19 @@
"""Websocket client that sends pings periodically."""
# pylint: disable=broad-except,bare-except
# pylint: disable=broad-except,bare-except,no-self-use
import threading

import websocket

from rotest.common import core_log


class PingingWebsocket(websocket.WebSocket):
"""Websocket client that sends pings periodically.
Attributes:
ping_interval (number): interval between pings in seconds, default 15.
"""
def __init__(self, ping_interval=15, *args, **kwargs):
def __init__(self, ping_interval=10, *args, **kwargs):
super(PingingWebsocket, self).__init__(*args, **kwargs)
self.ping_interval = ping_interval
self.pinging_thread = None
Expand All @@ -32,11 +34,16 @@ def close(self, *args, **kwargs):
self.pinging_event.set()
self.pinging_thread.join()

def handle_disconnection(self):
"""Called on server disconnection."""
core_log.warning("Server disconnetion detected!")

def ping_loop(self):
"""Ping periodically until the finish event."""
while not self.pinging_event.wait(self.ping_interval):
try:
self.send("ping")

except: # noqa
self.handle_disconnection()
break
30 changes: 30 additions & 0 deletions tests/management/test_resource_manager.py
Expand Up @@ -9,8 +9,10 @@
import time

from threading import Thread
from unittest import TestCase

import mock
from waiting import wait
from future.builtins import zip, range
from django.db.models.query_utils import Q
from django.contrib.auth.models import User
Expand All @@ -20,10 +22,12 @@
from rotest.management import BaseResource, ResourceRequest
from rotest.management.models.resource_data import DataPointer
from rotest.management.client.manager import ClientResourceManager
from rotest.management.client.websocket_client import PingingWebsocket
from rotest.management.common.resource_descriptor import \
ResourceDescriptor as Descriptor
from rotest.management.models.ut_models import (DemoResourceData,
DemoComplexResourceData)

from rotest.management.models.ut_resources import (DemoService,
DemoResource,
DemoComplexResource)
Expand Down Expand Up @@ -2036,3 +2040,29 @@ def test_locking_resource_with_group_none(self):
% (self.NO_GROUP_RESOURCE, resource.name))

self.get_resource(self.NO_GROUP_RESOURCE, owner="")


class ClientWebsocketTests(TestCase):
"""Tests for client behavior."""

TEST_ADDRESS = 'localhost'

@mock.patch('websocket._core.handshake')
@mock.patch('websocket._core.connect')
@mock.patch('rotest.management.client.websocket_client.'
'PingingWebsocket.handle_disconnection')
def test_server_disconnection(self, mock_callback, mock_connect, _):
"""Check that 'close_session' is called at disconnect."""
client = PingingWebsocket(ping_interval=0.2)
mock_socket = mock.MagicMock()
mock_connect.return_value = mock_socket, self.TEST_ADDRESS
client.connect(self.TEST_ADDRESS)
wait(lambda: mock_socket.send.call_count > 1,
timeout_seconds=2, sleep_seconds=0.1,
waiting_for='Waiting for 2 pings')

mock_callback.assert_not_called()
mock_socket.send.side_effect = RuntimeError
wait(lambda: mock_callback.call_count > 0,
timeout_seconds=2, sleep_seconds=0.1,
waiting_for='Waiting for disconnection')

0 comments on commit 69040f8

Please sign in to comment.