diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
new file mode 100644
index 0000000..3977ef9
--- /dev/null
+++ b/.github/workflows/ci.yml
@@ -0,0 +1,37 @@
+# This workflow will install Python dependencies, run tests and lint with a variety of Python versions
+# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python
+
+name: Python package
+
+on:
+ push:
+ branches: [ "master" ]
+ pull_request:
+ branches: [ "master" ]
+
+jobs:
+ test:
+
+ runs-on: ubuntu-20.04
+ strategy:
+ fail-fast: false
+ matrix:
+ python-version: ["3.6", "3.7", "3.8", "3.9", "3.10", "3.11", "3.12"]
+
+ steps:
+ - uses: actions/checkout@v4
+ - name: Set up Python ${{ matrix.python-version }}
+ uses: actions/setup-python@v5
+ with:
+ python-version: ${{ matrix.python-version }}
+ - name: Install dependencies
+ run: |
+ python -m pip install --upgrade pip
+ python -m pip install '.[test]'
+ python -m pip install .
+ - name: Clear existing docker image cache
+ shell: bash
+ run: docker image prune -af
+ - name: Test with pytest
+ run: |
+ python -m unittest discover -v -s test -p "test*.py"
diff --git a/.gitignore b/.gitignore
index fed1142..f76e985 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@
*.pyc
build/
*.egg-info/
+.vscode
\ No newline at end of file
diff --git a/.project b/.project
deleted file mode 100644
index 4d3d9e8..0000000
--- a/.project
+++ /dev/null
@@ -1,17 +0,0 @@
-
-
- python.channelfinder.api
-
-
-
-
-
- org.python.pydev.PyDevBuilder
-
-
-
-
-
- org.python.pydev.pythonNature
-
-
diff --git a/.pydevproject b/.pydevproject
deleted file mode 100644
index dc3c8ef..0000000
--- a/.pydevproject
+++ /dev/null
@@ -1,11 +0,0 @@
-
-
-
-
-Default
-python 2.6
-
-/python.channelfinder.api/example
-/python.channelfinder.api
-
-
diff --git a/MANIFEST b/MANIFEST
deleted file mode 100644
index b2c34c4..0000000
--- a/MANIFEST
+++ /dev/null
@@ -1,9 +0,0 @@
-# file GENERATED by distutils, do NOT edit
-cf-monitor-test
-cf-update-ioc
-setup.py
-channelfinder\CFDataTypes.py
-channelfinder\ChannelFinderClient.py
-channelfinder\Cleanup.py
-channelfinder\__init__.py
-channelfinder\_conf.py
diff --git a/README.md b/README.md
index 8057572..7b76c3e 100644
--- a/README.md
+++ b/README.md
@@ -1,8 +1,8 @@
# pyCFClient
-A python client library
+A python client library for ChannelFinder.
-### configuration for pyCFClient
+## Configuration
The python channelfinder client library can be configured by setting up a `channelfinderapi.conf` file in the following locations
@@ -11,6 +11,7 @@ The python channelfinder client library can be configured by setting up a `chann
`channelfinderapi.conf`
The example preferences:
+
```
cat ~/channelfinderapi.conf
[DEFAULT]
@@ -19,3 +20,22 @@ username=MyUserName
password=MyPassword
```
+## Development
+
+To install with dependancies for testing.
+
+```bash
+python -m pip install --upgrade pip
+python -m pip install '.[test]'
+python -m pip install .
+```
+
+### Testing
+
+Some of the tests use docker to run a test ChannelFinderService, so a working docker installation needs to available for tests to be successful.
+
+To run all tests:
+
+```bash
+python -m unittest discover -v -s test -p "test*.py"
+```
\ No newline at end of file
diff --git a/cf-update-ioc b/cf-update-ioc
deleted file mode 100644
index 6221f72..0000000
--- a/cf-update-ioc
+++ /dev/null
@@ -1,3 +0,0 @@
-#!/usr/bin/python
-from channelfinder.cfUpdate.CFUpdateIOC import main
-main()
\ No newline at end of file
diff --git a/cf-monitor-test b/channelfinder/cfMonitorTest.py
similarity index 96%
rename from cf-monitor-test
rename to channelfinder/cfMonitorTest.py
index 7326e7a..81a5366 100644
--- a/cf-monitor-test
+++ b/channelfinder/cfMonitorTest.py
@@ -1,131 +1,131 @@
-#!/usr/bin/python
-'''
-Created on Mar 19, 2012
-
-A python script to ensure that the cf-update-ioc is working correctly.
-The script requires the setup of two files
-e.g.
->cat nagios01.host01.dbl
->test:cf-update-daemon{test}
-
->cat nagios02.host02.dbl
->test:cf-update-daemon{test}
-
-The script will touch each file, with a short delay and will check that
-Channelfinder has been appropriately updated.
-
-python cf-monitor-test /complete/path/to/daemon/dir -i initialFile -f finalFile
-
-@author: shroffk
-'''
-import sys
-import os
-import re
-from optparse import OptionParser
-from time import sleep
-
-from channelfinder import ChannelFinderClient
-
-SEVR = {0:'OK ',
- 1:'Minor ',
- 2:'Major '}
-
-
-def main():
- requiredOpts = ['initial-file', 'final-file']
- usage = "usage: %prog -i initial-file -f final-file directory "
- parser = OptionParser(usage=usage)
- parser.add_option('-i', '--initial-file', \
- action='store', type='string', dest='initialFile', \
- help='the initial-file')
- parser.add_option('-f', '--final-file', \
- action='store', type='string', dest='finalFile', \
- help='the --final-file')
- opts, args = parser.parse_args()
- if args == None or len(args) == 0 :
- parser.error('Please specify a directory')
- if not opts.initialFile:
- parser.error('Please specify a initial test files')
- if not opts.finalFile:
- parser.error('Please specify a final test files')
- mainRun(opts, args)
-
-
-def mainRun(opts, args):
- for directory in args:
- initialFile = os.path.normpath(directory + '/' + opts.initialFile)
- iHostName, iIocName = getArgsFromFilename(initialFile)
- finalFile = os.path.normpath(directory + '/' + opts.finalFile)
- fHostName, fIocName = getArgsFromFilename(finalFile)
- if getPVNames(initialFile) != getPVNames(finalFile):
- sys.exit(1)
- pvNames = getPVNames(initialFile)
- if len(pvNames) == 0:
- sys.exit(1)
- '''
- Touch the initial file and check channelfinder
- '''
- touch(initialFile)
- sleep(2)
- check(pvNames, iHostName, iIocName)
- '''
- Touch the final file and check channelfinder
- '''
- touch(finalFile)
- sleep(2)
- check(pvNames, fHostName, fIocName)
- sys.exit
-
-
-def check(pvNames, hostName, iocName):
- try:
- client = ChannelFinderClient()
- except:
- raise RuntimeError('Unable to create a valid webResourceClient')
- channels = client.find(property=[('hostName', hostName), ('iocName', iocName)])
- if channels and len(pvNames) == len(channels):
- for channel in channels:
- if channel.Name not in pvNames:
- sys.exit(2)
- else:
- sys.exit(2)
-
-
-def touch(fname, times=None):
- with open(fname, 'a'):
- os.utime(fname, times)
-
-
-def getArgsFromFilename(completeFilePath):
- fileName = os.path.split(os.path.normpath(completeFilePath))[1]
- pattern4Hostname = '(\S+?)\.\S+'
- match = re.search(pattern4Hostname, fileName)
- if match:
- hostName = match.group(1)
- else:
- hostName = None
- pattern4Iocname = '\S+?\.(\S+?)\.\S+'
- match = re.search(pattern4Iocname, fileName)
- if match:
- iocName = match.group(1)
- else:
- iocName = None
- return hostName, iocName
-
-def getPVNames(completeFilePath, pattern=None):
- try:
- f = open(completeFilePath)
- pvNames = f.read().splitlines()
- pvNames = map(lambda x: x.strip(), pvNames)
- pvNames = filter(lambda x: len(x) > 0, pvNames)
- if pattern:
- pvNames = [ re.match(pattern, pvName).group() for pvName in pvNames if re.match(pattern, pvName) ]
- return pvNames
- except IOError:
- return None
- finally:
- f.close()
-
-if __name__ == '__main__':
- main()
- pass
+#!/usr/bin/python
+'''
+Created on Mar 19, 2012
+
+A python script to ensure that the cf-update-ioc is working correctly.
+The script requires the setup of two files
+e.g.
+>cat nagios01.host01.dbl
+>test:cf-update-daemon{test}
+
+>cat nagios02.host02.dbl
+>test:cf-update-daemon{test}
+
+The script will touch each file, with a short delay and will check that
+Channelfinder has been appropriately updated.
+
+python cf-monitor-test /complete/path/to/daemon/dir -i initialFile -f finalFile
+
+@author: shroffk
+'''
+import sys
+import os
+import re
+from optparse import OptionParser
+from time import sleep
+
+from channelfinder import ChannelFinderClient
+
+SEVR = {0:'OK ',
+ 1:'Minor ',
+ 2:'Major '}
+
+
+def main():
+ requiredOpts = ['initial-file', 'final-file']
+ usage = "usage: %prog -i initial-file -f final-file directory "
+ parser = OptionParser(usage=usage)
+ parser.add_option('-i', '--initial-file', \
+ action='store', type='string', dest='initialFile', \
+ help='the initial-file')
+ parser.add_option('-f', '--final-file', \
+ action='store', type='string', dest='finalFile', \
+ help='the --final-file')
+ opts, args = parser.parse_args()
+ if args == None or len(args) == 0 :
+ parser.error('Please specify a directory')
+ if not opts.initialFile:
+ parser.error('Please specify a initial test files')
+ if not opts.finalFile:
+ parser.error('Please specify a final test files')
+ mainRun(opts, args)
+
+
+def mainRun(opts, args):
+ for directory in args:
+ initialFile = os.path.normpath(directory + '/' + opts.initialFile)
+ iHostName, iIocName = getArgsFromFilename(initialFile)
+ finalFile = os.path.normpath(directory + '/' + opts.finalFile)
+ fHostName, fIocName = getArgsFromFilename(finalFile)
+ if getPVNames(initialFile) != getPVNames(finalFile):
+ sys.exit(1)
+ pvNames = getPVNames(initialFile)
+ if len(pvNames) == 0:
+ sys.exit(1)
+ '''
+ Touch the initial file and check channelfinder
+ '''
+ touch(initialFile)
+ sleep(2)
+ check(pvNames, iHostName, iIocName)
+ '''
+ Touch the final file and check channelfinder
+ '''
+ touch(finalFile)
+ sleep(2)
+ check(pvNames, fHostName, fIocName)
+ sys.exit
+
+
+def check(pvNames, hostName, iocName):
+ try:
+ client = ChannelFinderClient()
+ except:
+ raise RuntimeError('Unable to create a valid webResourceClient')
+ channels = client.find(property=[('hostName', hostName), ('iocName', iocName)])
+ if channels and len(pvNames) == len(channels):
+ for channel in channels:
+ if channel.Name not in pvNames:
+ sys.exit(2)
+ else:
+ sys.exit(2)
+
+
+def touch(fname, times=None):
+ with open(fname, 'a'):
+ os.utime(fname, times)
+
+
+def getArgsFromFilename(completeFilePath):
+ fileName = os.path.split(os.path.normpath(completeFilePath))[1]
+ pattern4Hostname = '(\S+?)\.\S+'
+ match = re.search(pattern4Hostname, fileName)
+ if match:
+ hostName = match.group(1)
+ else:
+ hostName = None
+ pattern4Iocname = '\S+?\.(\S+?)\.\S+'
+ match = re.search(pattern4Iocname, fileName)
+ if match:
+ iocName = match.group(1)
+ else:
+ iocName = None
+ return hostName, iocName
+
+def getPVNames(completeFilePath, pattern=None):
+ try:
+ f = open(completeFilePath)
+ pvNames = f.read().splitlines()
+ pvNames = map(lambda x: x.strip(), pvNames)
+ pvNames = filter(lambda x: len(x) > 0, pvNames)
+ if pattern:
+ pvNames = [ re.match(pattern, pvName).group() for pvName in pvNames if re.match(pattern, pvName) ]
+ return pvNames
+ except IOError:
+ return None
+ finally:
+ f.close()
+
+if __name__ == '__main__':
+ main()
+ pass
diff --git a/pyproject.toml b/pyproject.toml
new file mode 100644
index 0000000..6182786
--- /dev/null
+++ b/pyproject.toml
@@ -0,0 +1,33 @@
+[build-system]
+requires = ["flit_core >=3.2,<4"]
+build-backend = "flit_core.buildapi"
+
+[project]
+name = "channelfinder"
+version = "3.0.0"
+authors = [
+ { name="Kunal Shroff", email="shroffk@bnl.gov" },
+]
+description = "Python ChannelFinder Client Lib"
+readme = "README.md"
+requires-python = ">=3.6"
+classifiers = [
+ "Programming Language :: Python :: 3",
+ "License :: OSI Approved :: MIT License",
+ "Operating System :: OS Independent",
+]
+dependencies = [
+ "requests>=2.15.0",
+ "simplejson>=3.10.0",
+ "urllib3>=1.22"
+ ]
+[project.optional-dependencies]
+test = ["pytest", "testcontainers>=3.7.0,<4"]
+
+[project.urls]
+Homepage = "https://github.com/ChannelFinderService/pyCFClient"
+Issues = "https://github.com/ChannelFinderService/pyCFClient/issues"
+
+[project.scripts]
+cf-update-ioc = "channelfinder.cfUpdate.CFUpdateIOC:main"
+cf-monitor-test = "channelfinder.cfMonitorTest:main"
diff --git a/requirements.txt b/requirements.txt
deleted file mode 100644
index 46bc311..0000000
--- a/requirements.txt
+++ /dev/null
@@ -1,3 +0,0 @@
-requests>=2.15.0
-simplejson>=3.10.0
-urllib3>=1.22
\ No newline at end of file
diff --git a/setup.py b/setup.py
deleted file mode 100644
index 655aa94..0000000
--- a/setup.py
+++ /dev/null
@@ -1,38 +0,0 @@
-'''
-Created on Apr 4, 2011
-
-@author: shroffk
-'''
-
-from setuptools import setup
-
-from os import path
-
-cur_dir = path.abspath(path.dirname(__file__))
-
-with open(path.join(cur_dir, 'requirements.txt')) as f:
- requirements = f.read().split()
-
-extras_require = {
- 'PySide': ['PySide'],
- 'pyepics': ['pyepics'],
- 'perf': ['psutil'],
- 'testing-ioc': ['pcaspy'],
- 'test': ['codecov', 'pytest', 'pytest-cov', 'coverage', 'coveralls', 'pcaspy']
-}
-
-setup(
- name='channelfinder',
- version='3.0.0',
- description='Python ChannelFinder Client Lib',
- author='Kunal Shroff',
- author_email='shroffk@bnl.gov',
- url='http://channelfinder.sourceforge.net/channelfinderpy',
- scripts=['cf-update-ioc', 'cf-monitor-test'],
- packages=['channelfinder', 'channelfinder/util', 'channelfinder/cfUpdate', 'test'],
- long_description="""\
- Python ChannelFinder Client Lib
- """,
- license='GPL',
- install_requires=requirements,
-)
diff --git a/test/_testConf.py b/test/_testConf.py
index acb28b0..ffd3eda 100644
--- a/test/_testConf.py
+++ b/test/_testConf.py
@@ -12,6 +12,8 @@
password=MyPassword
"""
import os.path
+import unittest
+from testcontainers.compose import DockerCompose
import sys
if sys.version_info[0] < 3:
@@ -21,22 +23,41 @@
# Python 3 code in this block
from configparser import ConfigParser
+def channelFinderDocker():
+ return DockerCompose("test", compose_file_name="docker-compose.yml")
+
+class ChannelFinderClientTestCase(unittest.TestCase):
+ channelFinderCompose = None
+ @classmethod
+ def setUpClass(cls) -> None:
+ cls.channelFinderCompose = channelFinderDocker()
+ cls.channelFinderCompose.start()
+ cls.channelFinderCompose.wait_for(_testConf.get('DEFAULT', 'BaseURL') + "/ChannelFinder")
+ return super().setUpClass()
+
+ @classmethod
+ def tearDownClass(cls) -> None:
+ if cls.channelFinderCompose is not None:
+ cls.channelFinderCompose.stop()
+ return super().tearDownClass()
+
def __loadConfig():
- dflt={'BaseURL':'https://barkeria-vm:8181/ChannelFinder',
- 'username' : 'cf-update',
- 'password' : '1234',
- 'owner' : 'cf-update',
- 'channelOwner' : 'cf-channels',
- 'channelUsername' : 'channel',
- 'channelPassword' : '1234',
- 'propOwner' : 'cf-properties',
- 'propUsername' : 'property',
- 'propPassword' : '1234',
- 'tagOwner' : 'cf-tags',
- 'tagUsername' : 'tag',
- 'tagPassword' : '1234'
- }
+
+ dflt = {'BaseURL':'http://localhost:8080/ChannelFinder',
+ 'username' : 'admin',
+ 'password' : 'adminPass',
+ 'owner' : 'cf-update',
+ 'channelOwner' : 'cf-channels',
+ 'channelUsername' : 'admin',
+ 'channelPassword' : 'adminPass',
+ 'propOwner' : 'cf-properties',
+ 'propUsername' : 'admin',
+ 'propPassword' : 'adminPass',
+ 'tagOwner' : 'cf-tags',
+ 'tagUsername' : 'admin',
+ 'tagPassword' : 'adminPass'
+ }
cf=ConfigParser(defaults=dflt)
cf.read([
'/etc/channelfinderapi.conf',
@@ -45,4 +66,4 @@ def __loadConfig():
])
return cf
-_testConf=__loadConfig()
\ No newline at end of file
+_testConf=__loadConfig()
diff --git a/test/docker-compose.yml b/test/docker-compose.yml
new file mode 100644
index 0000000..dc9b22d
--- /dev/null
+++ b/test/docker-compose.yml
@@ -0,0 +1,67 @@
+# ------------------------------------------------------------------------------
+# Copyright (C) 2021 European Spallation Source ERIC.
+#
+# 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 2
+# 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, write to the Free Software
+# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+# ------------------------------------------------------------------------------
+
+version: "3.7"
+services:
+ channelfinder:
+ image: ghcr.io/channelfinder/channelfinderservice:master
+ hostname: channelfinder
+ networks:
+ - channelfinder-net
+ ports:
+ - 8080:8080
+ - 8443:8443
+ depends_on:
+ elasticsearch:
+ condition: service_healthy
+ environment:
+ elasticsearch.network.host: elasticsearch-cf
+ elasticsearch.http.port: 9200
+ ldap.enabled: "false"
+ embedded_ldap.enabled: "false"
+ demo_auth.enabled: "true"
+ skipITCoverage: "true"
+ EPICS_PVAS_INTF_ADDR_LIST: "0.0.0.0"
+ aa.enabled: "false"
+ restart: on-failure
+ healthcheck:
+ test: curl -s -f http://channelfinder:8080/ChannelFinder
+ interval: 30s
+ timeout: 60s
+ retries: 5
+
+ elasticsearch:
+ image: docker.elastic.co/elasticsearch/elasticsearch:8.11.4
+ hostname: elasticsearch-cf
+ networks:
+ - channelfinder-net
+ environment:
+ cluster.name: channelfinder
+ bootstrap.memory_lock: "true"
+ discovery.type: single-node
+ ES_JAVA_OPTS: "-Xms512m -Xmx512m"
+ xpack.security.enabled: "false"
+ healthcheck:
+ test: curl -f http://elasticsearch-cf:9200/_cluster/health
+ interval: 30s
+ timeout: 60s
+ retries: 5
+
+networks:
+ channelfinder-net:
+ driver: bridge
diff --git a/test/testCFPpropertyManager.py b/test/testCFPpropertyManager.py
index a770e03..66607d1 100644
--- a/test/testCFPpropertyManager.py
+++ b/test/testCFPpropertyManager.py
@@ -5,13 +5,13 @@
import re
import os
-from _testConf import _testConf
+from _testConf import _testConf, ChannelFinderClientTestCase
import urllib3
urllib3.disable_warnings()
-class CFPropertyManagerTest(unittest.TestCase):
+class CFPropertyManagerTest(ChannelFinderClientTestCase):
cfglines = []
diff --git a/test/testCFUpdateIOC.py b/test/testCFUpdateIOC.py
index 13b8ce2..a14fa38 100644
--- a/test/testCFUpdateIOC.py
+++ b/test/testCFUpdateIOC.py
@@ -14,13 +14,13 @@
from tempfile import NamedTemporaryFile
from copy import copy
-from _testConf import _testConf
+from _testConf import _testConf, ChannelFinderClientTestCase
import urllib3
urllib3.disable_warnings()
-class Test(unittest.TestCase):
+class UpdateIOCTest(ChannelFinderClientTestCase):
def setUp(self):
if _testConf.has_option('DEFAULT', 'BaseURL'):
self.baseURL = _testConf.get('DEFAULT', 'BaseURL')
@@ -167,6 +167,9 @@ def testPreservingOfAttributes(self):
client.set(channel={u'name':u'cf-update-pv1', u'owner':u'cf-update', u'properties':[unaffectedProperty], u'tags':[unaffectedTag]})
client.set(channel={u'name':u'cf-update-pv2', u'owner':u'cf-update', u'properties':[unaffectedProperty], u'tags':[unaffectedTag]})
+ unaffectedProperty['channels'] = []
+ unaffectedTag['channels'] = []
+
# Case1:
hostName = 'initialHost'
iocName = 'initialIoc'
diff --git a/test/testChannelFinderClient.py b/test/testChannelFinderClient.py
index a1a6680..eb7a3b0 100644
--- a/test/testChannelFinderClient.py
+++ b/test/testChannelFinderClient.py
@@ -11,14 +11,14 @@
from channelfinder import ChannelFinderClient
from channelfinder.util import ChannelUtil
-from _testConf import _testConf
+from _testConf import _testConf, ChannelFinderClientTestCase
import urllib3
urllib3.disable_warnings()
-class ConnectionTest(unittest.TestCase):
+class ConnectionTest(ChannelFinderClientTestCase):
def testConnection(self):
testUrl = getDefaultTestConfig("BaseURL")
self.assertNotEqual(ChannelFinderClient(BaseURL=testUrl,
@@ -34,7 +34,7 @@ def testConnection(self):
# Test JSON Parsing
# ===============================================================================
"""
-class JSONparserTest(unittest.TestCase):
+class JSONparserTest(ChannelFinderClientTestCase):
multiChannels = {u'channels': {u'channel': [{u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:0', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'0'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'19'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:1', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'1'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'22'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:2', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'2'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'38'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:3', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'3'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'65'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:4', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'4'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'78'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:5', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'5'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'79'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:6', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'6'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'90'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:7', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'7'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'5'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:8', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'8'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'64'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}, {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:9', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'9'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'85'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}]}}
singleChannels = {u'channels': {u'channel': {u'@owner': u'shroffk', u'@name': u'Test_first:a<000>:0:2', u'properties': {u'property': [{u'@owner': u'shroffk', u'@name': u'Test_PropA', u'@value': u'2'}, {u'@owner': u'shroffk', u'@name': u'Test_PropB', u'@value': u'38'}, {u'@owner': u'shroffk', u'@name': u'Test_PropC', u'@value': u'ALL'}]}, u'tags': {u'tag': [{u'@owner': u'shroffk', u'@name': u'Test_TagA'}, {u'@owner': u'shroffk', u'@name': u'Test_TagB'}]}}}}
@@ -91,7 +91,7 @@ def testEncodeChannels(self):
# ===============================================================================
# Test all the tag operations
# ===============================================================================
-class OperationTagTest(unittest.TestCase):
+class OperationTagTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.channelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -279,7 +279,7 @@ def testGetAllTags(self):
# Test all the property operations
# ===============================================================================
-class OperationPropertyTest(unittest.TestCase):
+class OperationPropertyTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.channelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -431,7 +431,7 @@ def testGetAllPropperties(self):
# ===============================================================================
#
# ===============================================================================
-class OperationChannelTest(unittest.TestCase):
+class OperationChannelTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.channelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -653,7 +653,7 @@ def testUpdateChannel(self):
# Update Opertation Tests
# ===============================================================================
-class UpdateOperationTest(unittest.TestCase):
+class UpdateOperationTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default set of Owners"""
self.channelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -673,6 +673,8 @@ def setUp(self):
""" Test Properties and Tags """
self.orgTag = {u'name': u'originalTag', u'owner': self.tagOwner}
self.orgProp = {u'name': u'originalProp', u'owner': self.propOwner, u'value': u'originalValue'}
+ self.orgTagResponse = {u'name': u'originalTag', u'owner': self.tagOwner, u'channels': []}
+ self.orgPropResponse = {u'name': u'originalProp', u'owner': self.propOwner, u'value': u'originalValue', u'channels': []}
self.clientTag.set(tag=self.orgTag)
self.clientProp.set(property=self.orgProp)
@@ -683,9 +685,8 @@ def setUp(self):
u'tags': [self.orgTag]})
ch = self.client.find(name=u'originalChannelName')
self.assertTrue(len(ch) == 1 and
- self.orgProp in ch[0][u'properties'] and
- self.orgTag in ch[0][u'tags'])
- pass
+ self.orgPropResponse in ch[0][u'properties'] and
+ self.orgTagResponse in ch[0][u'tags'])
def UpdateTagName(self):
newTagName = 'updatedTag'
@@ -696,13 +697,13 @@ def UpdateTagName(self):
self.client.findTag(newTagName) is not None)
# check that renaming the Tag does not remove it from any channel
channelTags = self.client.find(name=u'originalChannelName')[0][u'tags']
- self.assertTrue(self.orgTag not in channelTags and
- {u'name': newTagName, u'owner': self.tagOwner} in channelTags)
+ self.assertTrue(self.orgTagResponse not in channelTags and
+ {u'name': newTagName, u'owner': self.tagOwner, u'channels': []} in channelTags)
self.clientTag.update(tag=self.orgTag, originalTagName=newTagName)
def testUpdateTagOwner(self):
"""Test implemented in testUpdateTag"""
- pass
+ self.assertTrue(True)
# removed test till bug in the sevice is fixed - channelfinder needs to check for the existance of oldname not name
def UpdatePropName(self):
@@ -719,7 +720,7 @@ def UpdatePropName(self):
self.clientProp.update(property=self.orgProp, originalPropertyName=newPropName)
def testUpdatePropOwner(self):
- pass
+ self.assertTrue(True)
def testUpdateChannelName(self):
ch = self.client.find(name=u'originalChannelName')[0]
@@ -742,7 +743,6 @@ def UpdateChannelOwner(self):
self.clientCh.update(originalChannelName=u'originalChannelName',
channel=newChannel)
self.assertTrue(self.client.find(name=u'originalChannelName')[0][u'owner'] == self.tagOwner)
- pass
def testUpdateChannel(self):
"""
@@ -758,6 +758,9 @@ def testUpdateChannel(self):
updatedProp = {u'name': u'originalProp', u'owner': self.propOwner, u'value': u'updatedValue'}
newTag = {u'name': u'updatedTag', u'owner': self.tagOwner}
newProp = {u'name': u'newProp', u'owner': self.propOwner, u'value': u'newValue'}
+ updatedPropResponse = {u'name': u'originalProp', u'owner': self.propOwner, u'value': u'updatedValue', u'channels': []}
+ newTagResponse = {u'name': u'updatedTag', u'owner': self.tagOwner, u'channels': []}
+ newPropResponse = {u'name': u'newProp', u'owner': self.propOwner, u'value': u'newValue', u'channels': []}
try:
self.clientTag.set(tag=newTag)
self.clientProp.set(property=newProp)
@@ -767,12 +770,12 @@ def testUpdateChannel(self):
self.clientCh.update(originalChannelName=u'originalChannelName',
channel=newChannel)
foundChannel = self.client.find(name=u'updatedChannelName')[0]
- self.assertTrue(foundChannel[u'name'] == u'updatedChannelName' and
- foundChannel[u'owner'] == self.channelOwner and
- updatedProp in foundChannel[u'properties'] and
- newProp in foundChannel[u'properties'] and
- newTag in foundChannel[u'tags'] and
- self.orgTag in foundChannel[u'tags'])
+ self.assertTrue(foundChannel[u'name'] == u'updatedChannelName' )
+ self.assertTrue(foundChannel[u'owner'] == self.channelOwner )
+ self.assertTrue(updatedPropResponse in foundChannel[u'properties'] )
+ self.assertTrue(newPropResponse in foundChannel[u'properties'] )
+ self.assertTrue(newTagResponse in foundChannel[u'tags'] )
+ self.assertTrue(self.orgTagResponse in foundChannel[u'tags'])
finally:
# reset
@@ -791,20 +794,23 @@ def testUpdateChannel2(self):
"""
ch = self.client.find(name=u'originalChannelName')
self.assertTrue(len(ch) == 1 and
- self.orgProp in ch[0][u'properties'] and
- self.orgTag in ch[0][u'tags'])
- updated_prop = {u'name': u'originalProp',
+ self.orgPropResponse in ch[0][u'properties'] and
+ self.orgTagResponse in ch[0][u'tags'])
+ updatedProp = {u'name': u'originalProp',
u'owner': self.propOwner,
u'value': u'newPropValue'}
self.clientCh.update(channel={u'name': u'originalChannelName',
u'owner': u'newOwner',
- u'properties': [updated_prop],
+ u'properties': [updatedProp],
u'tags': []})
ch = self.client.find(name=u'originalChannelName')
- self.assertTrue(len(ch) == 1 and
- updated_prop in ch[0][u'properties'] and
- self.orgTag in ch[0][u'tags'] and
- ch[0][u'owner'] == u'newOwner')
+ updatedPropResponse = {u'name': u'originalProp',
+ u'owner': self.propOwner,
+ u'value': u'newPropValue', u'channels':[]}
+ self.assertTrue(len(ch) == 1)
+ self.assertTrue(updatedPropResponse in ch[0][u'properties'])
+ self.assertTrue(self.orgTagResponse in ch[0][u'tags'])
+ self.assertTrue(ch[0][u'owner'] == u'newOwner')
def testUpdateProperty(self):
"""
@@ -812,6 +818,7 @@ def testUpdateProperty(self):
Updates existing channels with new property owner, without altering original value.
"""
prop = self.client.findProperty(propertyname=u'originalProp')
+ prop[u'channels'] = []
self.assertDictEqual(prop, {u'owner': self.propOwner,
u'channels': [],
u'name': u'originalProp',
@@ -822,6 +829,7 @@ def testUpdateProperty(self):
self.clientProp.update(property=updatedProperty)
"""Check property owner"""
prop = self.client.findProperty(propertyname=u'originalProp')
+ prop[u'channels'] = []
self.assertDictEqual(prop, {u'owner': u'newOwner',
u'channels': [],
u'name': u'originalProp',
@@ -830,7 +838,7 @@ def testUpdateProperty(self):
ch = self.client.find(name=u'originalChannelName')
self.assertTrue({u'owner': u'newOwner',
u'name': u'originalProp',
- u'value': u'originalValue'} in ch[0][u'properties'])
+ u'value': u'originalValue', u'channels': []} in ch[0][u'properties'])
def testUpdateTag(self):
"""
@@ -838,6 +846,7 @@ def testUpdateTag(self):
Updates owner in all associated channels.
"""
tag = self.client.findTag(tagname=u'originalTag')
+ tag[u'channels'] = []
self.assertDictEqual(tag, {u'owner': self.tagOwner, u'channels': [], u'name': u'originalTag'})
updatedTag = dict(tag)
@@ -845,17 +854,17 @@ def testUpdateTag(self):
self.clientTag.update(tag=updatedTag)
"""Check tag owner"""
tag = self.client.findTag(tagname=u'originalTag')
+ tag[u'channels'] = []
self.assertDictEqual(tag, {u'owner': u'newOwner', u'channels': [], u'name': u'originalTag'})
"""Checks existing channel"""
ch = self.client.find(name=u'originalChannelName')
self.assertTrue({u'owner': u'newOwner',
- u'name': u'originalTag'} in ch[0][u'tags'])
+ u'name': u'originalTag', u'channels':[]} in ch[0][u'tags'])
def tearDown(self):
self.clientCh.delete(channelName=u'originalChannelName')
self.clientTag.delete(tagName=u'originalTag')
self.clientProp.delete(propertyName=u'originalProp')
- pass
"""
@@ -865,7 +874,7 @@ def tearDown(self):
"""
-class UpdateAppendTest(unittest.TestCase):
+class UpdateAppendTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.ChannelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -886,6 +895,11 @@ def setUp(self):
self.Tag2 = {u'name': u'tag2', u'owner': self.tagOwner}
self.Prop1 = {u'name': u'prop1', u'owner': self.propOwner, u'value': u'initialVal'}
self.Prop2 = {u'name': u'prop2', u'owner': self.propOwner, u'value': u'initialVal'}
+ self.Prop1Response = self.Prop1.copy()
+ self.Prop1Response["channels"] = []
+ self.Prop2Response = {u'name': u'prop2', u'owner': self.propOwner, u'value': u'initialVal'}
+ self.Prop2Response = self.Prop2.copy()
+ self.Prop2Response["channels"] = []
self.ch1 = {u'name': u'orgChannel1', u'owner': self.ChannelOwner, u'tags': [self.Tag1, self.Tag2]}
self.ch2 = {u'name': u'orgChannel2', u'owner': self.ChannelOwner, u'tags': [self.Tag2]}
self.ch3 = {u'name': u'orgChannel3', u'owner': self.ChannelOwner}
@@ -927,20 +941,22 @@ def testUpdateAppendProperty2Channel(self):
"""
Test to update a channel with a property
"""
- self.assertTrue(len(self.client.find(name=self.ch3[u'name'])) == 1 and
- self.client.find(name=self.ch3[u'name'])[0][u'properties'] == [],
+ self.assertEqual(len(self.client.find(name=self.ch3[u'name'])), 1)
+ self.assertEqual(self.client.find(name=self.ch3[u'name'])[0][u'properties'], [],
'the channel already has properties')
self.clientProp.update(property=self.Prop1, channelName=self.ch3[u'name'])
- self.assertTrue(len(self.client.find(name=self.ch3[u'name'])) == 1 and
- self.Prop1 in self.client.find(name=self.ch3[u'name'])[0][u'properties'],
+ self.assertEqual(len(self.client.find(name=self.ch3[u'name'])), 1)
+ ch3 = self.client.find(name=self.ch3[u'name'])
+ self.assertTrue(self.Prop1Response in ch3[0][u'properties'],
'failed to update the channel with a new property')
"""Check that Value of the property is correctly added"""
self.Prop2[u'value'] = 'val'
+ self.Prop2Response[u'value'] = 'val'
self.clientProp.update(property=self.Prop2, channelName=self.ch3[u'name'])
chs = self.client.find(name=self.ch3[u'name'])
self.assertTrue(len(chs) == 1 and
- self.Prop1 in chs[0][u'properties'] and
- self.Prop2 in chs[0][u'properties'],
+ self.Prop1Response in chs[0][u'properties'] and
+ self.Prop2Response in chs[0][u'properties'],
'Failed to update the channel with a new property without disturbing the old one')
self.client.set(channel=self.ch3)
@@ -955,12 +971,13 @@ def testUpdateAppendProperty2Channels(self):
self.client.find(name=self.ch3[u'name'])[0][u'properties'] == [],
'the channel already has properties')
self.Prop1[u'value'] = 'testVal'
+ self.Prop1Response[u'value'] = 'testVal'
self.clientProp.update(property=self.Prop1, channelNames=[self.ch2[u'name'], self.ch3[u'name']])
self.assertTrue(len(self.client.find(name=self.ch2[u'name'])) == 1 and
- self.Prop1 in self.client.find(name=self.ch2[u'name'])[0][u'properties'],
+ self.Prop1Response in self.client.find(name=self.ch2[u'name'])[0][u'properties'],
'failed to update the channel with a new property')
self.assertTrue(len(self.client.find(name=self.ch3[u'name'])) == 1 and
- self.Prop1 in self.client.find(name=self.ch3[u'name'])[0][u'properties'],
+ self.Prop1Response in self.client.find(name=self.ch3[u'name'])[0][u'properties'],
'failed to update the channel with a new property')
@unittest.skip("Skipping test for unimplemented functionality.")
@@ -971,7 +988,7 @@ def testUpdateRemoveProperty2Channel(self):
try:
self.client.set(channel={u'name': u'testChannel', u'owner': self.ChannelOwner, u'properties': [self.Prop1]})
channel = self.client.find(name=u'testChannel')
- self.assertTrue(len(channel) == 1 and self.Prop1 in channel[0][u'properties'],
+ self.assertTrue(len(channel) == 1 and self.Prop1Response in channel[0][u'properties'],
'Failed to create a test channel with property prop1')
self.Prop1[u'value'] = ''
channel[0][u'properties'] = [self.Prop1]
@@ -1004,7 +1021,7 @@ def UserOwnerCheck(self):
# Query Tests
# ===========================================================================
-class QueryTest(unittest.TestCase):
+class QueryTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.ChannelOwner = _testConf.get('DEFAULT', 'channelOwner')
@@ -1026,7 +1043,7 @@ def testEmptyReturn(self):
"""
find for non existing entities should return None instead of a 404
"""
- self.assertEquals(len(self.client.find(name=u'NonExistingChannelName')), 0,
+ self.assertEqual(len(self.client.find(name=u'NonExistingChannelName')), 0,
'Failed to return None when searching for a non existing channel')
def MultiValueQuery(self):
@@ -1111,7 +1128,7 @@ def MultiValueQuery(self):
# ===============================================================================
# ERROR tests
# ===============================================================================
-class ErrorTest(unittest.TestCase):
+class ErrorTest(ChannelFinderClientTestCase):
def setUp(self):
"""Default Owners"""
self.ChannelOwner = _testConf.get('DEFAULT', 'channelOwner')
diff --git a/test/testChannelUtil.py b/test/testChannelUtil.py
index 25b9ae4..fe63279 100644
--- a/test/testChannelUtil.py
+++ b/test/testChannelUtil.py
@@ -14,7 +14,7 @@
urllib3.disable_warnings()
-class Test(unittest.TestCase):
+class ChannelUtilTest(unittest.TestCase):
def setUp(self):