Merge "Testcase for router/FloatingIP & net assoc mutual exclusivity"
[sdnvpn.git] / sdnvpn / lib / results.py
1 #!/usr/bin/python
2 #
3 # Copyright (c) 2016 All rights reserved
4 # This program and the accompanying materials
5 # are made available under the terms of the Apache License, Version 2.0
6 # which accompanies this distribution, and is available at
7 #
8 # http://www.apache.org/licenses/LICENSE-2.0
9 #
10 import time
11
12 import functest.utils.functest_logger as ft_logger
13 import functest.utils.functest_utils as ft_utils
14
15 logger = ft_logger.Logger("sdnvpn-results").getLogger()
16
17
18 class Results(object):
19
20     def __init__(self, line_length):
21         self.line_length = line_length
22         self.test_result = "PASS"
23         self.summary = ""
24         self.details = []
25         self.num_tests = 0
26         self.num_tests_failed = 0
27
28     def get_ping_status(self,
29                         vm_source,
30                         vm_target,
31                         expected="PASS", timeout=30):
32         console_log = vm_source.get_console_output()
33
34         ip_source = vm_source.networks.itervalues().next()[0]
35         ip_target = vm_target.networks.itervalues().next()[0]
36
37         if "request failed" in console_log:
38             # Normally, cirros displays this message when userdata fails
39             logger.debug("It seems userdata is not supported in "
40                          "nova boot...")
41             return False
42         else:
43             tab = ("%s" % (" " * 53))
44             expected_result = 'can ping' if expected == 'PASS' \
45                               else 'cannot ping'
46             test_case_name = ("'%s' %s '%s'" %
47                               (vm_source.name,
48                                expected_result,
49                                vm_target.name))
50             logger.debug("%sPing\n%sfrom '%s' (%s)\n%sto '%s' (%s).\n"
51                          "%s-->Expected result: %s.\n"
52                          % (tab, tab, vm_source.name, ip_source,
53                             tab, vm_target.name, ip_target,
54                             tab, expected_result))
55             while True:
56                 console_log = vm_source.get_console_output()
57                 # the console_log is a long string, we want to take
58                 # the last 4 lines (for example)
59                 lines = console_log.split('\n')
60                 last_n_lines = lines[-5:]
61                 if ("ping %s OK" % ip_target) in last_n_lines:
62                     msg = ("'%s' can ping '%s'"
63                            % (vm_source.name, vm_target.name))
64                     if expected == "PASS":
65                         logger.debug("[PASS] %s" % msg)
66                         self.add_success(test_case_name)
67                     else:
68                         logger.debug("[FAIL] %s" % msg)
69                         self.test_result = "FAIL"
70                         self.add_failure(test_case_name)
71                         logger.debug("\n%s" % last_n_lines)
72                     break
73                 elif ("ping %s KO" % ip_target) in last_n_lines:
74                     msg = ("'%s' cannot ping '%s'" %
75                            (vm_source.name, vm_target.name))
76                     if expected == "FAIL":
77                         logger.debug("[PASS] %s" % msg)
78                         self.add_success(test_case_name)
79                     else:
80                         logger.debug("[FAIL] %s" % msg)
81                         self.test_result = "FAIL"
82                         self.add_failure(test_case_name)
83                     break
84                 time.sleep(1)
85                 timeout -= 1
86                 if timeout == 0:
87                     self.test_result = "FAIL"
88                     logger.debug("[FAIL] Timeout reached for '%s'. "
89                                  "No ping output captured in the console log"
90                                  % vm_source.name)
91                     self.add_failure(test_case_name)
92                     break
93
94     def add_to_summary(self, num_cols, col1, col2=""):
95         if num_cols == 0:
96             self.summary += ("+%s+\n" % (col1 * (self.line_length - 2)))
97         elif num_cols == 1:
98             self.summary += ("| " + col1.ljust(self.line_length - 3) + "|\n")
99         elif num_cols == 2:
100             self.summary += ("| %s" % col1.ljust(7) + "| ")
101             self.summary += (col2.ljust(self.line_length - 12) + "|\n")
102             if col1 in ("FAIL", "PASS"):
103                 self.details.append({col2: col1})
104                 self.num_tests += 1
105                 if col1 == "FAIL":
106                     self.num_tests_failed += 1
107
108     def record_action(self, msg):
109         """Record and log an action and display it in the summary."""
110         logger.info(msg)
111         self.add_to_summary(1, msg)
112
113     def add_failure(self, test):
114         self.add_to_summary(2, "FAIL", test)
115
116     def add_success(self, test):
117         self.add_to_summary(2, "PASS", test)
118
119     def check_ssh_output(self, vm_source, vm_target,
120                          expected, timeout=30):
121         console_log = vm_source.get_console_output()
122         ip_source = vm_source.networks.itervalues().next()[0]
123         ip_target = vm_target.networks.itervalues().next()[0]
124
125         if "request failed" in console_log:
126             # Normally, cirros displays this message when userdata fails
127             logger.debug("It seems userdata is not supported in "
128                          "nova boot...")
129             return False
130         else:
131             tab = ("%s" % (" " * 53))
132             test_case_name = ("[%s] returns 'I am %s' to '%s'[%s]" %
133                               (ip_target, expected,
134                                vm_source.name, ip_source))
135             logger.debug("%sSSH\n%sfrom '%s' (%s)\n%sto '%s' (%s).\n"
136                          "%s-->Expected result: %s.\n"
137                          % (tab, tab, vm_source.name, ip_source,
138                             tab, vm_target.name, ip_target,
139                             tab, expected))
140             while True:
141                 console_log = vm_source.get_console_output()
142                 # the console_log is a long string, we want to take
143                 # the last 4 lines (for example)
144                 lines = console_log.split('\n')
145                 last_n_lines = lines[-5:]
146                 if ("%s %s" % (ip_target, expected)) in last_n_lines:
147                     logger.debug("[PASS] %s" % test_case_name)
148                     self.add_success(test_case_name)
149                     break
150                 elif ("%s not reachable" % ip_target) in last_n_lines:
151                     logger.debug("[FAIL] %s" % test_case_name)
152                     self.add_failure(test_case_name)
153                     self.test_result = "FAIL"
154                     break
155                 time.sleep(1)
156                 timeout -= 1
157                 if timeout == 0:
158                     self.test_result = "FAIL"
159                     logger.debug("[FAIL] Timeout reached for '%s'."
160                                  " No ping output captured in the console log"
161                                  % vm_source.name)
162                     self.add_failure(test_case_name)
163                     break
164
165     def ping_ip_test(self, address):
166         ping = "ping %s -c 3" % address
167         testcase_name = "Ping IP %s" % address
168         exit_code = ft_utils.execute_command(ping)
169
170         if exit_code != 0:
171             self.add_failure(testcase_name)
172         else:
173             self.add_success(testcase_name)
174
175     def compile_summary(self, SUCCESS_CRITERIA):
176         success_message = "All the subtests have passed."
177         failure_message = "One or more subtests have failed."
178
179         self.add_to_summary(0, "=")
180         logger.info("\n%s" % self.summary)
181         if self.test_result == "PASS":
182             logger.info(success_message)
183         else:
184             logger.info(failure_message)
185
186         status = "PASS"
187         success = 100 - \
188             (100 * int(self.num_tests_failed) / int(self.num_tests))
189         if success < int(SUCCESS_CRITERIA):
190             status = "FAILED"
191
192         return {"status": status, "details": self.details}