sabre_dev_studio-flight 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (38) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +18 -0
  3. data/Gemfile +5 -0
  4. data/LICENSE.txt +22 -0
  5. data/README.md +54 -0
  6. data/Rakefile +20 -0
  7. data/lib/sabre_dev_studio-flight/airports_at_cities_lookup.rb +13 -0
  8. data/lib/sabre_dev_studio-flight/api.rb +209 -0
  9. data/lib/sabre_dev_studio-flight/city_pairs_lookup.rb +13 -0
  10. data/lib/sabre_dev_studio-flight/destination_finder.rb +13 -0
  11. data/lib/sabre_dev_studio-flight/fare_range.rb +13 -0
  12. data/lib/sabre_dev_studio-flight/instaflights_search.rb +13 -0
  13. data/lib/sabre_dev_studio-flight/lead_price_calendar.rb +13 -0
  14. data/lib/sabre_dev_studio-flight/low_fare_forecast.rb +13 -0
  15. data/lib/sabre_dev_studio-flight/multiairport_city_lookup.rb +13 -0
  16. data/lib/sabre_dev_studio-flight/shop/streamlined_destinations.rb +38 -0
  17. data/lib/sabre_dev_studio-flight/shop/streamlined_itineraries.rb +225 -0
  18. data/lib/sabre_dev_studio-flight/theme_airport_lookup.rb +13 -0
  19. data/lib/sabre_dev_studio-flight/travel_seasonality.rb +13 -0
  20. data/lib/sabre_dev_studio-flight/travel_theme_lookup.rb +13 -0
  21. data/lib/sabre_dev_studio-flight/version.rb +5 -0
  22. data/lib/sabre_dev_studio-flight.rb +6 -0
  23. data/sabre_dev_studio-flight.gemspec +24 -0
  24. data/test/api_test.rb +194 -0
  25. data/test/fixtures/air_shopping_themes.json +113 -0
  26. data/test/fixtures/airports_at_cities_lookup.json +26 -0
  27. data/test/fixtures/city_pairs.json +16708 -0
  28. data/test/fixtures/destination_air_shop.json +481 -0
  29. data/test/fixtures/fare_range.json +35 -0
  30. data/test/fixtures/future_dates_lead_fare_shop.json +2525 -0
  31. data/test/fixtures/low_fare_forecast.json +28 -0
  32. data/test/fixtures/multiairport_city_lookup.json +164 -0
  33. data/test/fixtures/single_date_air_shop.json +352 -0
  34. data/test/fixtures/theme_airport_lookup.json +77 -0
  35. data/test/fixtures/theme_airports.json +32 -0
  36. data/test/fixtures/travel_seasonality.json +379 -0
  37. data/test/test_helper.rb +32 -0
  38. metadata +149 -0
@@ -0,0 +1,225 @@
1
+ =begin
2
+
3
+ options = {
4
+ :origin => 'ATL',
5
+ :destination => 'LAS',
6
+ :departuredate => '2014-06-01',
7
+ :returndate => '2014-06-05',
8
+ :limit => 300
9
+ }
10
+ itineraries = SabreDevStudio::Flight::Api.single_date_air_shop(options); nil
11
+ streamlined_itineraries = SabreDevStudio::Flight::Shop::StreamlinedItineraries.new(itineraries.response['PricedItineraries']); nil
12
+
13
+ -- or --
14
+
15
+ require 'json'
16
+ itineraries = JSON.parse(File.read('./test/fixtures/single_date_air_shop.json')); nil
17
+ streamlined_itineraries = SabreDevStudio::Flight::Shop::StreamlinedItineraries.new(itineraries['PricedItineraries']); nil
18
+ pp streamlined_itineraries; nil
19
+
20
+ =end
21
+
22
+ # require 'digest'
23
+ module SabreDevStudio
24
+ module Flight
25
+ module Shop
26
+ class StreamlinedItineraries
27
+ attr_reader :flights, :outbounds, :min_price, :max_price,
28
+ :min_outbound_duration, :max_outbound_duration, :airline_codes
29
+
30
+ def initialize(itineraries)
31
+ @flights = []
32
+ @outbounds = []
33
+ @min_price = @max_price = nil
34
+ @min_outbound_duration = @max_outbound_duration = nil
35
+ outbound_flights = Hash.new
36
+ outbound_flight = nil
37
+
38
+ itineraries.each do |itin|
39
+ segments = itin['AirItinerary']['OriginDestinationOptions']['OriginDestinationOption']
40
+ amount = itin['AirItineraryPricingInfo']['ItinTotalFare']['TotalFare']['Amount'].to_f
41
+ segments.each_with_index.each do |segment, idx|
42
+ direction = idx % 2 == 0 ? 'outbound' : 'inbound'
43
+ flight = Flight.new(segment['FlightSegment'], direction, segment['ElapsedTime'])
44
+ @flights << flight.to_hash
45
+
46
+ set_price(amount)
47
+ if flight.direction == 'outbound'
48
+ set_duration(flight.duration)
49
+ outbound_flight = flight
50
+ outbound_flights[outbound_flight.sha] ||= OutboundFlight.new(flight, amount)
51
+ else
52
+ outbound_flights[outbound_flight.sha].add_inbound_flight(flight, amount)
53
+ end
54
+
55
+ if segment['FlightSegment'].is_a?(Array)
56
+ segment['FlightSegment'].each_with_index do |flight_segment, idx|
57
+ # next if idx > 0
58
+ connection = Flight.new(flight_segment, 'connecting', segment['ElapsedTime'])
59
+ next if connection.sha == flight.sha
60
+ @flights << connection.to_hash
61
+ flight.add_connecting_flight(connection)
62
+ end
63
+ end
64
+ end
65
+ end
66
+
67
+ @airline_codes = @flights.map { |f| f[:airlines] }.flatten.uniq.sort
68
+ @flights.uniq!
69
+ @outbounds = outbound_flights.values.map(&:to_hash)
70
+ end
71
+
72
+ def set_price(fare)
73
+ @min_price = fare if @min_price.nil? || fare < @min_price
74
+ @max_price = fare if @max_price.nil? || fare > @max_price
75
+ end
76
+ def set_duration(duration)
77
+ @min_outbound_duration = duration if @min_outbound_duration.nil? || duration < @min_outbound_duration
78
+ @max_outbound_duration = duration if @max_outbound_duration.nil? || duration > @max_outbound_duration
79
+ end
80
+ end
81
+
82
+ class Flight
83
+ attr_reader :direction, :airlines, :duration, :flight_number,
84
+ :departure_airport, :arrival_airport,
85
+ :stops, :departure_time, :arrival_time, :connections
86
+
87
+ def initialize(flight_segment, direction, duration)
88
+ @airlines = []
89
+ @stops = []
90
+ @connections = []
91
+ @direction = direction
92
+ if direction == 'connecting'
93
+ @duration = flight_segment['ElapsedTime']
94
+ else
95
+ @duration = duration
96
+ end
97
+ parse_data(flight_segment)
98
+ end
99
+
100
+ def sha
101
+ str = "#{@airlines.first}_#{@flight_number}_#{@departure_airport}_#{@departure_time}"
102
+ # Digest::SHA1.hexdigest(str)
103
+ str
104
+ end
105
+
106
+ def to_hash
107
+ {
108
+ uid: sha,
109
+ direction: @direction,
110
+ airlines: airlines.uniq,
111
+ duration: minutes_to_time(duration),
112
+ departureAirport: departure_airport,
113
+ arrivalAirport: arrival_airport,
114
+ stops: stops,
115
+ connections: connections,
116
+ departureTime: reformat_date_time(departure_time),
117
+ arrivalTime: reformat_date_time(arrival_time)
118
+ }
119
+ end
120
+
121
+ def add_connecting_flight(flight)
122
+ @connections << flight.sha
123
+ end
124
+
125
+ private
126
+
127
+ def parse_data(flight_segment)
128
+ if flight_segment.is_a?(Array)
129
+ flight_segment.each_with_index do |segment, idx|
130
+ if idx == 0
131
+ @departure_airport = segment['DepartureAirport']['LocationCode']
132
+ @departure_time = segment['DepartureDateTime']
133
+ @stops << segment['ArrivalAirport']['LocationCode']
134
+ @airlines << segment['MarketingAirline']['Code']
135
+ @flight_number = segment['FlightNumber']
136
+ elsif idx == flight_segment.length - 1
137
+ @arrival_airport = segment['ArrivalAirport']['LocationCode']
138
+ @arrival_time = segment['ArrivalDateTime']
139
+ @airlines << segment['MarketingAirline']['Code']
140
+ else
141
+ @stops << segment['ArrivalAirport']['LocationCode']
142
+ @airlines << segment['MarketingAirline']['Code']
143
+ end
144
+ end
145
+ else
146
+ @departure_airport = flight_segment['DepartureAirport']['LocationCode']
147
+ @arrival_airport = flight_segment['ArrivalAirport']['LocationCode']
148
+ @departure_time = flight_segment['DepartureDateTime']
149
+ @arrival_time = flight_segment['ArrivalDateTime']
150
+ @airlines << flight_segment['MarketingAirline']['Code']
151
+ @flight_number = flight_segment['FlightNumber']
152
+ end
153
+ end
154
+
155
+ def minutes_to_time(minutes)
156
+ minutes = minutes.to_i
157
+ {
158
+ hour: minutes / 60,
159
+ minutes: minutes % 60,
160
+ raw: minutes
161
+ }
162
+ end
163
+
164
+ # "2013-06-01T09:56:00" --> "9:56 am"
165
+ # "2013-06-01T19:06:00" --> "7:06 pm"
166
+ def reformat_date_time(datetime)
167
+ datetime =~ /\d+-\d+-\d+T(\d+):(\d+):\d+/
168
+ hour, minute = $1.to_i, $2.to_i
169
+ am_pm = hour < 12 ? 'am' : 'pm'
170
+
171
+ hour = hour % 12
172
+ hour = hour == 0 ? 12 : hour
173
+ minute = sprintf("%02d", minute)
174
+ "#{hour}:#{minute} #{am_pm}"
175
+ end
176
+ end
177
+
178
+ class OutboundFlight
179
+ attr_reader :flight_uuid, :inbounds, :min_price, :max_price,
180
+ :duration, :min_inbound_duration, :max_inbound_duration
181
+
182
+ def initialize(flight, price)
183
+ @flight_uuid = flight.sha
184
+ @min_price = @max_price = price
185
+ @inbounds = []
186
+ @duration = flight.duration
187
+ @min_inbound_duration = @max_inbound_duration = nil
188
+ end
189
+
190
+ def add_inbound_flight(flight, price)
191
+ set_min_price(price)
192
+ set_inbound_duration(flight.duration)
193
+ @inbounds << {
194
+ flight_uuid: flight.sha,
195
+ price: price
196
+ }
197
+ end
198
+
199
+ def to_hash
200
+ {
201
+ flight_uuid: flight_uuid,
202
+ min_price: min_price,
203
+ max_price: max_price,
204
+ duration: duration,
205
+ min_inbound_duration: min_inbound_duration,
206
+ max_inbound_duration: max_inbound_duration,
207
+ inbounds: inbounds.uniq
208
+ }
209
+ end
210
+
211
+ private
212
+
213
+ def set_min_price(price)
214
+ @min_price = price if price < @min_price
215
+ @max_price = price if price > @max_price
216
+ end
217
+
218
+ def set_inbound_duration(duration)
219
+ @min_inbound_duration = duration if @min_inbound_duration.nil? || duration < @min_inbound_duration
220
+ @max_inbound_duration = duration if @max_inbound_duration.nil? || duration > @max_inbound_duration
221
+ end
222
+ end
223
+ end
224
+ end
225
+ end
@@ -0,0 +1,13 @@
1
+ module SabreDevStudio
2
+ module Flight
3
+
4
+ ##
5
+ # Air Shopping Themes Convenience Object
6
+ #
7
+ # ==== Documentation:
8
+ # https://developer.sabre.com/docs/read/rest_apis/theme_airport_lookup
9
+ class ThemeAirportLookup < SabreDevStudio::RequestObject
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module SabreDevStudio
2
+ module Flight
3
+
4
+ ##
5
+ # Travel Seasonality
6
+ #
7
+ # ==== Documentation:
8
+ # https://developer.sabre.com/docs/read/rest_apis/travel_seasonality
9
+ class TravelSeasonality < SabreDevStudio::RequestObject
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,13 @@
1
+ module SabreDevStudio
2
+ module Flight
3
+
4
+ ##
5
+ # Air Shopping Themes Convenience Object
6
+ #
7
+ # ==== Documentation:
8
+ # https://developer.sabre.com/docs/read/rest_apis/travel_theme_lookup
9
+ class TravelThemeLookup < SabreDevStudio::RequestObject
10
+ end
11
+
12
+ end
13
+ end
@@ -0,0 +1,5 @@
1
+ module SabreDevStudio
2
+ module Flight
3
+ VERSION = '1.0.0'
4
+ end
5
+ end
@@ -0,0 +1,6 @@
1
+ require 'sabre_dev_studio'
2
+ require File.expand_path("../sabre_dev_studio-flight/api", __FILE__)
3
+ require File.expand_path("../sabre_dev_studio-flight/version", __FILE__)
4
+
5
+ require File.expand_path("../sabre_dev_studio-flight/shop/streamlined_destinations", __FILE__)
6
+ require File.expand_path("../sabre_dev_studio-flight/shop/streamlined_itineraries", __FILE__)
@@ -0,0 +1,24 @@
1
+ # -*- encoding: utf-8 -*-
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'sabre_dev_studio-flight/version'
5
+
6
+ Gem::Specification.new do |gem|
7
+ gem.name = "sabre_dev_studio-flight"
8
+ gem.version = SabreDevStudio::Flight::VERSION
9
+ gem.authors = ["Barrett Clark"]
10
+ gem.email = ["barrett.clark@sabre.com"]
11
+ gem.description = %q{Access the Sabre Travel Platform Services (TPS) Dev Studio Flight API}
12
+ gem.summary = %q{Access the Sabre Dev Studio API}
13
+ gem.homepage = "http://developer.sabre.com"
14
+
15
+ gem.files = `git ls-files`.split($/)
16
+ gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) }
17
+ gem.test_files = gem.files.grep(%r{^(test|spec|features)/})
18
+ gem.require_paths = ["lib"]
19
+
20
+ gem.add_development_dependency 'geminabox'
21
+ gem.add_development_dependency 'webmock'
22
+ gem.add_development_dependency 'rdoc'
23
+ gem.add_runtime_dependency 'sabre_dev_studio'
24
+ end
data/test/api_test.rb ADDED
@@ -0,0 +1,194 @@
1
+ require File.expand_path("../test_helper", __FILE__)
2
+
3
+ class ApiTests < Test::Unit::TestCase
4
+ def setup
5
+ SabreDevStudio.configure do |c|
6
+ c.user = 'USER'
7
+ c.group = 'GROUP'
8
+ c.domain = 'DOMAIN'
9
+ c.password = 'PASSWORD'
10
+ c.uri = 'https://api.test.sabre.com'
11
+ end
12
+ stub_request(:post, "https://VjE6VVNFUjpHUk9VUDpET01BSU4%3D:UEFTU1dPUkQ%3D@api.test.sabre.com/v1/auth/token").
13
+ to_return(:status => 200, :body =>"{\"access_token\":\"Shared/IDL:IceSess\\\\/SessMgr:1\\\\.0.IDL/Common/!ICESMS\\\\/ACPCRTD!ICESMSLB\\\\/CRT.LB!-3801964284027024638!507667!0!F557CBE649675!E2E-1\",\"token_type\":\"bearer\",\"expires_in\":1800}")
14
+ end
15
+
16
+ def test_air_shopping_theme_api
17
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/themes").
18
+ to_return(json_response('air_shopping_themes.json'))
19
+ air_shopping_themes = SabreDevStudio::Flight::Api.air_shopping_themes
20
+ assert_equal 11, air_shopping_themes.response['Themes'].count
21
+ assert_equal 'BEACH', air_shopping_themes.response['Themes'].first['Theme']
22
+ assert_equal 'BEACH', air_shopping_themes.themes.first.theme
23
+ end
24
+
25
+ def test_theme_airport_lookup_api
26
+ theme = 'DISNEY'
27
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/themes/#{theme}").
28
+ to_return(json_response('theme_airport_lookup.json'))
29
+ airports = SabreDevStudio::Flight::Api.theme_airport_lookup(theme)
30
+ assert_equal 7, airports.destinations.count
31
+ assert_equal 'BUR', airports.destinations.first.destination
32
+ end
33
+
34
+ def test_destination_air_shop_api
35
+ options = {
36
+ :origin => 'LAS',
37
+ :lengthofstay => 1,
38
+ :theme => 'MOUNTAINS'
39
+ }
40
+ uri = Addressable::URI.new
41
+ uri.query_values = options
42
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights/fares?#{uri.query}").
43
+ to_return(json_response('destination_air_shop.json'))
44
+ fares = SabreDevStudio::Flight::Api.destination_air_shop(options)
45
+ assert_equal options[:origin], fares.origin_location
46
+ assert_equal 31, fares.fare_info.count
47
+ assert_equal 158, fares.fare_info.first.lowest_fare
48
+ date = SabreDevStudio::Helpers::DateExtensions.make_date(fares.fare_info.first.departure_date_time)
49
+ assert_equal 4, date.month
50
+ assert_equal options[:origin], fares.response['OriginLocation']
51
+ assert_equal 158, fares.response['FareInfo'].first['LowestFare']
52
+ end
53
+
54
+ def test_future_dates_lead_fare_shop_api
55
+ options = {
56
+ :origin => 'JFK',
57
+ :destination => 'LAX',
58
+ :lengthofstay => 5
59
+ }
60
+ uri = Addressable::URI.new
61
+ uri.query_values = options
62
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights/fares?#{uri.query}").
63
+ to_return(json_response('future_dates_lead_fare_shop.json'))
64
+ fares = SabreDevStudio::Flight::Api.future_dates_lead_fare_shop(options)
65
+ assert_equal options[:origin], fares.origin_location
66
+ assert_equal 193, fares.fare_info.count
67
+ assert_equal 792, fares.fare_info.first.lowest_fare
68
+ assert_equal options[:origin], fares.response['OriginLocation']
69
+ assert_equal 792, fares.response['FareInfo'].first['LowestFare']
70
+ end
71
+
72
+ def test_single_date_air_shop_api
73
+ options = {
74
+ :origin => 'JFK',
75
+ :destination => 'LAX',
76
+ :departuredate => '2014-10-01',
77
+ :returndate => '2014-10-05',
78
+ :onlineitinerariesonly => 'N',
79
+ :limit => 1,
80
+ :offset => 1,
81
+ :sortby => 'totalfare',
82
+ :order => 'asc',
83
+ :sortby2 => 'departuretime',
84
+ :order2 => 'dsc'
85
+ }
86
+ uri = Addressable::URI.new
87
+ uri.query_values = options
88
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/shop/flights?#{uri.query}").
89
+ to_return(json_response('single_date_air_shop.json'))
90
+ fares = SabreDevStudio::Flight::Api.single_date_air_shop(options)
91
+ assert_equal options[:origin], fares.origin_location
92
+ assert_equal 387.0, fares.priced_itineraries.first.air_itinerary_pricing_info.itin_total_fare.total_fare.amount
93
+ assert_equal options[:origin], fares.response['OriginLocation']
94
+ assert_equal 387, fares.response['PricedItineraries'].first['AirItineraryPricingInfo']['ItinTotalFare']['TotalFare']['Amount']
95
+ end
96
+
97
+ def test_low_fare_forecast_api
98
+ options = {
99
+ :origin => 'JFK',
100
+ :destination => 'LAX',
101
+ :departuredate => '2014-10-01',
102
+ :returndate => '2014-10-05'
103
+ }
104
+ uri = Addressable::URI.new
105
+ uri.query_values = options
106
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/forecast/flights/fares?#{uri.query}").
107
+ to_return(json_response('low_fare_forecast.json'))
108
+ forecast = SabreDevStudio::Flight::Api.low_fare_forecast(options)
109
+ assert_equal options[:origin], forecast.origin_location
110
+ assert_equal options[:origin], forecast.response['OriginLocation']
111
+ assert_equal options[:destination], forecast.response['DestinationLocation']
112
+ assert_equal 387.0, forecast.response['LowestFare']
113
+ end
114
+
115
+ def test_fare_range_api
116
+ options = {
117
+ :origin => 'JFK',
118
+ :destination => 'LAX',
119
+ :earliestdeparturedate => '2014-06-01',
120
+ :latestdeparturedate => '2014-06-01',
121
+ :lengthofstay => 4
122
+ }
123
+ uri = Addressable::URI.new
124
+ uri.query_values = options
125
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/historical/flights/fares?#{uri.query}").
126
+ to_return(json_response('fare_range.json'))
127
+ fare_range = SabreDevStudio::Flight::Api.fare_range(options)
128
+ assert_equal options[:origin], fare_range.origin_location
129
+ assert_equal options[:destination], fare_range.destination_location
130
+ assert_equal 1, fare_range.fare_data.count
131
+ assert_equal options[:origin], fare_range.response['OriginLocation']
132
+ assert_equal options[:destination], fare_range.response['DestinationLocation']
133
+ assert_equal 1, fare_range.response['FareData'].count
134
+ end
135
+
136
+ def test_travel_seasonality_api
137
+ destination = 'DFW'
138
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/historical/flights/#{destination}/seasonality").
139
+ to_return(json_response('travel_seasonality.json'))
140
+ travel_seasonality = SabreDevStudio::Flight::Api.travel_seasonality(destination)
141
+ assert_equal destination, travel_seasonality.destination_location
142
+ assert_equal 52, travel_seasonality.seasonality.count
143
+ assert_equal 1, travel_seasonality.seasonality.first.year_week_number
144
+ assert_equal destination, travel_seasonality.response['DestinationLocation']
145
+ assert_equal 52, travel_seasonality.response['Seasonality'].count
146
+ assert_equal 1, travel_seasonality.response['Seasonality'].first['YearWeekNumber']
147
+ assert_equal 'Low', travel_seasonality.response['Seasonality'].first['SeasonalityIndicator']
148
+ end
149
+
150
+ def test_city_pairs_lookup_api
151
+ options = {
152
+ :origincountry => 'US',
153
+ :destinationcountry => 'US'
154
+ }
155
+ uri = Addressable::URI.new
156
+ uri.query_values = options
157
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/airports/supported/origins-destinations?#{uri.query}").
158
+ to_return(json_response('city_pairs.json'))
159
+ city_pairs = SabreDevStudio::Flight::Api.city_pairs_lookup(options)
160
+ assert_equal 982, city_pairs.origin_destination_locations.count
161
+ assert_equal 'DEN', city_pairs.origin_destination_locations.first.origin_location.airport_code
162
+ assert_equal 'ABQ', city_pairs.origin_destination_locations.first.destination_location.airport_code
163
+ assert_equal 982, city_pairs.response['OriginDestinationLocations'].count
164
+ assert_equal 'DEN', city_pairs.response['OriginDestinationLocations'].first['OriginLocation']['AirportCode']
165
+ assert_equal 'ABQ', city_pairs.response['OriginDestinationLocations'].first['DestinationLocation']['AirportCode']
166
+ end
167
+
168
+ def test_multiairport_city_lookup_api
169
+ options = { :country => 'US' }
170
+ uri = Addressable::URI.new
171
+ uri.query_values = options
172
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/cities?#{uri.query}").
173
+ to_return(json_response('multiairport_city_lookup.json'))
174
+ city_lookup = SabreDevStudio::Flight::Api.multiairport_city_lookup(options)
175
+ assert_equal 15, city_lookup.cities.count
176
+ assert_equal 'WAS', city_lookup.cities.last.code
177
+ assert_equal 15, city_lookup.response['Cities'].count
178
+ assert_equal 'WAS', city_lookup.response['Cities'].last['code']
179
+ end
180
+
181
+ def test_airports_at_cities_lookup_api
182
+ options = { :city => 'QDF' }
183
+ uri = Addressable::URI.new
184
+ uri.query_values = options
185
+ stub_request(:get, "#{SabreDevStudio.configuration.uri}/v1/lists/airports?#{uri.query}").
186
+ to_return(json_response('airports_at_cities_lookup.json'))
187
+ airports = SabreDevStudio::Flight::Api.airports_at_cities_lookup(options)
188
+ assert_equal 3, airports.airports.count
189
+ assert_equal 'EWR', airports.airports.first.code
190
+ assert_equal 'NEWARK', airports.airports.first.name
191
+ assert_equal 3, airports.response['Airports'].count
192
+ assert_equal 'EWR', airports.response['Airports'].first['code']
193
+ end
194
+ end
@@ -0,0 +1,113 @@
1
+ {
2
+ "Themes": [
3
+ {
4
+ "Theme": "BEACH",
5
+ "Links": [
6
+ {
7
+ "rel": "destinations",
8
+ "href": "https://api.test.sabre.com/v1/shop/themes/BEACH"
9
+ }
10
+ ]
11
+ },
12
+ {
13
+ "Theme": "DISNEY",
14
+ "Links": [
15
+ {
16
+ "rel": "destinations",
17
+ "href": "https://api.test.sabre.com/v1/shop/themes/DISNEY"
18
+ }
19
+ ]
20
+ },
21
+ {
22
+ "Theme": "GAMBLING",
23
+ "Links": [
24
+ {
25
+ "rel": "destinations",
26
+ "href": "https://api.test.sabre.com/v1/shop/themes/GAMBLING"
27
+ }
28
+ ]
29
+ },
30
+ {
31
+ "Theme": "HISTORIC",
32
+ "Links": [
33
+ {
34
+ "rel": "destinations",
35
+ "href": "https://api.test.sabre.com/v1/shop/themes/HISTORIC"
36
+ }
37
+ ]
38
+ },
39
+ {
40
+ "Theme": "MOUNTAINS",
41
+ "Links": [
42
+ {
43
+ "rel": "destinations",
44
+ "href": "https://api.test.sabre.com/v1/shop/themes/MOUNTAINS"
45
+ }
46
+ ]
47
+ },
48
+ {
49
+ "Theme": "NATIONAL-PARKS",
50
+ "Links": [
51
+ {
52
+ "rel": "destinations",
53
+ "href": "https://api.test.sabre.com/v1/shop/themes/NATIONAL-PARKS"
54
+ }
55
+ ]
56
+ },
57
+ {
58
+ "Theme": "OUTDOORS",
59
+ "Links": [
60
+ {
61
+ "rel": "destinations",
62
+ "href": "https://api.test.sabre.com/v1/shop/themes/OUTDOORS"
63
+ }
64
+ ]
65
+ },
66
+ {
67
+ "Theme": "ROMANTIC",
68
+ "Links": [
69
+ {
70
+ "rel": "destinations",
71
+ "href": "https://api.test.sabre.com/v1/shop/themes/ROMANTIC"
72
+ }
73
+ ]
74
+ },
75
+ {
76
+ "Theme": "SHOPPING",
77
+ "Links": [
78
+ {
79
+ "rel": "destinations",
80
+ "href": "https://api.test.sabre.com/v1/shop/themes/SHOPPING"
81
+ }
82
+ ]
83
+ },
84
+ {
85
+ "Theme": "SKIING",
86
+ "Links": [
87
+ {
88
+ "rel": "destinations",
89
+ "href": "https://api.test.sabre.com/v1/shop/themes/SKIING"
90
+ }
91
+ ]
92
+ },
93
+ {
94
+ "Theme": "THEME-PARK",
95
+ "Links": [
96
+ {
97
+ "rel": "destinations",
98
+ "href": "https://api.test.sabre.com/v1/shop/themes/THEME-PARK"
99
+ }
100
+ ]
101
+ }
102
+ ],
103
+ "Links": [
104
+ {
105
+ "rel": "self",
106
+ "href": "https://api.test.sabre.com/v1/shop/themes"
107
+ },
108
+ {
109
+ "rel": "linkTemplate",
110
+ "href": "https://api.test.sabre.com/v1/shop/themes"
111
+ }
112
+ ]
113
+ }
@@ -0,0 +1,26 @@
1
+ {
2
+ "Airports": [
3
+ {
4
+ "code": "EWR",
5
+ "name": "NEWARK"
6
+ },
7
+ {
8
+ "code": "JFK",
9
+ "name": "NEW YORK JFK"
10
+ },
11
+ {
12
+ "code": "LGA",
13
+ "name": "NEW YORK LGA"
14
+ }
15
+ ],
16
+ "Links": [
17
+ {
18
+ "rel": "self",
19
+ "href": "https://api.test.sabre.com/v1/lists/airports?country=US&city=NYC"
20
+ },
21
+ {
22
+ "rel": "linkTemplate",
23
+ "href": "https://api.test.sabre.com/v1/lists/airports?city=<city>"
24
+ }
25
+ ]
26
+ }