1# Copyright 2015 Amazon.com, Inc. or its affiliates. All Rights Reserved. 2# 3# Licensed under the Apache License, Version 2.0 (the "License"). You 4# may not use this file except in compliance with the License. A copy of 5# the License is located at 6# 7# https://aws.amazon.com/apache2.0/ 8# 9# or in the "license" file accompanying this file. This file is 10# distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF 11# ANY KIND, either express or implied. See the License for the specific 12# language governing permissions and limitations under the License. 13import pytest 14import botocore.session 15from botocore import xform_name 16from botocore.exceptions import DataNotFoundError 17 18import boto3 19from boto3.docs.service import ServiceDocumenter 20 21 22@pytest.fixture 23def botocore_session(): 24 return botocore.session.get_session() 25 26 27@pytest.fixture 28def boto3_session(): 29 return boto3.Session(region_name='us-east-1') 30 31 32def all_services(): 33 session = boto3.Session(region_name='us-east-1') 34 for service_name in session.get_available_services(): 35 yield service_name 36 37 38@pytest.fixture 39def available_resources(): 40 session = boto3.Session(region_name='us-east-1') 41 return session.get_available_resources() 42 43 44@pytest.mark.parametrize('service_name', all_services()) 45def test_documentation( 46 boto3_session, botocore_session, available_resources, service_name 47): 48 generated_docs = ServiceDocumenter( 49 service_name, session=boto3_session).document_service() 50 generated_docs = generated_docs.decode('utf-8') 51 client = boto3.client(service_name, 'us-east-1') 52 53 # Check that all of the services have the appropriate title 54 _assert_has_title(generated_docs, client) 55 56 # Check that all services have the client documented. 57 _assert_has_client_documentation(generated_docs, service_name, client) 58 59 # If the service has resources, make sure the service resource 60 # is at least documented. 61 if service_name in available_resources: 62 63 resource = boto3.resource(service_name, 'us-east-1') 64 _assert_has_resource_documentation( 65 generated_docs, service_name, resource 66 ) 67 68 # If the client can paginate, make sure the paginators are documented. 69 try: 70 paginator_model = botocore_session.get_paginator_model(service_name) 71 _assert_has_paginator_documentation( 72 generated_docs, service_name, client, 73 sorted(paginator_model._paginator_config) 74 ) 75 except DataNotFoundError: 76 pass 77 78 # If the client has waiters, make sure the waiters are documented. 79 if client.waiter_names: 80 waiter_model = botocore_session.get_waiter_model(service_name) 81 _assert_has_waiter_documentation( 82 generated_docs, service_name, client, waiter_model 83 ) 84 85 86def _assert_contains_lines_in_order(lines, contents): 87 for line in lines: 88 assert line in contents 89 beginning = contents.find(line) 90 contents = contents[(beginning + len(line)):] 91 92 93def _assert_has_title(generated_docs, client): 94 title = client.__class__.__name__ 95 ref_lines = [ 96 '*' * len(title), 97 title, 98 '*' * len(title) 99 ] 100 _assert_contains_lines_in_order(ref_lines, generated_docs) 101 102 103def _assert_has_client_documentation(generated_docs, service_name, client): 104 class_name = client.__class__.__name__ 105 ref_lines = [ 106 '======', 107 'Client', 108 '======', 109 '.. py:class:: %s.Client' % class_name, 110 ' A low-level client representing', 111 ' import boto3', 112 ' client = boto3.client(\'%s\')' % service_name, 113 ' These are the available methods:', 114 ' * :py:meth:`~%s.Client.get_paginator`' % class_name, 115 ' * :py:meth:`~%s.Client.get_waiter`' % class_name, 116 ' .. py:method:: get_paginator(operation_name)', 117 ' .. py:method:: get_waiter(waiter_name)', 118 ] 119 _assert_contains_lines_in_order(ref_lines, generated_docs) 120 121 122def _assert_has_paginator_documentation(generated_docs, service_name, client, 123 paginator_names): 124 ref_lines = [ 125 '==========', 126 'Paginators', 127 '==========', 128 'The available paginators are:' 129 ] 130 for paginator_name in paginator_names: 131 ref_lines.append( 132 '* :py:class:`%s.Paginator.%s`' % ( 133 client.__class__.__name__, paginator_name)) 134 135 for paginator_name in paginator_names: 136 ref_lines.append( 137 '.. py:class:: %s.Paginator.%s' % ( 138 client.__class__.__name__, paginator_name)) 139 ref_lines.append( 140 ' .. py:method:: paginate(') 141 142 _assert_contains_lines_in_order(ref_lines, generated_docs) 143 144 145def _assert_has_waiter_documentation(generated_docs, service_name, client, 146 waiter_model): 147 ref_lines = [ 148 '=======', 149 'Waiters', 150 '=======', 151 'The available waiters are:' 152 ] 153 for waiter_name in waiter_model.waiter_names: 154 ref_lines.append( 155 '* :py:class:`%s.Waiter.%s`' % ( 156 client.__class__.__name__, waiter_name)) 157 158 for waiter_name in waiter_model.waiter_names: 159 ref_lines.append( 160 '.. py:class:: %s.Waiter.%s' % ( 161 client.__class__.__name__, waiter_name)) 162 ref_lines.append( 163 ' waiter = client.get_waiter(\'%s\')' % xform_name(waiter_name)) 164 ref_lines.append( 165 ' .. py:method:: wait(') 166 167 _assert_contains_lines_in_order(ref_lines, generated_docs) 168 169 170def _assert_has_resource_documentation(generated_docs, service_name, resource): 171 ref_lines = [ 172 '================', 173 'Service Resource', 174 '================', 175 '.. py:class:: %s.ServiceResource' % ( 176 resource.meta.client.__class__.__name__), 177 ' A resource representing', 178 ' import boto3', 179 ' %s = boto3.resource(\'%s\')' % (service_name, service_name), 180 ] 181 _assert_contains_lines_in_order(ref_lines, generated_docs) 182