diff --git a/endpoints/test/test_live_auth.py b/endpoints/test/test_live_auth.py index 69adbb6..646e991 100644 --- a/endpoints/test/test_live_auth.py +++ b/endpoints/test/test_live_auth.py @@ -106,6 +106,11 @@ def become_apikey_app(self, project_id): shutil.copytree(source_path, self.app_path) self.update_app_yaml(project_id) + def become_base_path_app(self, project_id): + source_path = os.path.join(TESTDIR, 'testdata', 'base_path_sample_app') + shutil.copytree(source_path, self.app_path) + self.update_app_yaml(project_id) + def update_app_yaml(self, project_id, version=None): yaml_path = os.path.join(self.app_path, 'app.yaml') app_yaml = yaml.load(open(yaml_path)) @@ -125,7 +130,7 @@ def apikey_app(gcloud_sdk, integration_project_id): os.mkdir(os.path.join(path, 'lib')) # Install the checked-out endpoints repo subprocess.check_call(['python', '-m', 'pip', 'install', '-t', 'lib', PKGDIR, '--ignore-installed'], cwd=path) - print path + subprocess.check_call(['python', 'lib/endpoints/endpointscfg.py', 'get_openapi_spec', 'main.IataApi', '--hostname', '{}.appspot.com'.format(integration_project_id)], cwd=path) out, err, code = gcloud_sdk.RunGcloud(['endpoints', 'services', 'deploy', os.path.join(path, 'iatav1openapi.json')]) assert code == 0 @@ -226,3 +231,40 @@ def test_delete_airport_key_required(self, clean_apikey_app): actual = r.json() expected = {u'iata': u'YYZ', u'name': u'Lester B. Pearson International Airport'} assert actual == expected + + +@pytest.fixture(scope='class') +def base_path_app(gcloud_sdk, integration_project_id): + app = TestAppManager() + app.become_base_path_app(integration_project_id) + path = app.app_path + os.mkdir(os.path.join(path, 'lib')) + # Install the checked-out endpoints repo + subprocess.check_call(['python', '-m', 'pip', 'install', '-t', 'lib', PKGDIR, '--ignore-installed'], cwd=path) + + subprocess.check_call(['python', 'lib/endpoints/endpointscfg.py', 'get_openapi_spec', 'main.IataApi', '--hostname', '{}.appspot.com'.format(integration_project_id)], cwd=path) + out, err, code = gcloud_sdk.RunGcloud(['endpoints', 'services', 'deploy', os.path.join(path, 'iatav1openapi.json')]) + assert code == 0 + version = out['serviceConfig']['id'].encode('ascii') + app.update_app_yaml(integration_project_id, version) + + out, err, code = gcloud_sdk.RunGcloud(['app', 'deploy', os.path.join(path, 'app.yaml')]) + assert code == 0 + + base_url = 'https://{}.appspot.com/custom_base_path/iata/v1'.format(integration_project_id) + yield base_url + app.cleanup() + + +@pytest.mark.livetest +class TestBasePathDeployment(object): + # This test doesn't need the clean fixture to reset its state; + # we're not using the mutation methods in this test. + def test_get_airport(self, base_path_app): + url = '/'.join([base_path_app, 'airport', 'YYZ']) + assert 'custom_base_path' in url + assert '_ah/api' not in url + r = requests.get(url, headers=JSON_HEADERS) + actual = r.json() + expected = {u'iata': u'YYZ', u'name': u'Lester B. Pearson International Airport'} + assert actual == expected diff --git a/endpoints/test/testdata/base_path_sample_app/app.yaml b/endpoints/test/testdata/base_path_sample_app/app.yaml new file mode 100644 index 0000000..07352a3 --- /dev/null +++ b/endpoints/test/testdata/base_path_sample_app/app.yaml @@ -0,0 +1,32 @@ +runtime: python27 +threadsafe: false +api_version: 1 +basic_scaling: + max_instances: 2 + +#[START_EXCLUDE] +skip_files: +- ^(.*/)?#.*#$ +- ^(.*/)?.*~$ +- ^(.*/)?.*\.py[co]$ +- ^(.*/)?.*/RCS/.*$ +- ^(.*/)?\..*$ +- ^(.*/)?setuptools/script \(dev\).tmpl$ +#[END_EXCLUDE] + +handlers: +# The endpoints handler must be mapped to /_ah/api. +- url: /custom_base_path/.* + script: main.api + +libraries: +- name: pycrypto + version: 2.6 +- name: ssl + version: 2.7.11 + +env_variables: + # The following values are to be replaced by information from the output of + # 'gcloud service-management deploy swagger.json' command. + ENDPOINTS_SERVICE_NAME: project_id.appspot.com + ENDPOINTS_SERVICE_VERSION: version diff --git a/endpoints/test/testdata/base_path_sample_app/appengine_config.py b/endpoints/test/testdata/base_path_sample_app/appengine_config.py new file mode 100644 index 0000000..3bb4ea6 --- /dev/null +++ b/endpoints/test/testdata/base_path_sample_app/appengine_config.py @@ -0,0 +1,4 @@ +from google.appengine.ext import vendor + +# Add any libraries installed in the `lib` folder. +vendor.add('lib') diff --git a/endpoints/test/testdata/base_path_sample_app/data.py b/endpoints/test/testdata/base_path_sample_app/data.py new file mode 100644 index 0000000..d325bfd --- /dev/null +++ b/endpoints/test/testdata/base_path_sample_app/data.py @@ -0,0 +1,207 @@ +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +AIRPORTS = { + u'ABQ': u'Albuquerque International Sunport Airport', + u'ACA': u'General Juan N Alvarez International Airport', + u'ADW': u'Andrews Air Force Base', + u'AFW': u'Fort Worth Alliance Airport', + u'AGS': u'Augusta Regional At Bush Field', + u'AMA': u'Rick Husband Amarillo International Airport', + u'ANC': u'Ted Stevens Anchorage International Airport', + u'ATL': u'Hartsfield Jackson Atlanta International Airport', + u'AUS': u'Austin Bergstrom International Airport', + u'AVL': u'Asheville Regional Airport', + u'BAB': u'Beale Air Force Base', + u'BAD': u'Barksdale Air Force Base', + u'BDL': u'Bradley International Airport', + u'BFI': u'Boeing Field King County International Airport', + u'BGR': u'Bangor International Airport', + u'BHM': u'Birmingham-Shuttlesworth International Airport', + u'BIL': u'Billings Logan International Airport', + u'BLV': u'Scott AFB/Midamerica Airport', + u'BMI': u'Central Illinois Regional Airport at Bloomington-Normal', + u'BNA': u'Nashville International Airport', + u'BOI': u'Boise Air Terminal/Gowen field', + u'BOS': u'General Edward Lawrence Logan International Airport', + u'BTR': u'Baton Rouge Metropolitan, Ryan Field', + u'BUF': u'Buffalo Niagara International Airport', + u'BWI': u'Baltimore/Washington International Thurgood Marshall Airport', + u'CAE': u'Columbia Metropolitan Airport', + u'CBM': u'Columbus Air Force Base', + u'CHA': u'Lovell Field', + u'CHS': u'Charleston Air Force Base-International Airport', + u'CID': u'The Eastern Iowa Airport', + u'CLE': u'Cleveland Hopkins International Airport', + u'CLT': u'Charlotte Douglas International Airport', + u'CMH': u'Port Columbus International Airport', + u'COS': u'City of Colorado Springs Municipal Airport', + u'CPR': u'Casper-Natrona County International Airport', + u'CRP': u'Corpus Christi International Airport', + u'CRW': u'Yeager Airport', + u'CUN': u'Canc\xfan International Airport', + u'CVG': u'Cincinnati Northern Kentucky International Airport', + u'CVS': u'Cannon Air Force Base', + u'DAB': u'Daytona Beach International Airport', + u'DAL': u'Dallas Love Field', + u'DAY': u'James M Cox Dayton International Airport', + u'DBQ': u'Dubuque Regional Airport', + u'DCA': u'Ronald Reagan Washington National Airport', + u'DEN': u'Denver International Airport', + u'DFW': u'Dallas Fort Worth International Airport', + u'DLF': u'Laughlin Air Force Base', + u'DLH': u'Duluth International Airport', + u'DOV': u'Dover Air Force Base', + u'DSM': u'Des Moines International Airport', + u'DTW': u'Detroit Metropolitan Wayne County Airport', + u'DYS': u'Dyess Air Force Base', + u'EDW': u'Edwards Air Force Base', + u'END': u'Vance Air Force Base', + u'ERI': u'Erie International Tom Ridge Field', + u'EWR': u'Newark Liberty International Airport', + u'FAI': u'Fairbanks International Airport', + u'FFO': u'Wright-Patterson Air Force Base', + u'FLL': u'Fort Lauderdale Hollywood International Airport', + u'FSM': u'Fort Smith Regional Airport', + u'FTW': u'Fort Worth Meacham International Airport', + u'FWA': u'Fort Wayne International Airport', + u'GDL': u'Don Miguel Hidalgo Y Costilla International Airport', + u'GEG': u'Spokane International Airport', + u'GPT': u'Gulfport Biloxi International Airport', + u'GRB': u'Austin Straubel International Airport', + u'GSB': u'Seymour Johnson Air Force Base', + u'GSO': u'Piedmont Triad International Airport', + u'GSP': u'Greenville Spartanburg International Airport', + u'GUS': u'Grissom Air Reserve Base', + u'HIB': u'Range Regional Airport', + u'HMN': u'Holloman Air Force Base', + u'HMO': u'General Ignacio P. Garcia International Airport', + u'HNL': u'Honolulu International Airport', + u'HOU': u'William P Hobby Airport', + u'HSV': u'Huntsville International Carl T Jones Field', + u'HTS': u'Tri-State/Milton J. Ferguson Field', + u'IAD': u'Washington Dulles International Airport', + u'IAH': u'George Bush Intercontinental Houston Airport', + u'ICT': u'Wichita Mid Continent Airport', + u'IND': u'Indianapolis International Airport', + u'JAN': u'Jackson-Medgar Wiley Evers International Airport', + u'JAX': u'Jacksonville International Airport', + u'JFK': u'John F Kennedy International Airport', + u'JLN': u'Joplin Regional Airport', + u'LAS': u'McCarran International Airport', + u'LAX': u'Los Angeles International Airport', + u'LBB': u'Lubbock Preston Smith International Airport', + u'LCK': u'Rickenbacker International Airport', + u'LEX': u'Blue Grass Airport', + u'LFI': u'Langley Air Force Base', + u'LFT': u'Lafayette Regional Airport', + u'LGA': u'La Guardia Airport', + u'LIT': u'Bill & Hillary Clinton National Airport/Adams Field', + u'LTS': u'Altus Air Force Base', + u'LUF': u'Luke Air Force Base', + u'MBS': u'MBS International Airport', + u'MCF': u'Mac Dill Air Force Base', + u'MCI': u'Kansas City International Airport', + u'MCO': u'Orlando International Airport', + u'MDW': u'Chicago Midway International Airport', + u'MEM': u'Memphis International Airport', + u'MEX': u'Licenciado Benito Juarez International Airport', + u'MGE': u'Dobbins Air Reserve Base', + u'MGM': u'Montgomery Regional (Dannelly Field) Airport', + u'MHT': u'Manchester Airport', + u'MIA': u'Miami International Airport', + u'MKE': u'General Mitchell International Airport', + u'MLI': u'Quad City International Airport', + u'MLU': u'Monroe Regional Airport', + u'MOB': u'Mobile Regional Airport', + u'MSN': u'Dane County Regional Truax Field', + u'MSP': u'Minneapolis-St Paul International/Wold-Chamberlain Airport', + u'MSY': u'Louis Armstrong New Orleans International Airport', + u'MTY': u'General Mariano Escobedo International Airport', + u'MUO': u'Mountain Home Air Force Base', + u'OAK': u'Metropolitan Oakland International Airport', + u'OKC': u'Will Rogers World Airport', + u'ONT': u'Ontario International Airport', + u'ORD': u"Chicago O'Hare International Airport", + u'ORF': u'Norfolk International Airport', + u'PAM': u'Tyndall Air Force Base', + u'PBI': u'Palm Beach International Airport', + u'PDX': u'Portland International Airport', + u'PHF': u'Newport News Williamsburg International Airport', + u'PHL': u'Philadelphia International Airport', + u'PHX': u'Phoenix Sky Harbor International Airport', + u'PIA': u'General Wayne A. Downing Peoria International Airport', + u'PIT': u'Pittsburgh International Airport', + u'PPE': u'Mar de Cort\xe9s International Airport', + u'PVR': u'Licenciado Gustavo D\xedaz Ordaz International Airport', + u'PWM': u'Portland International Jetport Airport', + u'RDU': u'Raleigh Durham International Airport', + u'RFD': u'Chicago Rockford International Airport', + u'RIC': u'Richmond International Airport', + u'RND': u'Randolph Air Force Base', + u'RNO': u'Reno Tahoe International Airport', + u'ROA': u'Roanoke\u2013Blacksburg Regional Airport', + u'ROC': u'Greater Rochester International Airport', + u'RST': u'Rochester International Airport', + u'RSW': u'Southwest Florida International Airport', + u'SAN': u'San Diego International Airport', + u'SAT': u'San Antonio International Airport', + u'SAV': u'Savannah Hilton Head International Airport', + u'SBN': u'South Bend Regional Airport', + u'SDF': u'Louisville International Standiford Field', + u'SEA': u'Seattle Tacoma International Airport', + u'SFB': u'Orlando Sanford International Airport', + u'SFO': u'San Francisco International Airport', + u'SGF': u'Springfield Branson National Airport', + u'SHV': u'Shreveport Regional Airport', + u'SJC': u'Norman Y. Mineta San Jose International Airport', + u'SJD': u'Los Cabos International Airport', + u'SKA': u'Fairchild Air Force Base', + u'SLC': u'Salt Lake City International Airport', + u'SMF': u'Sacramento International Airport', + u'SNA': u'John Wayne Airport-Orange County Airport', + u'SPI': u'Abraham Lincoln Capital Airport', + u'SPS': u'Sheppard Air Force Base-Wichita Falls Municipal Airport', + u'SRQ': u'Sarasota Bradenton International Airport', + u'SSC': u'Shaw Air Force Base', + u'STL': u'Lambert St Louis International Airport', + u'SUS': u'Spirit of St Louis Airport', + u'SUU': u'Travis Air Force Base', + u'SUX': u'Sioux Gateway Col. Bud Day Field', + u'SYR': u'Syracuse Hancock International Airport', + u'SZL': u'Whiteman Air Force Base', + u'TCM': u'McChord Air Force Base', + u'TIJ': u'General Abelardo L. Rodr\xedguez International Airport', + u'TIK': u'Tinker Air Force Base', + u'TLH': u'Tallahassee Regional Airport', + u'TOL': u'Toledo Express Airport', + u'TPA': u'Tampa International Airport', + u'TRI': u'Tri Cities Regional Tn Va Airport', + u'TUL': u'Tulsa International Airport', + u'TUS': u'Tucson International Airport', + u'TYS': u'McGhee Tyson Airport', + u'VBG': u'Vandenberg Air Force Base', + u'VPS': u'Destin-Ft Walton Beach Airport', + u'WRB': u'Robins Air Force Base', + u'YEG': u'Edmonton International Airport', + u'YHZ': u'Halifax / Stanfield International Airport', + u'YOW': u'Ottawa Macdonald-Cartier International Airport', + u'YUL': u'Montreal / Pierre Elliott Trudeau International Airport', + u'YVR': u'Vancouver International Airport', + u'YWG': u'Winnipeg / James Armstrong Richardson International Airport', + u'YYC': u'Calgary International Airport', + u'YYJ': u'Victoria International Airport', + u'YYT': u"St. John's International Airport", + u'YYZ': u'Lester B. Pearson International Airport' +} diff --git a/endpoints/test/testdata/base_path_sample_app/main.py b/endpoints/test/testdata/base_path_sample_app/main.py new file mode 100644 index 0000000..1653603 --- /dev/null +++ b/endpoints/test/testdata/base_path_sample_app/main.py @@ -0,0 +1,133 @@ +# Copyright 2017 Google Inc. All rights reserved. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. + +"""This is a sample Hello World API implemented using Google Cloud +Endpoints.""" + +# [START imports] +import endpoints +from protorpc import message_types +from protorpc import messages +from protorpc import remote + +import copy + +from data import AIRPORTS as SOURCE_AIRPORTS +# [END imports] + +AIRPORTS = copy.deepcopy(SOURCE_AIRPORTS) + +# [START messages] +IATA_RESOURCE = endpoints.ResourceContainer( + iata=messages.StringField(1, required=True) +) + +class Airport(messages.Message): + iata = messages.StringField(1, required=True) + name = messages.StringField(2, required=True) + +IATA_AIRPORT_RESOURCE = endpoints.ResourceContainer( + Airport, + iata=messages.StringField(1, required=True) +) + +class AirportList(messages.Message): + airports = messages.MessageField(Airport, 1, repeated=True) +# [END messages] + + +# [START echo_api] +@endpoints.api(name='iata', version='v1', base_path='/custom_base_path/') +class IataApi(remote.Service): + @endpoints.method( + IATA_RESOURCE, + Airport, + path='airport/{iata}', + http_method='GET', + name='get_airport') + def get_airport(self, request): + if request.iata not in AIRPORTS: + raise endpoints.NotFoundException() + return Airport(iata=request.iata, name=AIRPORTS[request.iata]) + + @endpoints.method( + message_types.VoidMessage, + AirportList, + path='airports', + http_method='GET', + name='list_airports') + def list_airports(self, request): + codes = AIRPORTS.keys() + codes.sort() + return AirportList(airports=[ + Airport(iata=iata, name=AIRPORTS[iata]) for iata in codes + ]) + + @endpoints.method( + IATA_RESOURCE, + message_types.VoidMessage, + path='airport/{iata}', + http_method='DELETE', + name='delete_airport', + api_key_required=True) + def delete_airport(self, request): + if request.iata not in AIRPORTS: + raise endpoints.NotFoundException() + del AIRPORTS[request.iata] + return message_types.VoidMessage() + + @endpoints.method( + Airport, + Airport, + path='airport', + http_method='POST', + name='create_airport', + api_key_required=True) + def create_airport(self, request): + if request.iata in AIRPORTS: + raise endpoints.BadRequestException() + AIRPORTS[request.iata] = request.name + return Airport(iata=request.iata, name=AIRPORTS[request.iata]) + + @endpoints.method( + IATA_AIRPORT_RESOURCE, + Airport, + path='airport/{iata}', + http_method='POST', + name='update_airport', + api_key_required=True) + def update_airport(self, request): + if request.iata not in AIRPORTS: + raise endpoints.BadRequestException() + AIRPORTS[request.iata] = request.name + return Airport(iata=request.iata, name=AIRPORTS[request.iata]) + + @endpoints.method( + message_types.VoidMessage, + message_types.VoidMessage, + path='reset', + http_method='POST', + name='reset_data', + api_key_required=True) + def reset_data(self, request): + global AIRPORTS + AIRPORTS = copy.deepcopy(SOURCE_AIRPORTS) + return message_types.VoidMessage() + +# [END echo_api] + + +# [START api_server] +api = endpoints.api_server([IataApi]) +# [END api_server]