REST Actions testing
[openflowplugin.git] / test-scripts / sw_restart_test.py
1 import unittest
2 import os
3 import re
4 import sys
5 import logging
6 import time
7 import argparse
8 import itertools
9 import requests
10 import xml.dom.minidom as md
11 from xml.etree import ElementTree as ET
12
13 from odl_tests_new import MininetTools, FileLoaderTools, ParseTools
14
15 class TestRestartMininet(unittest.TestCase):
16
17     log = logging.getLogger('TestRestartMininet')
18
19     def setUp(self):
20         TestRestartMininet.log.info('setUp')
21         self.switch_flows_stored = 0
22         self.table_id = 2
23
24         self.__start_MN()
25
26     def tearDown(self):
27         TestRestartMininet.log.info('tearDown')
28         self.net.stop()
29
30     def __start_MN(self):
31         wait_time = 15
32
33         self.net = MininetTools.create_network(self.host, self.mn_port)
34         self.net.start()
35         TestRestartMininet.log.info('mininet stared')
36         TestRestartMininet.log.info('waiting {} seconds...'.format(wait_time))
37         time.sleep(wait_time)
38
39     def __get_flows_string(self, net=None):
40         if net is None:
41             net = self.net
42         switch = net.switches[0]
43         output = switch.cmdPrint(
44         'ovs-ofctl -O OpenFlow13 dump-flows %s' % switch.name)
45
46         TestRestartMininet.log.debug('switch flow table: {}'.format(output))
47
48         return output.splitlines()[1:]
49
50     def __load_xmls(self, path='xmls'):
51         TestRestartMininet.log.info('loading xmls')
52         xmls = None
53         suite = unittest.TestSuite()
54         if args.xmls is not None:
55             xmls = map(int, args.xmls.split(','))
56
57         xmlfiles = None
58         if xmls is not None:
59             xmlfiles = (path + '/f%d.xml' % fid for fid in xmls)
60         else:
61             xmlfiles = (path + '/' + xml for xml in os.listdir(path) if xml.endswith('.xml'))
62
63         return xmlfiles
64
65     def __add_flows(self, path_to_xml):
66         TestRestartMininet.log.info('adding flow from xml: {}'.format(path_to_xml))
67         xml_string = FileLoaderTools.load_file_to_string(path_to_xml)
68         #TestRestartMininet.log.info('loaded xml: {}'.format(''.join(xml_string.split())))
69         tree = md.parseString(xml_string)
70
71         ids = ParseTools.get_values(tree.documentElement, 'table_id', 'id')
72
73         data = (self.host, self.port, ids['table_id'], ids['id'])
74
75         url = 'http://%s:%d/restconf/config/opendaylight-inventory:nodes' \
76               '/node/openflow:1/table/%s/flow/%s' % data
77         # send request via RESTCONF
78         headers = {
79             'Content-Type': 'application/xml',
80             'Accept': 'application/xml',
81         }
82         TestRestartMininet.log.info('sending request to url: {}'.format(url))
83         rsp = requests.put(url, auth=('admin', 'admin'), data=xml_string,
84                            headers=headers)
85         TestRestartMininet.log.info('received status code: {}'.format(rsp.status_code))
86         TestRestartMininet.log.debug('received content: {}'.format(rsp.text))
87         assert rsp.status_code == 204 or rsp.status_code == 200, 'Status' \
88                         ' code returned %d' % rsp.status_code
89         
90         # check request content against restconf's datastore
91         response = requests.get(url, auth=('admin', 'admin'),
92                                 headers={'Accept': 'application/xml'})
93         assert response.status_code == 200
94
95         switch_flows = self.__get_flows_string(self.net)
96         assert len(switch_flows) > 0
97
98         # store last used table id which got flows for later checkup
99         self.table_id = ids['table_id']
100         self.switch_flows_stored = len(switch_flows)
101         TestRestartMininet.log.info('stored: {} flows'.format(self.switch_flows_stored))
102
103     def test(self):
104
105         xmls = self.__load_xmls()
106         for xml in xmls:
107             self.__add_flows(xml)
108         
109         switch_flows = 0
110
111         TestRestartMininet.log.info('---------- preparation finished, running test ----------\n\n')
112         assert self.switch_flows_stored > 0, 'don\'t have any stored flows'
113         TestRestartMininet.log.info('got {} stored flows'.format(self.switch_flows_stored))
114
115         #STOP mininet and start it again - then check flows
116         TestRestartMininet.log.info('restaring mininet...')
117         self.net.stop()
118         TestRestartMininet.log.info('mininet stopped')
119         self.__start_MN()
120
121         url = 'http://%s:%d/restconf/config/opendaylight-inventory:nodes' \
122             '/node/openflow:1/table/%s/' % (self.host, self.port, self.table_id)
123         TestRestartMininet.log.info('checking flows in controller - sending request to url: {}'.format(url))
124         response = requests.get(url, auth=('admin', 'admin'),
125                                 headers={'Accept': 'application/xml'})
126         assert response.status_code == 200
127
128         tree = ET.ElementTree(ET.fromstring(response.text))
129         flows_on_controller = len(tree.getroot())
130         TestRestartMininet.log.info('{} flows are stored in switch config datastore'.format(flows_on_controller))
131
132         current_try = 1
133
134         while current_try <= self.retry and switch_flows != self.switch_flows_stored:
135             TestRestartMininet.log.info('trying to get flows from mininet switch: {}/{}...'.format(current_try, self.retry))
136             TestRestartMininet.log.info('waiting {} more seconds...'.format(self.wait))
137             time.sleep(self.wait)
138             switch_flows = len(self.__get_flows_string(self.net))
139             TestRestartMininet.log.info('got {} flows...'.format(switch_flows))
140             current_try = current_try + 1
141
142         assert self.switch_flows_stored == switch_flows, 'Stored amount of flows on switch should be equal to stored flows on controller'\
143             ' %d <> %d' % (switch_flows,self.switch_flows_stored)
144
145 if __name__ == '__main__':
146     logging.basicConfig(level=logging.INFO)
147
148     # parse cmdline arguments
149     parser = argparse.ArgumentParser(description='Test for flow addition to'
150                         ' switch after the switch has been restarted')
151     parser.add_argument('--odlhost', default='127.0.0.1', help='host where '
152                         'odl controller is running')
153     parser.add_argument('--odlport', type=int, default=8080, help='port on '
154                         'which odl\'s RESTCONF is listening')
155     parser.add_argument('--mnport', type=int, default=6653, help='port on '
156                         'which odl\'s controller is listening')
157     parser.add_argument('--xmls', default=None, help='generete tests only '
158                         'from some xmls (i.e. 1,3,34) ')
159     parser.add_argument('--wait', default=30, help='number of second that '
160                         'should test wait before trying to get flows from '
161                         'restared mininet switch')
162     parser.add_argument('--retry', default=1, help='number of tries to get'
163                         'flows from restarted mininet')
164     args = parser.parse_args()
165
166     # set host and port of ODL controller for test cases
167     TestRestartMininet.port = args.odlport
168     TestRestartMininet.host = args.odlhost
169     TestRestartMininet.mn_port = args.mnport
170     TestRestartMininet.wait = args.wait
171     TestRestartMininet.retry = args.retry
172
173     del sys.argv[1:]
174     unittest.main()