1 Extending kamaki.clients
2 ========================
4 By default, kamaki clients are REST clients (they manage HTTP requests and responses to communicate with services).
9 All service clients consist of a subclass of the Client class and implement separate client functionalities as member methods. There is also an error class to raise exceptions that can be handled by kamaki interfaces.
11 .. code-block:: python
13 # ${KAMAKI_PATH}/kamaki/clients/mynewclient.py
15 from kamaki.clients import Client, ClientError
17 class MyNewClient(Client):
18 """MyNewClient Description Here"""
20 def my_first_method(self, **args):
21 """Method description"""
26 except SomeKnownException as e1:
27 raise ClientError('MyError: %s' % e1)
28 except SomeOtherException as e2:
29 raise ClientError('MyError: %s' % e2)
31 def my_second_method(self, **params):
32 """Method description"""
35 Custom clients can use a set of convenience methods for easy HTTP requests
37 .. code-block:: python
39 def get(self, path, **kwargs)
40 def head(self, path, **kwargs)
41 def post(self, path, **kwargs)
42 def put(self, path, **kwargs)
43 def delete(self, path, **kwargs)
44 def copy(self, path, **kwargs)
45 def move(self, path, **kwargs)
47 How to use your client
48 ----------------------
50 External applications must instantiate a MyNewClient object.
52 .. code-block:: python
54 from kamaki.clients import ClientError
55 from kamaki.clients.mynewclient import MyNewClient
59 cl = MyNewClient(args)
60 cl.my_first_method(other_args)
61 except ClientError as cle:
62 print('Client Error: %s' % cle)
68 Kamaki clients may handle multiple requests at once, using threads. In that case, users might implement their own thread handling mechanism, use an external solution or take advantage of the mechanism featured in kamaki.clients
70 .. code-block:: python
72 from threading import enumerate
73 from kamaki.clients import SilentEvent
76 class MyNewClient(Client):
79 def _single_threaded_method(self, **args):
84 def multithread_method(self):
86 self._init_thread_limit()
87 while some_condition or thread_list:
89 event = SilentEvent(self._single_threaded_method, **args)
91 thread_list.append(event)
92 thread_list = self._watch_thread_limit(thread_list)
97 The kamaki.clients package contains a set of fine-grained unit-tests for all its packages.
99 .. note:: unit tests require the optional python-mock package, version 1.X or better
104 To run the tests, the kamaki source code has to be downloaded.
106 .. code-block:: console
108 $ git clone https://code.grnet.gr/git/kamaki
109 $ cd kamaki/kamaki/clients
111 In each package under kamaki.clients, there is a test module (test.py) where the tests are implemented. To run all tests, run the test.py file from kamaki.clients
113 .. code-block:: console
117 To test a specific class, add the class name as an argument. E.g. for the Client class:
119 .. code-block:: console
121 $ python test.py Client
123 To test a specific method in a class, apply an extra argument, e.g. for the request method in the Client class:
125 .. code-block:: console
127 $ python test.py Client request
129 Each package contains a test module (test.py) which is also runnable from the command line. E.g. in the pithos package there is a test module which contains, among others, the **download** sub-test:
131 .. code-block:: console
135 # Run all kamaki.clients.pithos tests
138 # Run all kamaki.clients.pithos.PithoClient tests
139 $ python test.py Pithos
141 # Test kamaki.clients.pithos.PithosClient.download
142 $ python test.py Pithos download
144 To fully test a specific package, run test.py from the package location. E.g. to test everything in kamaki.clients.pithos package:
146 .. code-block:: console
154 Each folder / package contains a test.py file, that represents the test module of this package. All test modules contain a set of classes that extent the TestCase class. They also contain a main method to run the tests.
156 By convention, testing classes are named as <Tested Class> where <Test Class> is the name of the tested class or module. Methods not grouped in classes are tested by classes named after their respective module.
158 For example, the kamaki.clients.pithos.PithosClient class is tested by the kamaki.clients.pithos.test.PithosClient class, while the methods in kamaki.clients.utils module are tested by the kamaki.clients.utils.test.Utils testing class.
162 After modifying or extending kamaki.clients method, classes, modules or packages, it is a good practice to also modify or extend the corresponding unit tests. What's more, it is recommended to modify or implement the testing of new behavior before implementing the behavior itself. The aim for kamaki.clients package is an 1 to 1 mapping between methods and their tests.
164 Modifying an existing method
165 """"""""""""""""""""""""""""
167 In case of an existing method modification, the programmer has to modify the corresponding test as well. By convention, the test method is located in the test module under the same package, in a TestCase subclass that is named with a name similar to the package or class that contains the tested method.
169 Example 1: to modify the kamaki.clients.utils.filter_in method, the programmer has to also adjust the kamaki.clients.utils.test.Utils.test_filter_in method.
171 Example 2: to modify the kamaki.clients.pithos.PithosRestClient.object_get, the programmer has to also adjust the kamaki.clients.pithos.test.PithosRestClient.test_object_get method.
176 Programmers who want to implement a new method in an existing class, are encouraged to implement the corresponding unit test first. In order to do that, they should find the testing class that is mapped to the class or module they need to extend.
178 Example 1: To add a **list_special** method to kamaki.clients.astakos.AstakosClient, extend the kamaki.clients.astakos.test.AstakosClient class, as shown bellow:
180 .. code-block:: python
182 # file: ${kamaki}/kamaki/clients/astakos/__init__.py
184 class AstakosClient(TestCase):
186 def test_list_special(self):
187 """Test the list_special method"""
190 Example 2: To add a **get_random_int** method in kamaki.clients.utils module, extend the kamaki.clients.utils.test.Utils test class, as shown bellow:
192 .. code-block:: python
194 # file: ${kamaki}/kamaki/clients/utils/__init__.py
196 class Utils(TestCase):
198 def test_get_random_int(self):
199 """Test the get_random_int method"""
202 Implementing a new class or module
203 """"""""""""""""""""""""""""""""""
205 Each class or module needs a seperate test sub-module. By convention, each class or module under the kamaki.clients should be located in a separate directory.
207 Example 1: To add a NewService class that implements the kamaki.clients.Client interface:
209 * create a new_service package and implement the unit tests in the kamaki.clients.new_service.test module:
211 .. code-block:: console
213 $ mkdir new_service && touch new_service/test.py
215 * create the file that will hold the package code and implement the module there:
217 .. code-block:: console
219 $ touch new_service/__init__.py
221 * Create the test class and methods in kamaki.clients.new_service.test
223 .. code-block:: python
225 # file: ${kamaki}/kamaki/clients/new_service/test.py
226 from unittest import TestCase
228 class NewService(TestCase):
230 def test_method1(self):
233 * Create the NewService and its actual functionality in kamaki.clients.new_service
235 .. code-block:: python
237 # file: ${kamaki}/kamaki/clients/new_service/__init__.py
238 from kamaki.clients import Client
240 class NewService(Client):
242 def method1(self, ...):
245 * Expose the new tests to top test module, by importing the test class to kamaki.clients.test
247 ..code-block:: python
249 # file: ${kamaki}/kamaki/clients/test.py
251 from kamaki.clients.new_service.test import NewService
253 .. note:: If the new class or module is part of an existing sub-package, it is acceptable to append its testing class in the existing test.py file of the sub-package it belongs to. For example, the kamaki.clients.pithos.PithosClient and kamaki.clients.pithos.rest_api.PithosRestClient classes are tested by two different classes (PithosClient and PithosRestClient respectively) in the same module (kamaki.clients.pithos.test).