Merge branch 'master' of ssh://git.onelab.eu/git/sfa
[sfa.git] / tests / testInterfaces.py
1 #!/usr/bin/python
2 import sys
3 import os
4 import random
5 import string
6 import unittest
7 import sfa.util.xmlrpcprotocol as xmlrpc
8 from unittest import TestCase
9 from optparse import OptionParser
10 from sfa.util.xmlrpcprotocol import ServerException
11 from sfa.util.xrn import get_authority
12 from sfa.util.config import *
13 from sfa.trust.certificate import *
14 from sfa.trust.credential import *
15 from sfa.util.sfaticket import *
16 from sfa.util.rspec import *
17 from sfa.client import sfi
18
19 def random_string(size):
20     return "".join(random.sample(string.letters, size))
21
22 class Client:
23     registry = None
24     aggregate = None
25     sm = None
26     cm = None
27     key = None
28     cert = None
29     credential = None
30     type = None            
31     def __init__(self, options):
32         try: self.config = config = Config(options.config_file)
33         except:
34             print "failed to read config_file %s" % options.config_file
35             sys.exit(1)
36         key_path = os.path.dirname(options.config_file)
37         user_name = self.config.SFI_USER.split('.')[-1:][0]
38         key_file = key_path + os.sep + user_name + '.pkey'
39         cert_file = key_path + os.sep + user_name + '.cert'
40         self.key = Keypair(filename=key_file)
41         self.cert = Certificate(subject=self.config.SFI_USER)
42         self.cert.set_pubkey(self.key)
43         self.cert.set_issuer(self.key, self.config.SFI_USER)
44         self.cert.sign()
45         self.cert.save_to_file(cert_file)        
46         SFI_AGGREGATE = config.SFI_SM.replace('12347', '12346')
47         SFI_CM = 'http://' + options.cm_host + ':12346'
48         self.registry = xmlrpc.get_server(config.SFI_REGISTRY, key_file, cert_file)
49         self.aggregate = xmlrpc.get_server(SFI_AGGREGATE, key_file, cert_file)
50         self.sm = xmlrpc.get_server(config.SFI_SM, key_file, cert_file)
51         self.cm = xmlrpc.get_server(SFI_CM, key_file, cert_file)
52         self.hrn = config.SFI_USER
53         # XX defaulting to user, but this should be configurable so we can
54         # test from components persepctive
55         self.type = 'user'
56         self.credential = self.get_credential(self.hrn)
57         
58     def get_credential(self, hrn = None, type = 'user'):
59         if not hrn: hrn = self.hrn 
60         if hrn == self.hrn:
61             cert = self.cert.save_to_string(save_parents=True)
62             request_hash = self.key.compute_hash([cert, 'user', hrn])
63             credential = self.registry.get_self_credential(cert, type, hrn, request_hash)
64             return credential
65         else:
66             if not self.credential:
67                 self.credential = self.get_credential(self.hrn, 'user')
68             return self.registry.get_credential(self.credential, type, hrn)     
69
70 class BasicTestCase(unittest.TestCase):
71     def __init__(self, testname, client, test_slice=None):
72         unittest.TestCase.__init__(self, testname)
73         self.client = client
74         self.slice = test_slice
75     
76     def setUp(self):
77         self.registry = self.client.registry
78         self.aggregate = self.client.aggregate
79         self.sm = self.client.sm
80         self.cm = self.client.cm
81         self.credential = self.client.credential
82         self.hrn = self.client.hrn
83         self.type = self.client.type  
84                 
85 # Registry tests
86 class RegistryTest(BasicTestCase):
87
88     def setUp(self):
89         """
90         Make sure test records dont exsit
91         """
92         BasicTestCase.setUp(self)
93
94     def testGetSelfCredential(self):
95         cred = self.client.get_credential()
96         # this will raise an openssl error if the credential string isnt valid
97         Credential(string=cred)
98
99     def testRegister(self):
100         authority = get_authority(self.hrn)
101         auth_cred = self.client.get_credential(authority, 'authority')
102         auth_record = {'hrn': '.'.join([authority, random_string(10).lower()]),
103                        'type': 'authority'}
104         node_record = {'hrn': '.'.join([authority, random_string(10)]),
105                        'type': 'node',
106                        'hostname': random_string(6) + '.' + random_string(6)}
107         slice_record = {'hrn': '.'.join([authority, random_string(10)]),
108                         'type': 'slice', 'researcher': [self.hrn]}
109         user_record = {'hrn': '.'.join([authority, random_string(10)]),
110                        'type': 'user',
111                        'email': random_string(6) +'@'+ random_string(5) +'.'+ random_string(3),
112                        'first_name': random_string(7),
113                        'last_name': random_string(7)}
114
115         all_records = [auth_record, node_record, slice_record, user_record]
116         for record in all_records:
117             try:
118                 self.registry.register(auth_cred, record)
119                 self.registry.resolve(self.credential, record['hrn'])
120             except:
121                 raise
122             finally:
123                 try: self.registry.remove(auth_cred, record['type'], record['hrn'])
124                 except: pass
125
126     
127     def testRegisterPeerObject(self):
128         assert True
129    
130     def testUpdate(self):
131         authority = get_authority(self.hrn)
132         auth_cred = self.client.get_credential(authority, 'authority')
133         records = self.registry.resolve(self.credential, self.hrn)
134         if not records: assert False
135         record = records[0]
136         self.registry.update(auth_cred, record) 
137
138     def testResolve(self):
139         authority = get_authority(self.hrn)
140         self.registry.resolve(self.credential, self.hrn)
141    
142     def testRemove(self):
143         authority = get_authority(self.hrn)
144         auth_cred = self.client.get_credential(authority, 'authority')
145         record = {'hrn': ".".join([authority, random_string(10)]),
146                        'type': 'slice'}
147         self.registry.register(auth_cred, record)
148         self.registry.remove(auth_cred, record['type'], record['hrn'])
149         # should generate an exception
150         try:
151             self.registry.resolve(self.credential,  record['hrn'])
152             assert False
153         except:       
154             assert True
155  
156     def testRemovePeerObject(self):
157         assert True
158
159     def testList(self):
160         authority = get_authority(self.client.hrn)
161         self.registry.list(self.credential, authority)
162              
163     def testGetRegistries(self):
164         self.registry.get_registries(self.credential)
165     
166     def testGetAggregates(self):
167         self.registry.get_aggregates(self.credential)
168
169     def testGetTrustedCerts(self):
170         # this should fail unless we are a node
171         callable = self.registry.get_trusted_certs
172         server_exception = False 
173         try:
174             callable(self.credential)
175         except ServerException:
176             server_exception = True
177         finally:
178             if self.type in ['user'] and not server_exception:
179                 assert False
180             
181
182 class AggregateTest(BasicTestCase):
183     def setUp(self):
184         BasicTestCase.setUp(self)
185         
186     def testGetSlices(self):
187         self.aggregate.get_slices(self.credential)
188
189     def testGetResources(self):
190         # available resources
191         agg_rspec = self.aggregate.get_resources(self.credential)
192         # resources used by a slice
193         slice_rspec = self.aggregate.get_resources(self.credential, self.slice['hrn'])
194         # will raise an exception if the rspec isnt valid
195         RSpec(xml=agg_rspec)
196         RSpec(xml=slice_rspec)
197
198     def testCreateSlice(self):
199         # get availabel resources   
200         rspec = self.aggregate.get_resources(self.credential)
201         slice_credential = self.client.get_credential(self.slice['hrn'], 'slice')
202         self.aggregate.create_slice(slice_credential, self.slice['hrn'], rspec)
203
204     def testDeleteSlice(self):
205         slice_credential = self.client.get_credential(self.slice['hrn'], 'slice')
206         self.aggregate.delete_slice(slice_credential, self.slice['hrn'])
207
208     def testGetTicket(self):
209         slice_credential = self.client.get_credential(self.slice['hrn'], 'slice')
210         rspec = self.aggregate.get_resources(self.credential)
211         ticket = self.aggregate.get_ticket(slice_credential, self.slice['hrn'], rspec)
212         # will raise an exception if the ticket inst valid
213         SfaTicket(string=ticket)        
214
215 class SlicemgrTest(AggregateTest):
216     def setUp(self):
217         AggregateTest.setUp(self)
218         
219         # force calls to go through slice manager   
220         self.aggregate = self.sm
221
222         # get the slice credential
223         
224
225 class ComponentTest(BasicTestCase):
226     def setUp(self):
227         BasicTestCase.setUp(self)
228         self.slice_cred = self.client.get_credential(self.slice['hrn'], 'slice')
229
230     def testStartSlice(self):
231         self.cm.start_slice(self.slice_cred, self.slice['hrn'])
232
233     def testStopSlice(self):
234         self.cm.stop_slice(self.slice_cred, self.slice['hrn'])
235
236     def testDeleteSlice(self):
237         self.cm.delete_slice(self.slice_cred, self.slice['hrn'])
238
239     def testRestartSlice(self):
240         self.cm.restart_slice(self.slice_cred, self.slice['hrn'])
241
242     def testGetSlices(self):
243         self.cm.get_slices(self.slice_cred, self.slice['hrn'])
244
245     def testRedeemTicket(self):
246         rspec = self.aggregate.get_resources(self.credential)
247         ticket = self.aggregate.get_ticket(slice_cred, self.slice['hrn'], rspec)
248         self.cm.redeem_ticket(slice_cred, ticket)
249
250
251 def test_names(testcase):
252     return [name for name in dir(testcase) if name.startswith('test')]
253
254 def create_slice(client):
255     # register a slice that will be used for some test
256     authority = get_authority(client.hrn)
257     auth_cred = client.get_credential(authority, 'authority')
258     slice_record = {'hrn': ".".join([authority, random_string(10)]),
259                     'type': 'slice', 'researcher': [client.hrn]}
260     client.registry.register(auth_cred, slice_record)
261     return  slice_record
262  
263 def delete_slice(cleint, slice):
264     authority = get_authority(client.hrn)
265     auth_cred = client.get_credential(authority, 'authority')
266     if slice:
267         client.registry.remove(auth_cred, 'slice', slice['hrn'])
268     
269 if __name__ == '__main__':
270
271     args = sys.argv
272     prog_name = args[0]
273     default_config_dir = os.path.expanduser('~/.sfi/sfi_config')
274     default_cm = "echo.cs.princeton.edu"
275     parser = OptionParser(usage="%(prog_name)s [options]" % locals())
276     parser.add_option('-f', '--config_file', dest='config_file', default=default_config_dir,
277                       help='config file. default is %s' % default_config_dir)
278     parser.add_option('-r', '--registry', dest='registry', action='store_true',
279                       default=False, help='run registry tests')
280     parser.add_option('-a', '--aggregate', dest='aggregate', action='store_true',
281                       default=False, help='run aggregate tests')
282     parser.add_option('-s', '--slicemgr', dest='slicemgr', action='store_true',
283                       default=False, help='run slicemgr tests')
284     parser.add_option('-c', '--component', dest='component', action='store_true',
285                       default=False, help='run component tests')
286     parser.add_option('-d', '--cm_host', dest='cm_host', default=default_cm, 
287                       help='dns name of component to test. default is %s' % default_cm)
288     parser.add_option('-A', '--all', dest='all', action='store_true',
289                       default=False, help='run component tests')
290     
291     options, args = parser.parse_args()
292     suite = unittest.TestSuite()
293     client = Client(options)
294     test_slice = {}
295     
296     # create the test slice if necessary
297     if options.all or options.slicemgr or options.aggregate \
298        or options.component:
299         test_slice = create_slice(client)
300
301     if options.registry or options.all:
302         for name in test_names(RegistryTest):
303             suite.addTest(RegistryTest(name, client))
304
305     if options.aggregate or options.all: 
306         for name in test_names(AggregateTest):
307             suite.addTest(AggregateTest(name, client, test_slice))
308
309     if options.slicemgr or options.all: 
310         for name in test_names(SlicemgrTest):
311             suite.addTest(SlicemgrTest(name, client, test_slice))
312
313     if options.component or options.all: 
314         for name in test_names(ComponentTest):
315             suite.addTest(ComponentTest(name, client, test_slice))
316     
317     # run tests 
318     unittest.TextTestRunner(verbosity=2).run(suite)
319
320     # remove teset slice
321     delete_slice(client, test_slice)