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