PJLink2 update V04

bzr-revno: 2865
This commit is contained in:
Ken Roberts 2019-05-04 20:28:49 +01:00 committed by Tim Bentley
commit 3b179c74a0
7 changed files with 373 additions and 223 deletions

View File

@ -106,6 +106,9 @@ S_WARMUP = 314
S_ON = 315 S_ON = 315
S_COOLDOWN = 316 S_COOLDOWN = 316
S_INFO = 317 S_INFO = 317
S_CONNECT = 318 # Initial connection, connected
S_AUTHENTICATE = 319 # Initial connection, send pin hash
S_DATA_OK = 320 # Previous command returned OK
# Information that does not affect status # Information that does not affect status
S_NETWORK_IDLE = 400 S_NETWORK_IDLE = 400
@ -369,11 +372,14 @@ STATUS_CODE = {
E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR', E_UNKNOWN_SOCKET_ERROR: 'E_UNKNOWN_SOCKET_ERROR',
E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION', E_UNSUPPORTED_SOCKET_OPERATION: 'E_UNSUPPORTED_SOCKET_OPERATION',
E_WARN: 'E_WARN', E_WARN: 'E_WARN',
S_AUTHENTICATE: 'S_AUTHENTICATE',
S_BOUND: 'S_BOUND', S_BOUND: 'S_BOUND',
S_CONNECT: 'S_CONNECT',
S_COOLDOWN: 'S_COOLDOWN', S_COOLDOWN: 'S_COOLDOWN',
S_CLOSING: 'S_CLOSING', S_CLOSING: 'S_CLOSING',
S_CONNECTED: 'S_CONNECTED', S_CONNECTED: 'S_CONNECTED',
S_CONNECTING: 'S_CONNECTING', S_CONNECTING: 'S_CONNECTING',
S_DATA_OK: 'S_DATA_OK',
S_HOST_LOOKUP: 'S_HOST_LOOKUP', S_HOST_LOOKUP: 'S_HOST_LOOKUP',
S_INFO: 'S_INFO', S_INFO: 'S_INFO',
S_INITIALIZE: 'S_INITIALIZE', S_INITIALIZE: 'S_INITIALIZE',
@ -387,7 +393,7 @@ STATUS_CODE = {
S_ON: 'S_ON', S_ON: 'S_ON',
S_STANDBY: 'S_STANDBY', S_STANDBY: 'S_STANDBY',
S_STATUS: 'S_STATUS', S_STATUS: 'S_STATUS',
S_WARMUP: 'S_WARMUP', S_WARMUP: 'S_WARMUP'
} }
# Map status codes to message strings # Map status codes to message strings
@ -459,11 +465,14 @@ STATUS_MSG = {
'The requested socket operation is not supported by the local ' 'The requested socket operation is not supported by the local '
'operating system (e.g., lack of IPv6 support)'), 'operating system (e.g., lack of IPv6 support)'),
E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'), E_WARN: translate('OpenLP.ProjectorConstants', 'Warning condition detected'),
S_AUTHENTICATE: translate('OpenLP.ProjectorConstants', 'Connection initializing with pin'),
S_BOUND: translate('OpenLP.ProjectorConstants', 'Socket is bount to an address or port'), S_BOUND: translate('OpenLP.ProjectorConstants', 'Socket is bount to an address or port'),
S_CONNECT: translate('OpenLP.ProjectorConstants', 'Connection initializing'),
S_CLOSING: translate('OpenLP.ProjectorConstants', 'Socket is about to close'), S_CLOSING: translate('OpenLP.ProjectorConstants', 'Socket is about to close'),
S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'), S_CONNECTED: translate('OpenLP.ProjectorConstants', 'Connected'),
S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'), S_CONNECTING: translate('OpenLP.ProjectorConstants', 'Connecting'),
S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'), S_COOLDOWN: translate('OpenLP.ProjectorConstants', 'Cooldown in progress'),
S_DATA_OK: translate('OpenLP.ProjectorConstants', 'Command returned with OK'),
S_HOST_LOOKUP: translate('OpenLP.ProjectorConstants', 'Performing a host name lookup'), S_HOST_LOOKUP: translate('OpenLP.ProjectorConstants', 'Performing a host name lookup'),
S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'), S_INFO: translate('OpenLP.ProjectorConstants', 'Projector Information available'),
S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'), S_INITIALIZE: translate('OpenLP.ProjectorConstants', 'Initialize in progress'),

View File

@ -52,14 +52,15 @@ from copy import copy
from PyQt5 import QtCore, QtNetwork from PyQt5 import QtCore, QtNetwork
from openlp.core.common import qmd5_hash
from openlp.core.common.i18n import translate from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
from openlp.core.projectors.pjlinkcommands import process_command from openlp.core.projectors.pjlinkcommands import process_command
from openlp.core.projectors.constants import CONNECTION_ERRORS, E_CONNECTION_REFUSED, E_GENERAL, \ from openlp.core.projectors.constants import CONNECTION_ERRORS, E_AUTHENTICATION, E_CONNECTION_REFUSED, E_GENERAL, \
E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, PJLINK_CLASS, \ E_NETWORK, E_NOT_CONNECTED, E_SOCKET_TIMEOUT, PJLINK_CLASS, \
PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_PREFIX, PJLINK_SUFFIX, \ PJLINK_MAX_PACKET, PJLINK_PORT, PJLINK_PREFIX, PJLINK_SUFFIX, \
PJLINK_VALID_CMD, PROJECTOR_STATE, QSOCKET_STATE, S_CONNECTED, S_CONNECTING, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, \ PJLINK_VALID_CMD, PROJECTOR_STATE, QSOCKET_STATE, S_AUTHENTICATE, S_CONNECT, S_CONNECTED, S_CONNECTING, \
STATUS_CODE, STATUS_MSG S_DATA_OK, S_NOT_CONNECTED, S_OFF, S_OK, S_ON, STATUS_CODE, STATUS_MSG
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -565,21 +566,10 @@ class PJLink(QtNetwork.QTcpSocket):
# V = PJLink class or version # V = PJLink class or version
# C = PJLink command # C = PJLink command
version, cmd = header[1], header[2:].upper() version, cmd = header[1], header[2:].upper()
log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name, log.debug('({ip}) get_data() version="{version}" cmd="{cmd}" data="{data}"'.format(ip=self.entry.name,
version=version, cmd=cmd)) version=version,
# TODO: Below commented for now since it seems to cause issues with testing some invalid data. cmd=cmd,
# Revisit after more refactoring is finished. data=data))
'''
try:
version, cmd = header[1], header[2:].upper()
log.debug('({ip}) get_data() version="{version}" cmd="{cmd}"'.format(ip=self.entry.name,
version=version, cmd=cmd))
except ValueError as e:
self.change_status(E_INVALID_DATA)
log.warning('({ip}) get_data(): Received data: "{data}"'.format(ip=self.entry.name, data=data_in))
self._trash_buffer('get_data(): Expected header + command + data')
return self.receive_data_signal()
'''
if cmd not in PJLINK_VALID_CMD: if cmd not in PJLINK_VALID_CMD:
self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(data=cmd)) self._trash_buffer('get_data(): Invalid packet - unknown command "{data}"'.format(data=cmd))
return self.receive_data_signal() return self.receive_data_signal()
@ -590,7 +580,38 @@ class PJLink(QtNetwork.QTcpSocket):
if not ignore_class: if not ignore_class:
log.warning('({ip}) get_data(): Projector returned class reply higher ' log.warning('({ip}) get_data(): Projector returned class reply higher '
'than projector stated class'.format(ip=self.entry.name)) 'than projector stated class'.format(ip=self.entry.name))
process_command(self, cmd, data) return self.receive_data_signal()
chk = process_command(self, cmd, data)
if chk is None:
# Command processed normally and not initial connection, so skip other checks
return self.receive_data_signal()
# PJLink initial connection checks
elif chk == S_DATA_OK:
# Previous command returned OK
log.debug('({ip}) OK returned - resending command'.format(ip=self.entry.name))
self.send_command(cmd=cmd, priority=True)
elif chk == S_CONNECT:
# Normal connection
log.debug('({ip}) Connecting normal'.format(ip=self.entry.name))
self.change_status(S_CONNECTED)
self.send_command(cmd='CLSS', priority=True)
self.readyRead.connect(self.get_socket)
elif chk == S_AUTHENTICATE:
# Connection with pin
log.debug('({ip}) Connecting with pin'.format(ip=self.entry.name))
data_hash = str(qmd5_hash(salt=chk[1].encode('utf-8'), data=self.pin.encode('utf-8')),
encoding='ascii')
self.change_status(S_CONNECTED)
self.readyRead.connect(self.get_socket)
self.send_command(cmd='CLSS', salt=data_hash, priority=True)
elif chk == E_AUTHENTICATION:
# Projector did not like our pin
log.warning('({ip}) Failed authentication - disconnecting'.format(ip=self.entry.name))
self.disconnect_from_host()
self.projectorAuthentication.emit(self.entry.name)
self.change_status(status=E_AUTHENTICATION)
return self.receive_data_signal() return self.receive_data_signal()
@QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError) @QtCore.pyqtSlot(QtNetwork.QAbstractSocket.SocketError)
@ -631,7 +652,9 @@ class PJLink(QtNetwork.QTcpSocket):
:param salt: Optional salt for md5 hash initial authentication :param salt: Optional salt for md5 hash initial authentication
:param priority: Option to send packet now rather than queue it up :param priority: Option to send packet now rather than queue it up
""" """
if QSOCKET_STATE[self.state()] != QSOCKET_STATE[S_CONNECTED]: log.debug('({ip}) send_command(cmd="{cmd}" opts="{opts}" salt="{salt}" '
'priority={pri}'.format(ip=self.entry.name, cmd=cmd, opts=opts, salt=salt, pri=priority))
if QSOCKET_STATE[self.state()] != S_CONNECTED:
log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.entry.name)) log.warning('({ip}) send_command(): Not connected - returning'.format(ip=self.entry.name))
return self.reset_information() return self.reset_information()
if cmd not in PJLINK_VALID_CMD: if cmd not in PJLINK_VALID_CMD:
@ -640,11 +663,11 @@ class PJLink(QtNetwork.QTcpSocket):
# Just in case there's already something to send # Just in case there's already something to send
return self._send_command() return self._send_command()
return return
log.debug('({ip}) send_command(): Building cmd="{command}" opts="{data}"{salt}'.format(ip=self.entry.name, log.debug('({ip}) send_command(): Building cmd="{command}" opts="{data}" '
'{salt}'.format(ip=self.entry.name,
command=cmd, command=cmd,
data=opts, data=opts,
salt='' if salt is None salt='' if salt is None else 'with hash'))
else ' with hash'))
# Until we absolutely have to start doing version checks, use the default # Until we absolutely have to start doing version checks, use the default
# for PJLink class # for PJLink class
header = PJLINK_HEADER.format(linkclass=PJLINK_VALID_CMD[cmd]['default']) header = PJLINK_HEADER.format(linkclass=PJLINK_VALID_CMD[cmd]['default'])

View File

@ -30,14 +30,12 @@ NOTE: PJLink Class (version) checks are handled in the respective PJLink/PJLinkU
import logging import logging
import re import re
from openlp.core.common import qmd5_hash
from openlp.core.common.i18n import translate from openlp.core.common.i18n import translate
from openlp.core.common.settings import Settings from openlp.core.common.settings import Settings
from openlp.core.projectors.constants import E_AUTHENTICATION, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \ from openlp.core.projectors.constants import E_AUTHENTICATION, PJLINK_DEFAULT_CODES, PJLINK_ERRORS, \
PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_POWR_STATUS, S_CONNECTED, S_OFF, S_OK, S_ON, S_STANDBY, \ PJLINK_ERST_DATA, PJLINK_ERST_STATUS, PJLINK_POWR_STATUS, S_AUTHENTICATE, S_CONNECT, S_DATA_OK, S_OFF, S_OK, S_ON, \
STATUS_MSG S_STANDBY, STATUS_MSG
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
log.debug('Loading pjlinkcommands') log.debug('Loading pjlinkcommands')
@ -68,19 +66,18 @@ def process_command(projector, cmd, data):
elif _data == 'OK': elif _data == 'OK':
log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=projector.entry.name, cmd=cmd)) log.debug('({ip}) Command "{cmd}" returned OK'.format(ip=projector.entry.name, cmd=cmd))
# A command returned successfully, so do a query on command to verify status # A command returned successfully, so do a query on command to verify status
return projector.send_command(cmd=cmd, priority=True) return S_DATA_OK
elif _data in PJLINK_ERRORS: elif _data in PJLINK_ERRORS:
# Oops - projector error # Oops - projector error
log.error('({ip}) {cmd}: {err}'.format(ip=projector.entry.name, log.error('({ip}) {cmd}: {err}'.format(ip=projector.entry.name,
cmd=cmd, cmd=cmd,
err=STATUS_MSG[PJLINK_ERRORS[_data]])) err=STATUS_MSG[PJLINK_ERRORS[_data]]))
if PJLINK_ERRORS[_data] == E_AUTHENTICATION: return PJLINK_ERRORS[_data]
projector.disconnect_from_host()
projector.projectorAuthentication.emit(projector.name)
return projector.change_status(status=E_AUTHENTICATION)
# Command checks already passed # Command checks already passed
log.debug('({ip}) Calling function for {cmd}'.format(ip=projector.entry.name, cmd=cmd)) log.debug('({ip}) Calling function for {cmd}'.format(ip=projector.entry.name, cmd=cmd))
pjlink_functions[cmd](projector=projector, data=data) return pjlink_functions[cmd](projector=projector, data=data)
def process_ackn(projector, data): def process_ackn(projector, data):
@ -376,35 +373,28 @@ def process_pjlink(projector, data):
if len(chk[0]) != 1: if len(chk[0]) != 1:
# Invalid - after splitting, first field should be 1 character, either '0' or '1' only # Invalid - after splitting, first field should be 1 character, either '0' or '1' only
log.error('({ip}) Invalid initial authentication scheme - aborting'.format(ip=projector.entry.name)) log.error('({ip}) Invalid initial authentication scheme - aborting'.format(ip=projector.entry.name))
return projector.disconnect_from_host() return E_AUTHENTICATION
elif chk[0] == '0': elif chk[0] == '0':
# Normal connection no authentication # Normal connection no authentication
if len(chk) > 1: if len(chk) > 1:
# Invalid data - there should be nothing after a normal authentication scheme # Invalid data - there should be nothing after a normal authentication scheme
log.error('({ip}) Normal connection with extra information - aborting'.format(ip=projector.entry.name)) log.error('({ip}) Normal connection with extra information - aborting'.format(ip=projector.entry.name))
return projector.disconnect_from_host() return E_AUTHENTICATION
elif projector.pin: elif projector.pin:
log.error('({ip}) Normal connection but PIN set - aborting'.format(ip=projector.entry.name)) log.error('({ip}) Normal connection but PIN set - aborting'.format(ip=projector.entry.name))
return projector.disconnect_from_host() return E_AUTHENTICATION
else: log.debug('({ip}) PJLINK: Returning S_CONNECT'.format(ip=projector.entry.name))
data_hash = None return S_CONNECT
elif chk[0] == '1': elif chk[0] == '1':
if len(chk) < 2: if len(chk) < 2:
# Not enough information for authenticated connection # Not enough information for authenticated connection
log.error('({ip}) Authenticated connection but not enough info - aborting'.format(ip=projector.entry.name)) log.error('({ip}) Authenticated connection but not enough info - aborting'.format(ip=projector.entry.name))
return projector.disconnect_from_host() return E_AUTHENTICATION
elif not projector.pin: elif not projector.pin:
log.error('({ip}) Authenticate connection but no PIN - aborting'.format(ip=projector.entry.name)) log.error('({ip}) Authenticate connection but no PIN - aborting'.format(ip=projector.entry.name))
return projector.disconnect_from_host() return E_AUTHENTICATION
else: log.debug('({ip}) PJLINK: Returning S_AUTHENTICATE'.format(ip=projector.entry.name))
data_hash = str(qmd5_hash(salt=chk[1].encode('utf-8'), data=projector.pin.encode('utf-8')), return S_AUTHENTICATE
encoding='ascii')
# Passed basic checks, so start connection
projector.readyRead.connect(projector.get_socket)
projector.change_status(S_CONNECTED)
log.debug('({ip}) process_pjlink(): Sending "CLSS" initial command'.format(ip=projector.entry.name))
# Since this is an initial connection, make it a priority just in case
return projector.send_command(cmd="CLSS", salt=data_hash, priority=True)
def process_powr(projector, data): def process_powr(projector, data):

View File

@ -0,0 +1,132 @@
# -*- coding: utf-8 -*-
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
##########################################################################
# OpenLP - Open Source Lyrics Projection #
# ---------------------------------------------------------------------- #
# Copyright (c) 2008-2019 OpenLP Developers #
# ---------------------------------------------------------------------- #
# This program is free software: you can redistribute it and/or modify #
# it under the terms of the GNU General Public License as published by #
# the Free Software Foundation, either version 3 of the License, or #
# (at your option) any later version. #
# #
# This program is distributed in the hope that it will be useful, #
# but WITHOUT ANY WARRANTY; without even the implied warranty of #
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the #
# GNU General Public License for more details. #
# #
# You should have received a copy of the GNU General Public License #
# along with this program. If not, see <https://www.gnu.org/licenses/>. #
##########################################################################
"""
Package to test the openlp.core.projectors.pjlink command routing.
"""
from unittest import TestCase
from unittest.mock import call, patch
import openlp.core.projectors.pjlink
from openlp.core.projectors.pjlinkcommands import process_command
from openlp.core.projectors.constants import E_UNDEFINED, S_DATA_OK
from openlp.core.projectors.db import Projector
from openlp.core.projectors.pjlink import PJLink
from tests.resources.projector.data import TEST1_DATA
class TestPJLinkRouting(TestCase):
"""
Tests for the PJLink module command routing
"""
def setUp(self):
"""
Setup test environment
"""
self.pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
def tearDown(self):
"""
Reset test environment
"""
del(self.pjlink)
@patch.object(openlp.core.projectors.pjlinkcommands, 'log')
def test_routing_command(self, mock_log):
"""
Test process_command receiving command not in function map
"""
# GIVEN: Test setup
log_warning_text = []
log_debug_text = [call('({ip}) Processing command "CLSS" with data "1"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name)),
call('({ip}) Setting pjlink_class for this projector to "1"'.format(ip=self.pjlink.name))]
# WHEN: called with valid command and data
chk = process_command(projector=self.pjlink, cmd='CLSS', data='1')
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.warning.assert_has_calls(log_warning_text)
mock_log.debug.assert_has_calls(log_debug_text)
assert (chk is None), 'process_clss() should have returned None'
@patch.object(openlp.core.projectors.pjlinkcommands, 'process_clss')
@patch.object(openlp.core.projectors.pjlinkcommands, 'pjlink_functions')
@patch.object(openlp.core.projectors.pjlinkcommands, 'log')
def test_routing_command_unknown(self, mock_log, mock_functions, mock_clss):
"""
Test process_command receiving command not in function map
"""
# GIVEN: Test setup
log_warning_text = [call('({ip}) Unable to process command="CLSS" '
'(Future option?)'.format(ip=self.pjlink.name))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "?"'.format(ip=self.pjlink.name))]
# Fake CLSS command is not in list
mock_functions.__contains__.return_value = False
# WHEN: called with unknown command
process_command(projector=self.pjlink, cmd='CLSS', data='?')
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.warning.assert_has_calls(log_warning_text)
mock_log.debug.assert_has_calls(log_debug_text)
assert (mock_functions.__contains__.call_count == 1), 'pjlink_functions should have been accessed only once'
assert (not mock_clss.called), 'Should not have called process_clss'
@patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command')
@patch.object(openlp.core.projectors.pjlinkcommands, 'process_clss')
@patch.object(openlp.core.projectors.pjlinkcommands, 'log')
def test_routing_data_ok(self, mock_log, mock_clss, mock_send):
"""
Test process_command calls function and sets appropriate value(s) in projector instance
"""
# GIVEN: Test setup
log_debug_text = [call('({ip}) Processing command "CLSS" with data "OK"'.format(ip=self.pjlink.name)),
call('({ip}) Command "CLSS" returned OK'.format(ip=self.pjlink.name))
]
# WHEN: Command called with OK
chk = process_command(projector=self.pjlink, cmd='CLSS', data='OK')
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.debug.asset_has_calls(log_debug_text)
mock_send.assert_not_called()
mock_clss.assert_not_called()
assert (chk == S_DATA_OK), 'Should have returned S_DATA_OK'
@patch.object(openlp.core.projectors.pjlinkcommands, 'log')
def test_routing_pjink_errors(self, mock_log):
"""
Test rouing when PJLink error received (err1, err2, err3, err4, erra)
"""
# GIVEN: Test setup
log_error_text = [call('({ip}) CLSS: PJLink returned "ERR1: Undefined Command"'.format(ip=self.pjlink.name))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR1"'.format(ip=self.pjlink.name))]
err_code = E_UNDEFINED
# WHEN: routing called
chk = process_command(projector=self.pjlink, cmd='CLSS', data='ERR1')
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
assert (chk == err_code), 'Should have returned E_UNDEFINED'

View File

@ -40,11 +40,12 @@ class TestProjectorConstants(TestCase):
missing_str = [] missing_str = []
# GIVEN: List of defined E_* and S_* items defined in constants # GIVEN: List of defined E_* and S_* items defined in constants
for item in constants.__dict__: for item in constants.__dict__:
if item.startswith('E_') or item.startswith('S_'): if item.startswith('E_') or item.startswith('S_'):
check.append(item) check.append(item)
# WHEN: Verify defined list against STATUS_STR # WHEN: Verify items were addeded to check
for item in check: for item in check:
if constants.__dict__[item] not in STATUS_CODE: if constants.__dict__[item] not in STATUS_CODE:
missing_str.append(item) missing_str.append(item)

View File

@ -456,7 +456,7 @@ class TestPJLinkBase(TestCase):
log_warning_calls = [] log_warning_calls = []
log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name)), log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name)),
call('({ip}) send_command(): Adding to normal queue'.format(ip=self.pjlink.name))] call('({ip}) send_command(): Adding to normal queue'.format(ip=self.pjlink.name))]
mock_state.return_value = S_CONNECTED mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
# Patch here since pjlink does not have priority or send queue's until instantiated # Patch here since pjlink does not have priority or send queue's until instantiated
with patch.object(self.pjlink, 'send_queue') as mock_send, \ with patch.object(self.pjlink, 'send_queue') as mock_send, \
@ -490,7 +490,7 @@ class TestPJLinkBase(TestCase):
log_warning_calls = [] log_warning_calls = []
log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name)), log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name)),
call('({ip}) send_command(): Adding to priority queue'.format(ip=self.pjlink.name))] call('({ip}) send_command(): Adding to priority queue'.format(ip=self.pjlink.name))]
mock_state.return_value = S_CONNECTED mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
# Patch here since pjlink does not have priority or send queue's until instantiated # Patch here since pjlink does not have priority or send queue's until instantiated
with patch.object(self.pjlink, 'send_queue') as mock_send, \ with patch.object(self.pjlink, 'send_queue') as mock_send, \
@ -523,8 +523,10 @@ class TestPJLinkBase(TestCase):
log_error_calls = [] log_error_calls = []
log_warning_calls = [call('({ip}) send_command(): Already in normal queue - ' log_warning_calls = [call('({ip}) send_command(): Already in normal queue - '
'skipping'.format(ip=self.pjlink.name))] 'skipping'.format(ip=self.pjlink.name))]
log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?"'.format(ip=self.pjlink.name))] log_debug_calls = [call('({ip}) send_command(cmd="CLSS" opts="?" salt="None" '
mock_state.return_value = S_CONNECTED 'priority=False'.format(ip=self.pjlink.name)),
call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name))]
mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
self.pjlink.send_queue = [test_command] self.pjlink.send_queue = [test_command]
self.pjlink.priority_queue = [] self.pjlink.priority_queue = []
@ -555,8 +557,10 @@ class TestPJLinkBase(TestCase):
log_error_calls = [] log_error_calls = []
log_warning_calls = [call('({ip}) send_command(): Already in priority queue - ' log_warning_calls = [call('({ip}) send_command(): Already in priority queue - '
'skipping'.format(ip=self.pjlink.name))] 'skipping'.format(ip=self.pjlink.name))]
log_debug_calls = [call('({ip}) send_command(): Building cmd="CLSS" opts="?"'.format(ip=self.pjlink.name))] log_debug_calls = [call('({ip}) send_command(cmd="CLSS" opts="?" salt="None" '
mock_state.return_value = S_CONNECTED 'priority=True'.format(ip=self.pjlink.name)),
call('({ip}) send_command(): Building cmd="CLSS" opts="?" '.format(ip=self.pjlink.name))]
mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
self.pjlink.send_queue = [] self.pjlink.send_queue = []
self.pjlink.priority_queue = [test_command] self.pjlink.priority_queue = [test_command]
@ -585,7 +589,7 @@ class TestPJLinkBase(TestCase):
'ignoring.'.format(ip=self.pjlink.name))] 'ignoring.'.format(ip=self.pjlink.name))]
log_warning_calls = [] log_warning_calls = []
log_debug_calls = [] log_debug_calls = []
mock_state.return_value = S_CONNECTED mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
self.pjlink.send_queue = [] self.pjlink.send_queue = []
self.pjlink.priority_queue = [] self.pjlink.priority_queue = []
@ -617,7 +621,7 @@ class TestPJLinkBase(TestCase):
'ignoring.'.format(ip=self.pjlink.name))] 'ignoring.'.format(ip=self.pjlink.name))]
log_warning_calls = [] log_warning_calls = []
log_debug_calls = [] log_debug_calls = []
mock_state.return_value = S_CONNECTED mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
self.pjlink.send_queue = [test_command] self.pjlink.send_queue = [test_command]
self.pjlink.priority_queue = [] self.pjlink.priority_queue = []
@ -649,7 +653,7 @@ class TestPJLinkBase(TestCase):
'ignoring.'.format(ip=self.pjlink.name))] 'ignoring.'.format(ip=self.pjlink.name))]
log_warning_calls = [] log_warning_calls = []
log_debug_calls = [] log_debug_calls = []
mock_state.return_value = S_CONNECTED mock_state.return_value = QSOCKET_STATE[S_CONNECTED]
self.pjlink.send_queue = [] self.pjlink.send_queue = []
self.pjlink.priority_queue = [test_command] self.pjlink.priority_queue = [test_command]

View File

@ -24,10 +24,9 @@ Package to test the openlp.core.projectors.pjlink command routing.
""" """
from unittest import TestCase, skip from unittest import TestCase, skip
from unittest.mock import MagicMock, call, patch from unittest.mock import call, patch
import openlp.core.projectors.pjlink import openlp.core.projectors.pjlink
from openlp.core.projectors.pjlinkcommands import process_command
from openlp.core.projectors.constants import E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED, \ from openlp.core.projectors.constants import E_AUTHENTICATION, E_PARAMETER, E_PROJECTOR, E_UNAVAILABLE, E_UNDEFINED, \
PJLINK_ERRORS, PJLINK_PREFIX, STATUS_MSG PJLINK_ERRORS, PJLINK_PREFIX, STATUS_MSG
from openlp.core.projectors.db import Projector from openlp.core.projectors.db import Projector
@ -51,54 +50,181 @@ class TestPJLinkRouting(TestCase):
""" """
del(self.pjlink) del(self.pjlink)
@patch.object(openlp.core.projectors.pjlinkcommands, 'process_command')
@patch.object(openlp.core.projectors.pjlink, 'log') @patch.object(openlp.core.projectors.pjlink, 'log')
def test_get_data_unknown_command(self, mock_log): def test_projector_get_data_invalid_version(self, mock_log, mock_process_cmd):
""" """
Test not a valid command Test projector received valid command invalid version
"""
# GIVEN: Test object
log_warning_text = [call('({ip}) get_data() Command reply version does not match '
'a valid command version'.format(ip=self.pjlink.name)),
call('({ip}) _send_command(): Nothing to send - returning'.format(ip=self.pjlink.name))]
log_debug_text = [call('({ip}) get_data(buffer="{pre}XCLSS=X"'.format(ip=self.pjlink.name, pre=PJLINK_PREFIX)),
call('({ip}) get_data(): Checking new data "{pre}XCLSS=X"'.format(ip=self.pjlink.name,
pre=PJLINK_PREFIX)),
call('({ip}) get_data() header="{pre}XCLSS" data="X"'.format(ip=self.pjlink.name,
pre=PJLINK_PREFIX)),
call('({ip}) get_data() version="X" cmd="CLSS" data="X"'.format(ip=self.pjlink.name)),
call('({ip}) Cleaning buffer - msg = "get_data() Command reply version does '
'not match a valid command version"'.format(ip=self.pjlink.name)),
call('({ip}) Finished cleaning buffer - 0 bytes dropped'.format(ip=self.pjlink.name))]
# WHEN: get_data called with an unknown command
self.pjlink.get_data(buff='{prefix}XCLSS=X'.format(prefix=PJLINK_PREFIX))
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.warning.assert_has_calls(log_warning_text)
mock_log.debug.assert_has_calls(log_debug_text)
assert (mock_process_cmd.call_count == 0), 'process_command should not have been called'
@patch.object(openlp.core.projectors.pjlinkcommands, 'process_command')
@patch.object(openlp.core.projectors.pjlink, 'log')
def test_projector_get_data_unknown_command(self, mock_log, mock_process_cmd):
"""
Test projector receiving invalid command
""" """
# GIVEN: Test object # GIVEN: Test object
self.pjlink.pjlink_functions = MagicMock()
log_warning_text = [call('({ip}) get_data(): Invalid packet - ' log_warning_text = [call('({ip}) get_data(): Invalid packet - '
'unknown command "UNKN"'.format(ip=self.pjlink.name)), 'unknown command "UNKN"'.format(ip=self.pjlink.name)),
call('({ip}) _send_command(): Nothing to send - ' call('({ip}) _send_command(): Nothing to send - '
'returning'.format(ip=self.pjlink.name))] 'returning'.format(ip=self.pjlink.name))]
log_debug_text = [call('(___TEST_ONE___) get_data(buffer="%1UNKN=Huh?"'), log_debug_text = [call('({ip}) get_data(buffer="{pre}1UNKN=Huh?"'.format(ip=self.pjlink.name,
call('(___TEST_ONE___) get_data(): Checking new data "%1UNKN=Huh?"'), pre=PJLINK_PREFIX)),
call('(___TEST_ONE___) get_data() header="%1UNKN" data="Huh?"'), call('({ip}) get_data(): Checking new data "{pre}1UNKN=Huh?"'.format(ip=self.pjlink.name,
call('(___TEST_ONE___) get_data() version="1" cmd="UNKN"'), pre=PJLINK_PREFIX)),
call('(___TEST_ONE___) Cleaning buffer - msg = "get_data(): ' call('({ip}) get_data() header="{pre}1UNKN" data="Huh?"'.format(ip=self.pjlink.name,
'Invalid packet - unknown command "UNKN""'), pre=PJLINK_PREFIX)),
call('(___TEST_ONE___) Finished cleaning buffer - 0 bytes dropped')] call('({ip}) get_data() version="1" cmd="UNKN" data="Huh?"'.format(ip=self.pjlink.name)),
call('({ip}) Cleaning buffer - msg = "get_data(): Invalid packet - '
'unknown command "UNKN""'.format(ip=self.pjlink.name)),
call('({ip}) Finished cleaning buffer - 0 bytes dropped'.format(ip=self.pjlink.name))]
# WHEN: get_data called with an unknown command # WHEN: get_data called with an unknown command
self.pjlink.get_data(buff='{prefix}1UNKN=Huh?'.format(prefix=PJLINK_PREFIX)) self.pjlink.get_data(buff='{prefix}1UNKN=Huh?'.format(prefix=PJLINK_PREFIX))
# THEN: Appropriate log entries should have been made and methods called/not called # THEN: Appropriate log entries should have been made and methods called/not called
mock_log.warning.assert_has_calls(log_warning_text) mock_log.warning.assert_has_calls(log_warning_text)
mock_log.debug.assert_has_calls(log_debug_text) mock_log.debug.assert_has_calls(log_debug_text)
assert self.pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions' assert (mock_process_cmd.call_count == 0), 'process_command should not have been called'
@patch.object(openlp.core.projectors.pjlinkcommands, 'process_command')
@patch.object(openlp.core.projectors.pjlink, 'log')
def test_projector_get_data_version_mismatch(self, mock_log, mock_process_cmd):
"""
Test projector received valid command with command version higher than projector
"""
# GIVEN: Test object
log_warning_text = [call('({ip}) get_data(): Projector returned class reply higher than projector '
'stated class'.format(ip=self.pjlink.name)),
call('({ip}) _send_command(): Nothing to send - returning'.format(ip=self.pjlink.name))]
log_debug_text = [call('({ip}) get_data(buffer="{pre}2ACKN=X"'.format(ip=self.pjlink.name,
pre=PJLINK_PREFIX)),
call('({ip}) get_data(): Checking new data "{pre}2ACKN=X"'.format(ip=self.pjlink.name,
pre=PJLINK_PREFIX)),
call('({ip}) get_data() header="{pre}2ACKN" data="X"'.format(ip=self.pjlink.name,
pre=PJLINK_PREFIX)),
call('({ip}) get_data() version="2" cmd="ACKN" data="X"'.format(ip=self.pjlink.name))]
self.pjlink.pjlink_class = '1'
# WHEN: get_data called with an unknown command
self.pjlink.get_data(buff='{prefix}2ACKN=X'.format(prefix=PJLINK_PREFIX))
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.warning.assert_has_calls(log_warning_text)
mock_log.debug.assert_has_calls(log_debug_text)
assert (mock_process_cmd.call_count == 0), 'process_command should not have been called'
@skip('Needs update to new setup') @skip('Needs update to new setup')
@patch("openlp.core.projectors.pjlink.log") def test_routing_err1(self):
def test_process_command_call_clss(self, mock_log):
""" """
Test process_command calls proper function Test ERR1 - Undefined projector function
""" """
# GIVEN: Test object and mocks # GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \ with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss: patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
log_debug_calls = [call('({ip}) Processing command "CLSS" with data "1"'.format(ip=self.pjlink.name)), pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_UNDEFINED]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR1"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))] call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command is called with valid function and data # WHEN: process_command called with ERR1
process_command(projector=self.pjlink, cmd='CLSS', data='1') pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
# THEN: Appropriate log entries should have been made and methods called # THEN: Appropriate log entries should have been made and methods called
mock_log.debug.assert_has_calls(log_debug_calls) mock_log.error.assert_has_calls(log_error_text)
mock_process_clss.assert_called_once_with(data='1') mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNDEFINED])
@skip('Needs update to new setup') @skip('Needs update to new setup')
def test_process_command_erra(self): def test_routing_err2(self):
"""
Test ERR2 - Parameter Error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_PARAMETER]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR2"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR2
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PARAMETER])
@skip('Needs update to new setup')
def test_routing_err3(self):
"""
Test ERR3 - Unavailable error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_UNAVAILABLE]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR3"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR3
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
# THEN: Appropriate log entries should have been made and methods called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNAVAILABLE])
@skip('Needs update to new setup')
def test_routing_err4(self):
"""
Test ERR3 - Unavailable error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_PROJECTOR]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR4"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR4
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
# THEN: Appropriate log entries should have been made and methods called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PROJECTOR])
@skip('Needs update to new setup')
def test_routing_erra(self):
""" """
Test ERRA - Authentication Error Test ERRA - Authentication Error
""" """
@ -124,138 +250,3 @@ class TestPJLinkRouting(TestCase):
mock_change_status.assert_called_once_with(status=E_AUTHENTICATION) mock_change_status.assert_called_once_with(status=E_AUTHENTICATION)
mock_authentication.emit.assert_called_once_with(pjlink.name) mock_authentication.emit.assert_called_once_with(pjlink.name)
mock_process_pjlink.assert_not_called() mock_process_pjlink.assert_not_called()
@skip('Needs update to new setup')
def test_process_command_err1(self):
"""
Test ERR1 - Undefined projector function
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_UNDEFINED]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR1"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR1
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNDEFINED])
# THEN: Appropriate log entries should have been made and methods called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNDEFINED])
@skip('Needs update to new setup')
def test_process_command_err2(self):
"""
Test ERR2 - Parameter Error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_PARAMETER]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR2"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR2
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PARAMETER])
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PARAMETER])
@skip('Needs update to new setup')
def test_process_command_err3(self):
"""
Test ERR3 - Unavailable error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_UNAVAILABLE]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR3"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR3
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_UNAVAILABLE])
# THEN: Appropriate log entries should have been made and methods called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_UNAVAILABLE])
@skip('Needs update to new setup')
def test_process_command_err4(self):
"""
Test ERR3 - Unavailable error
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_error_text = [call('({ip}) CLSS: {msg}'.format(ip=self.pjlink.name, msg=STATUS_MSG[E_PROJECTOR]))]
log_debug_text = [call('({ip}) Processing command "CLSS" with data "ERR4"'.format(ip=self.pjlink.name)),
call('({ip}) Calling function for CLSS'.format(ip=self.pjlink.name))]
# WHEN: process_command called with ERR4
pjlink.process_command(cmd='CLSS', data=PJLINK_ERRORS[E_PROJECTOR])
# THEN: Appropriate log entries should have been made and methods called
mock_log.error.assert_has_calls(log_error_text)
mock_log.debug.assert_has_calls(log_debug_text)
mock_process_clss.assert_called_once_with(data=PJLINK_ERRORS[E_PROJECTOR])
@skip('Needs update to new setup')
def test_process_command_future(self):
"""
Test command valid but no method to process yet
"""
# GIVEN: Test object
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
pjlink.pjlink_functions = MagicMock()
log_warning_text = [call('({ip}) Unable to process command="CLSS" '
'(Future option?)'.format(ip=self.pjlink.name))]
log_debug_text = [call('({ip}) Processing command "CLSS" '
'with data "Huh?"'.format(ip=self.pjlink.name))]
# WHEN: Processing a possible future command
pjlink.process_command(cmd='CLSS', data="Huh?")
# THEN: Appropriate log entries should have been made and methods called/not called
mock_log.debug.assert_has_calls(log_debug_text)
mock_log.warning.assert_has_calls(log_warning_text)
assert pjlink.pjlink_functions.called is False, 'Should not have accessed pjlink_functions'
assert mock_process_clss.called is False, 'Should not have called process_clss'
@skip('Needs update to new setup')
def test_process_command_ok(self):
"""
Test command returned success
"""
# GIVEN: Test object and mocks
with patch.object(openlp.core.projectors.pjlink, 'log') as mock_log, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'send_command') as mock_send_command, \
patch.object(openlp.core.projectors.pjlink.PJLink, 'process_clss') as mock_process_clss:
pjlink = PJLink(Projector(**TEST1_DATA), no_poll=True)
log_debug_calls = [call('({ip}) Processing command "CLSS" with data "OK"'.format(ip=self.pjlink.name)),
call('({ip}) Command "CLSS" returned OK'.format(ip=self.pjlink.name))]
# WHEN: process_command is called with valid function and data
pjlink.process_command(cmd='CLSS', data='OK')
# THEN: Appropriate log entries should have been made and methods called
mock_log.debug.assert_has_calls(log_debug_calls)
mock_send_command.assert_called_once_with(cmd='CLSS')
mock_process_clss.assert_not_called()