| #// Copyright (c) 2000-2017 Ericsson Telecom AB // |
| #// All rights reserved. This program and the accompanying materials are made available under the terms // |
| #// of the Eclipse Public License v1.0 which accompanies this distribution, and is available at // |
| #// http://www.eclipse.org/legal/epl-v10.html // |
| #///////////////////////////////////////////////////////////////////////////////////////////////////////// |
| import unittest, json, time, os |
| import Microservices.Playlist |
| from Microservices.Playlist.ScheduledPlaylist import ScheduledPlaylist |
| from test.utils.Utils import * |
| |
| def loadPlaylist(path): |
| with open(path, 'r') as f: |
| playlist = json.load(f) |
| return playlist |
| |
| class ScheduledPlaylistTest(unittest.TestCase): |
| |
| def setUp(self): |
| self.next = 0 |
| self.failed = False |
| self.reason = '' |
| |
| def test_requestHandlingWithConditionTrue(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_requestHandlingWithConditionTrue |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| execute the playlist and check expected behaviour |
| Expected_Result: pass |
| ''' |
| |
| self.expected = ( |
| ( |
| lambda type, url, credentials: (type, url, credentials['username']), |
| ('LOGIN', 'http://localhost:8000/api.appagent', 'admin'), |
| None |
| ), |
| ( |
| lambda type, url, requests: (type, url, requests[0]['getData']['filter']), |
| ('REQUEST', 'http://localhost:8000/api.appagent', {'dataValue': 'false'}), |
| {'contentList': [{'node': {'val': '1', 'tp': 1}}]} |
| ), |
| ( |
| lambda type, amount: (type, amount), |
| ('WAIT', 0.2), |
| None |
| ), |
| ( |
| lambda type, url, requests: (type, url, requests[0]['setData']['element']), |
| ('REQUEST', 'http://localhost:8000/api.appagent', 'string'), |
| {'contentList': [{'node': {'val': '1', 'tp': 1}}]} |
| ), |
| ( |
| lambda type: type, |
| 'LOGOUT', |
| None |
| ) |
| ) |
| |
| self.runPlaylist(PLAYLIST_DIR + '/Playlists/admin/simple.json', 'blue') |
| |
| def test_relativeTo(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_relativeTo |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| execute the playlist and check expected behaviour |
| Expected_Result: pass |
| ''' |
| |
| self.expected = ( |
| ( |
| lambda type, url, credentials: (type, url, credentials['username']), |
| ('LOGIN', 'http://localhost:8000/api.appagent', 'admin'), |
| None |
| ), |
| ( |
| lambda type, url, requests: (time.sleep(0.1), requests[0]['setData']['content']), |
| (None, 'new_str1'), |
| {'contentList': [{'node': {'val': '1', 'tp': 1}}]} |
| ), |
| ( |
| lambda type, url, requests: (time.sleep(0.1), requests[0]['setData']['content']), |
| (None, 'new_str2'), |
| {'contentList': [{'node': {'val': '1', 'tp': 1}}]} |
| ), |
| ( |
| lambda type, url, requests: (time.sleep(0.1), requests[0]['setData']['content']), |
| (None, 'new_str3'), |
| {'contentList': [{'node': {'val': '1', 'tp': 1}}]} |
| ), |
| ( |
| lambda type: type, |
| 'LOGOUT', |
| None |
| ) |
| ) |
| |
| self.runPlaylist(PLAYLIST_DIR + '/Playlists/admin/relativeto.json', 'blue') |
| |
| def test_conditionMaxTriesExceeded(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_conditionMaxTriesExceeded |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| execute the playlist and check expected behaviour |
| Expected_Result: pass |
| ''' |
| |
| self.expected = ( |
| ( |
| lambda type, url, credentials: (type, url, credentials['username']), |
| ('LOGIN', 'http://localhost:8000/api.appagent', 'admin'), |
| None |
| ), |
| ( |
| lambda type, url, requests: (type, url, requests[0]['getData']['filter']), |
| ('REQUEST', 'http://localhost:8000/api.appagent', {'dataValue': 'false'}), |
| {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| ), |
| ( |
| lambda type, amount: (type, amount), |
| ('WAIT', 0.1), |
| None |
| ), |
| ( |
| lambda type, url, requests: (type, url, requests[0]['getData']['filter']), |
| ('REQUEST', 'http://localhost:8000/api.appagent', {'dataValue': 'false'}), |
| {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| ), |
| ( |
| lambda type, amount: (type, amount), |
| ('WAIT', 0.1), |
| None |
| ), |
| ( |
| lambda type, url, requests: (type, url, requests[0]['getData']['filter']), |
| ('REQUEST', 'http://localhost:8000/api.appagent', {'dataValue': 'false'}), |
| {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| ), |
| ( |
| lambda type: type, |
| 'LOGOUT', |
| None |
| ) |
| ) |
| |
| self.runPlaylist(PLAYLIST_DIR + '/Playlists/admin/try.json', 'red') |
| |
| def test_conditionsMaxTimeExceeded(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_conditionsMaxTimeExceeded |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| execute the playlist and check expected behaviour |
| Expected_Result: pass |
| ''' |
| |
| self.expected = ( |
| ( |
| lambda type, url, credentials: (type, url, credentials['username']), |
| ('LOGIN', 'http://localhost:8000/api.appagent', 'admin'), |
| None |
| ), |
| ( |
| lambda type, url, requests: time.sleep(0.5), |
| None, |
| {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| ), |
| ( |
| lambda type: type, |
| 'LOGOUT', |
| None |
| ) |
| ) |
| |
| self.runPlaylist(PLAYLIST_DIR + '/Playlists/admin/wait.json', 'red') |
| |
| def test_stop(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_stop |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| execute the playlist and check expected behaviour |
| Expected_Result: pass |
| ''' |
| |
| self.expected = ( |
| ( |
| lambda type, url, credentials: (type, url, credentials['username']), |
| ('LOGIN', 'http://localhost:8000/api.appagent', 'admin'), |
| None |
| ), |
| ( |
| lambda type, url, requests: self.handler.stop(), |
| None, |
| {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| ), |
| ( |
| lambda type: type, |
| 'LOGOUT', |
| None |
| ) |
| ) |
| |
| self.runPlaylist(PLAYLIST_DIR + '/Playlists/admin/relativeto.json', 'black') |
| |
| def test_pause(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_pause |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - ScheduledPlaylist |
| Requirement: playlist execution |
| Action_To_Be_taken: |
| start the playlist |
| pause the playlist |
| check if the playlist was paused |
| resume the playlist |
| check if it was resumed |
| stop the playlist |
| Expected_Result: pass |
| ''' |
| |
| # we count the number of 'actions'; when paused, the counter should not change |
| count = [0] # we can't modify an outer variable directly... |
| |
| def magicHandler(*args): |
| count[0] += 1 |
| time.sleep(0.1) |
| return {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| |
| # start the playlist |
| self.handler = ScheduledPlaylist(loadPlaylist(PLAYLIST_DIR + '/Playlists/admin/longtry.json')) |
| self.handler._login = magicHandler |
| self.handler._logout = magicHandler |
| self.handler._wait = magicHandler |
| self.handler._sendRequestsToUrl = magicHandler |
| self.handler.start(ADMIN) |
| |
| # pause the playlist |
| time.sleep(0.5) |
| self.handler.pause() |
| # check if the playlist was paused |
| time.sleep(0.2) |
| currentCount = count[0] |
| time.sleep(0.5) |
| self.assertEqual(count[0], currentCount, 'there should be no calls when paused') # there were no additional calls |
| # resume the playlist |
| self.handler.pause() |
| # check if it was resumed |
| time.sleep(0.5) |
| self.assertNotEqual(count[0], currentCount, 'there should be calls when unpaused') # there were calls after unpause |
| # stop the playlist |
| self.handler.stop() |
| time.sleep(0.2) |
| |
| def startPlaylist(self, fileName): |
| self.handler = ScheduledPlaylist(loadPlaylist(fileName)) |
| self.handler._login = self.mockedLogin |
| self.handler._logout = self.mockedLogout |
| self.handler._wait = self.mockedWait |
| self.handler._sendRequestsToUrl = self.mockedSendRequest |
| self.handler.start(ADMIN) |
| |
| def runPlaylist(self, fileName, color, timeout = 1): |
| self.startPlaylist(fileName) |
| startTime = time.time() |
| while self.handler.isRunning(): |
| if time.time() - startTime > timeout: |
| self.fail('Playlist execution timed out') |
| time.sleep(0.1) |
| while color not in self.handler.getStatus()['node']['val']: |
| if time.time() - startTime > timeout: |
| self.fail('Playlist status is wrong, expected ' + color + ', got ' + self.handler.getStatus()['node']['val']) |
| time.sleep(0.1) |
| if self.failed: |
| self.fail(self.reason) |
| |
| def handle(self, *args): |
| time.sleep(0.1) # this is needed to imitate non-blocking behaviour (this is the only way we can check the status led color reliably) |
| if self.next >= len(self.expected): |
| self.failed = True |
| self.reason = 'Too few expected values: ' + str(len(self.expected)) |
| return None |
| if len(self.expected[self.next]) < 3: |
| self.failed = True |
| self.reason = 'Not all 3 arguments present, only got: ' + str(len(self.expected[self.next])) |
| return None |
| transformer, expected, returnValue = self.expected[self.next] |
| self.next += 1 |
| try: |
| self.assertEqual(transformer(*args), expected) |
| except Exception as e: |
| self.failed = True |
| self.reason = e |
| return returnValue |
| |
| def mockedLogin(self, opener, url, userCredentials): |
| return self.handle('LOGIN', url, userCredentials) |
| |
| def mockedLogout(self): |
| return self.handle('LOGOUT') |
| |
| def mockedWait(self, amount): |
| return self.handle('WAIT', amount) |
| |
| def mockedSendRequest(self, opener, url, requests): |
| return self.handle('REQUEST', url, requests) |
| |
| class PlaylistTest(unittest.TestCase): |
| |
| def magicHandler(self, *args): |
| # a function that mocks parts of the ScheduledPlaylist |
| time.sleep(0.1) |
| return {'contentList': [{'node': {'val': '', 'tp': 0}}]} |
| |
| def createPlaylistExecutor(self, descriptor): |
| # create a mocked ScheduledPlaylist |
| executor = ScheduledPlaylist(descriptor) |
| executor._login = self.magicHandler |
| executor._logout = self.magicHandler |
| executor._wait = self.magicHandler |
| executor._sendRequestsToUrl = self.magicHandler |
| return executor |
| |
| def setUp(self): |
| # the "microservice" under test |
| self.handler = Microservices.Playlist.createHandler(PLAYLIST_DIR) |
| # the datasource handlers of the microservice |
| self.datasourceHandlers = self.handler.getDataSourceHandlers() |
| # mock the creation of ScheduledPlaylist |
| self.handler._createPlaylistExecutor = self.createPlaylistExecutor |
| # a list of created files to delete at the end |
| self.created = [] |
| |
| def tearDown(self): |
| # close tested "microservice" |
| self.handler.close() |
| # delete the created files |
| for fileName in self.created: |
| if os.path.exists(fileName): |
| os.unlink(fileName) |
| |
| def test_playlistHandling(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_playlistHandling |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - Playlist |
| Requirement: playlist microservice request handling |
| Action_To_Be_taken: |
| start a playlist |
| check elements of a running and an idle playlist |
| pause the running playlist |
| check status led |
| resume playlist |
| check status led |
| stop playlist |
| check status led |
| Expected_Result: pass |
| ''' |
| |
| # start a playlist |
| self.set('Start', '0', 1, 'admin/longtry') |
| time.sleep(0.2) |
| # check elements of a running and an idle playlist |
| self.check('0', 'Start', 'admin/longtry') |
| self.check('0', 'Start', 'admin/try') |
| self.check('0', 'Stop', 'admin/longtry') |
| self.check('0', 'Stop', 'admin/try') |
| self.check('0', 'Pause', 'admin/longtry') |
| self.check('0', 'Pause', 'admin/try') |
| self.check('0', 'Start', 'admin/longtry') |
| self.check('0', 'Start', 'admin/try') |
| self.check('green', 'Status', 'admin/longtry') |
| self.check('blue', 'Status', 'admin/try') |
| # pause the running playlist |
| self.set('Pause', '0', 1, 'admin/longtry') |
| time.sleep(0.2) |
| # check status led |
| self.check('yellow', 'Status', 'admin/longtry') |
| # resume playlist |
| self.set('Pause', '0', 1, 'admin/longtry') |
| time.sleep(0.2) |
| # check status led |
| self.check('green', 'Status', 'admin/longtry') |
| # stop playlist |
| self.set('Stop', '0', 1, 'admin/longtry') |
| time.sleep(0.2) |
| # check status led |
| self.check('black', 'Status', 'admin/longtry') |
| |
| def test_playlistFileHandling(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_playlistFileHandling |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - Playlist |
| Requirement: playlist microservice file handling |
| Action_To_Be_taken: |
| create a playlist |
| check if it was created |
| check if the descriptor is the same as the one that was saved |
| delete the playlist |
| check that it no longer exists |
| Expected_Result: pass |
| ''' |
| |
| # create a playlist |
| self.created.append(PLAYLIST_DIR + '/Playlists/admin/test.json') |
| self.set('Descriptor', '[]', 4, 'admin/test') |
| # check if it was created |
| self.assertIn('admin/test', self.makeList(self.get('Playlists'))) |
| # check if the descriptor is the same as the one that was saved |
| self.check('[]', 'Descriptor', 'admin/test') |
| # delete the playlist |
| self.set('Delete', '1', 1, 'admin/test') |
| # check that it no longer exists |
| self.assertNotIn('admin/test', self.makeList(self.get('Playlists'))) |
| |
| def test_microService(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_microService |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - Playlist |
| Requirement: playlist behaviour as a microservice |
| Action_To_Be_taken: |
| invoke the request handler with a simple request and check the result |
| Expected_Result: pass |
| ''' |
| |
| response = getEmptyResponse() |
| self.handler.handleMessage('POST', 'api.playlist', {}, '''{ |
| "requests": [ |
| { |
| "getData": { |
| "source": "Playlist", |
| "element": "Playlists" |
| } |
| } |
| ] |
| }''', ADMIN, response) |
| playlists = self.makeList(json.loads(response['body'])['contentList'][0]) |
| self.assertIn('admin/longtry', playlists) |
| |
| def test_help(self): |
| ''' |
| Author: EDNIGBO Daniel Gobor |
| Testcase: test_help |
| Tested component: ServiceFramework |
| Feature: ServiceFramework - Playlist |
| Requirement: datasource help in Playlist |
| Action_To_Be_taken: |
| get help |
| check help syntax |
| Expected_Result: pass |
| ''' |
| |
| # get help |
| help = self.get('help')['node']['val'] |
| # check help syntax |
| json.loads(help.decode('hex')) |
| |
| def makeList(self, response): |
| return [element['node']['val'] for element in response['list']] |
| |
| def check(self, expected, element, playlist = None, user = ADMIN): |
| response = self.get(element, playlist, user) |
| self.assertIn(expected, response['node']['val']) |
| |
| def get(self, element, playlist = None, user = ADMIN): |
| request = { |
| 'source': self.handler.SOURCE_ID, |
| 'element': element, |
| 'params': [] |
| } |
| if playlist is not None: |
| request['params'].append({ |
| 'paramName': 'Playlist', |
| 'paramValue': playlist |
| }) |
| return self.datasourceHandlers[self.handler.SOURCE_ID]['getDataHandler'](request, user) |
| |
| def set(self, element, content, tp, playlist = None, user = ADMIN): |
| request = { |
| 'source': self.handler.SOURCE_ID, |
| 'element': element, |
| 'params': [], |
| 'tp': tp, |
| 'content': content |
| } |
| if playlist is not None: |
| request['params'].append({ |
| 'paramName': 'Playlist', |
| 'paramValue': playlist |
| }) |
| return self.datasourceHandlers[self.handler.SOURCE_ID]['setDataHandler'](request, user) |