| 1 |  |  | import json | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 |  |  | import unittest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 |  |  | import warnings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 |  |  | from server import server | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 |  |  | class TestSwaggerCoverage(unittest.TestCase): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 |  |  |     @classmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 |  |  |     def setUpClass(cls): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 |  |  |         cls.client = server.test_client() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |         cls.BANNED_RULES = [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 |  |  |             '/routes', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 |  |  |             '/status', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 |  |  |             '/spec', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 |  |  |             '/ping', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 |  |  |             '/specs', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 |  |  |             '/apidocs', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 |  |  |             '/static' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |         cls.THRESHOLD = 100 | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 22 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 23 |  |  |     def test_swagger_coverage(self): | 
            
                                                                        
                            
            
                                    
            
            
                | 24 |  |  |         """ The swagger coverage should be 100% """ | 
            
                                                                        
                            
            
                                    
            
            
                | 25 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 26 |  |  |         self.color_print('yellow', '\n##### SWAGGER COVERAGE #####') | 
            
                                                                        
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 28 |  |  |         swagger_specs = self.retrieve_swagger_specs() | 
            
                                                                        
                            
            
                                    
            
            
                | 29 |  |  |         rules = self.filter_rules(self.client.application.url_map.iter_rules()) | 
            
                                                                        
                            
            
                                    
            
            
                | 30 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 31 |  |  |         ( | 
            
                                                                        
                            
            
                                    
            
            
                | 32 |  |  |             covered_methods, | 
            
                                                                        
                            
            
                                    
            
            
                | 33 |  |  |             methods_total | 
            
                                                                        
                            
            
                                    
            
            
                | 34 |  |  |         ) = self.retrieve_covered_methods_number(rules, swagger_specs) | 
            
                                                                        
                            
            
                                    
            
            
                | 35 |  |  |         coverage = int(100 * covered_methods / methods_total) | 
            
                                                                        
                            
            
                                    
            
            
                | 36 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 37 |  |  |         end_color = 'green' if coverage == 100 else 'yellow' | 
            
                                                                        
                            
            
                                    
            
            
                | 38 |  |  |         self.color_print( | 
            
                                                                        
                            
            
                                    
            
            
                | 39 |  |  |             end_color, | 
            
                                                                        
                            
            
                                    
            
            
                | 40 |  |  |             '%s of %s routes are swagged' % ( | 
            
                                                                        
                            
            
                                    
            
            
                | 41 |  |  |                 str(covered_methods), | 
            
                                                                        
                            
            
                                    
            
            
                | 42 |  |  |                 str(methods_total) | 
            
                                                                        
                            
            
                                    
            
            
                | 43 |  |  |             ) | 
            
                                                                        
                            
            
                                    
            
            
                | 44 |  |  |         ) | 
            
                                                                        
                            
            
                                    
            
            
                | 45 |  |  |  | 
            
                                                                        
                            
            
                                    
            
            
                | 46 |  |  |         self.assertTrue(coverage >= self.THRESHOLD) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |     def retrieve_swagger_specs(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |         """ Fetch the swagger specs """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         # suppress flasgger unclosed file warnings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 |  |  |         with warnings.catch_warnings(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 |  |  |             warnings.filterwarnings("ignore", message="unclosed file") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 |  |  |             response = self.client.get('application/spec') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 |  |  |         response_json = json.loads(response.data.decode('utf-8')) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |         swagger_specs = response_json['paths'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |         return swagger_specs | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |     def retrieve_covered_methods_number(self, rules, swagger_specs): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |         """ Return the number of covered methods and the number of methods """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 |  |  |         methods_total = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 |  |  |         covered_methods = 0 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 |  |  |         for rule in rules: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |             methods = self.filter_methods(rule.methods) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |             parsed_rule = self.format_rule(rule) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |             for method in methods: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |                 methods_total += 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 |  |  |                 try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 |  |  |                     swagger_specs[parsed_rule][method.lower()] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |                     covered_methods += 1 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |                 except KeyError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 |  |  |                     self.color_print( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |                         'red', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |                         'Uncovered: %s of route %s' % (method, parsed_rule) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |                     ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |         return (covered_methods, methods_total) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 |  |  |     def filter_methods(methods): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |         """ Filter methods OPTIONS and HEAD """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 |  |  |         return [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 |  |  |             method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 |  |  |             for method in methods | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 |  |  |             if method not in ['OPTIONS', 'HEAD'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |     def format_rule(rule): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |         Format the rule for swagger | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |         Replace '<' with '{' and '>' with '}' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |         Remove arguments type | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |         return ( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |             str(rule) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 |  |  |             .replace('<', '{') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |             .replace('>', '}') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |             .replace('string:', '') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |             .replace('int:', '') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |     def filter_rules(self, rules): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 |  |  |         """ Filter rules that do not need to be documented """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 |  |  |         return [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |             rule | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |             for rule in rules | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |             if not self.is_banned_rule(rule) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 |  |  |         ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 |  |  |     def is_banned_rule(self, rule): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 |  |  |         """ Check if rule should be banned """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 |  |  |         return any( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |             banned_rule in str(rule) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 |  |  |             for banned_rule in self.BANNED_RULES | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |         ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |     def color_print(color, message): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |         """ Print message with some nice color """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |         colors = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 |  |  |             'green': '\033[92m', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 |  |  |             'yellow': '\033[93m', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |             'red': '\033[91m', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 |  |  |             'endc': '\033[0m', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |         } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 |  |  |         print(colors[color] + message + colors['endc']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  | if __name__ == '__main__': | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 134 |  |  |     unittest.main() | 
            
                                                        
            
                                    
            
            
                | 135 |  |  |  |