diff options
-rw-r--r-- | partners_api/partners_api_tests/uber_tests.cpp | 87 | ||||
-rw-r--r-- | partners_api/uber_api.cpp | 56 | ||||
-rw-r--r-- | partners_api/uber_api.hpp | 48 |
3 files changed, 133 insertions, 58 deletions
diff --git a/partners_api/partners_api_tests/uber_tests.cpp b/partners_api/partners_api_tests/uber_tests.cpp index ab442545b8..81ba0c5329 100644 --- a/partners_api/partners_api_tests/uber_tests.cpp +++ b/partners_api/partners_api_tests/uber_tests.cpp @@ -22,15 +22,20 @@ bool IsComplete(uber::Product const & product) UNIT_TEST(Uber_GetProducts) { ms::LatLon const pos(38.897724, -77.036531); - - TEST(!uber::RawApi::GetProducts(pos).empty(), ()); + string result; + TEST(uber::RawApi::GetProducts(pos, result), ()); + TEST(!result.empty(), ()); } UNIT_TEST(Uber_GetTimes) { ms::LatLon const pos(38.897724, -77.036531); + string result; + + TEST(uber::RawApi::GetEstimatedTime(pos, result), ()); + TEST(!result.empty(), ()); - my::Json timeRoot(uber::RawApi::GetEstimatedTime(pos).c_str()); + my::Json timeRoot(result.c_str()); auto const timesArray = json_object_get(timeRoot.get(), "times"); TEST(json_is_array(timesArray), ()); @@ -64,8 +69,12 @@ UNIT_TEST(Uber_GetPrices) { ms::LatLon const from(38.897724, -77.036531); ms::LatLon const to(38.862416, -76.883316); + string result; + + TEST(uber::RawApi::GetEstimatedPrice(from, to, result), ()); + TEST(!result.empty(), ()); - my::Json priceRoot(uber::RawApi::GetEstimatedPrice(from, to).c_str()); + my::Json priceRoot(result.c_str()); auto const pricesArray = json_object_get(priceRoot.get(), "prices"); TEST(json_is_array(pricesArray), ()); @@ -116,15 +125,27 @@ UNIT_TEST(Uber_ProductMaker) uber::ProductMaker maker; - maker.Reset(reqId); - maker.SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); - maker.SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); - maker.MakeProducts(reqId, [&returnedId, &returnedProducts] - (vector<uber::Product> const & products, size_t const requestId) + string times; + string prices; + + auto const errorCallback = [](uber::ErrorCode const code, uint64_t const requestId) { - returnedId = requestId; - returnedProducts = products; - }); + TEST(false, ()); + }; + + TEST(uber::RawApi::GetEstimatedTime(from, times), ()); + TEST(uber::RawApi::GetEstimatedPrice(from, to, prices), ()); + + maker.Reset(reqId); + maker.SetTimes(reqId, times); + maker.SetPrices(reqId, prices); + maker.MakeProducts(reqId, + [&returnedId, &returnedProducts](vector<uber::Product> const & products, + size_t const requestId) { + returnedId = requestId; + returnedProducts = products; + }, + errorCallback); TEST(!returnedProducts.empty(), ()); TEST_EQUAL(returnedId, reqId, ()); @@ -134,14 +155,17 @@ UNIT_TEST(Uber_ProductMaker) ++reqId; + TEST(uber::RawApi::GetEstimatedTime(from, times), ()); + TEST(uber::RawApi::GetEstimatedPrice(from, to, prices), ()); + maker.Reset(reqId); - maker.SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); - maker.SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); + maker.SetTimes(reqId, times); + maker.SetPrices(reqId, prices); maker.MakeProducts(reqId + 1, [](vector<uber::Product> const & products, size_t const requestId) { TEST(false, ()); - }); + }, errorCallback); } UNIT_TEST(Uber_Smoke) @@ -153,6 +177,16 @@ UNIT_TEST(Uber_Smoke) ms::LatLon const from(38.897724, -77.036531); ms::LatLon const to(38.862416, -76.883316); + auto const errorCallback = [](uber::ErrorCode const code, uint64_t const requestId) + { + TEST(false, ()); + }; + + auto const errorPossibleCallback = [](uber::ErrorCode const code, uint64_t const requestId) + { + TEST(code == uber::ErrorCode::NoProducts, ()); + }; + auto const standardCallback = [&reqId, &productsContainer, &resultsMutex](vector<uber::Product> const & products, size_t const requestId) { @@ -169,12 +203,18 @@ UNIT_TEST(Uber_Smoke) testing::StopEventLoop(); }; + string times; + string prices; + + TEST(uber::RawApi::GetEstimatedTime(from, times), ()); + TEST(uber::RawApi::GetEstimatedPrice(from, to, prices), ()); + uber::ProductMaker maker; maker.Reset(reqId); - maker.SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); - maker.SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); - maker.MakeProducts(reqId, standardCallback); + maker.SetTimes(reqId, times); + maker.SetPrices(reqId, prices); + maker.MakeProducts(reqId, standardCallback, errorCallback); reqId = 0; @@ -187,21 +227,24 @@ UNIT_TEST(Uber_Smoke) { lock_guard<mutex> lock(resultsMutex); reqId = uberApi.GetAvailableProducts(ms::LatLon(55.753960, 37.624513), - ms::LatLon(55.765866, 37.661270), standardCallback); + ms::LatLon(55.765866, 37.661270), standardCallback, + errorPossibleCallback); } { lock_guard<mutex> lock(resultsMutex); reqId = uberApi.GetAvailableProducts(ms::LatLon(59.922445, 30.367201), - ms::LatLon(59.943675, 30.361123), standardCallback); + ms::LatLon(59.943675, 30.361123), standardCallback, + errorPossibleCallback); } { lock_guard<mutex> lock(resultsMutex); reqId = uberApi.GetAvailableProducts(ms::LatLon(52.509621, 13.450067), - ms::LatLon(52.510811, 13.409490), standardCallback); + ms::LatLon(52.510811, 13.409490), standardCallback, + errorPossibleCallback); } { lock_guard<mutex> lock(resultsMutex); - reqId = uberApi.GetAvailableProducts(from, to, lastCallback); + reqId = uberApi.GetAvailableProducts(from, to, lastCallback, errorCallback); } } diff --git a/partners_api/uber_api.cpp b/partners_api/uber_api.cpp index 56833f58a8..c03cdaaea6 100644 --- a/partners_api/uber_api.cpp +++ b/partners_api/uber_api.cpp @@ -17,14 +17,15 @@ using namespace platform; namespace { -string RunSimpleHttpRequest(string const & url) +bool RunSimpleHttpRequest(string const & url, string & result) { HttpClient request(url); if (request.RunHttpRequest() && !request.WasRedirected() && request.ErrorCode() == 200) { - return request.ServerResponse(); + result = request.ServerResponse(); + return true; } - return {}; + return false; } bool CheckUberAnswer(json_t const * answer) @@ -115,29 +116,29 @@ void MakeFromJson(char const * times, char const * prices, vector<uber::Product> namespace uber { // static -string RawApi::GetProducts(ms::LatLon const & pos) +bool RawApi::GetProducts(ms::LatLon const & pos, string & result) { stringstream url; url << fixed << setprecision(6) << "https://api.uber.com/v1/products?server_token=" << UBER_SERVER_TOKEN << "&latitude=" << pos.lat << "&longitude=" << pos.lon; - return RunSimpleHttpRequest(url.str()); + return RunSimpleHttpRequest(url.str(), result); } // static -string RawApi::GetEstimatedTime(ms::LatLon const & pos) +bool RawApi::GetEstimatedTime(ms::LatLon const & pos, string & result) { stringstream url; url << fixed << setprecision(6) << "https://api.uber.com/v1/estimates/time?server_token=" << UBER_SERVER_TOKEN << "&start_latitude=" << pos.lat << "&start_longitude=" << pos.lon; - return RunSimpleHttpRequest(url.str()); + return RunSimpleHttpRequest(url.str(), result); } // static -string RawApi::GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to) +bool RawApi::GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to, string & result) { stringstream url; url << fixed << setprecision(6) @@ -145,7 +146,7 @@ string RawApi::GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to) << "&start_latitude=" << from.lat << "&start_longitude=" << from.lon << "&end_latitude=" << to.lat << "&end_longitude=" << to.lon; - return RunSimpleHttpRequest(url.str()); + return RunSimpleHttpRequest(url.str(), result); } void ProductMaker::Reset(uint64_t const requestId) @@ -177,7 +178,8 @@ void ProductMaker::SetPrices(uint64_t const requestId, string const & prices) m_prices = make_unique<string>(prices); } -void ProductMaker::MakeProducts(uint64_t const requestId, ProductsCallback const & fn) +void ProductMaker::MakeProducts(uint64_t const requestId, ProductsCallback const & successFn, + ErrorCallback const & errorFn) { vector<uber::Product> products; { @@ -191,27 +193,45 @@ void ProductMaker::MakeProducts(uint64_t const requestId, ProductsCallback const else LOG(LWARNING, ("Time or price is empty, time:", *m_times, "; price:", *m_prices)); } - fn(products, requestId); + + if (products.empty()) + errorFn(ErrorCode::NoProducts, requestId); + else + successFn(products, requestId); } uint64_t Api::GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to, - ProductsCallback const & fn) + ProductsCallback const & successFn, ErrorCallback const & errorFn) { auto const reqId = ++m_requestId; auto const maker = m_maker; maker->Reset(reqId); - threads::SimpleThread([maker, from, reqId, fn]() + threads::SimpleThread([maker, from, reqId, successFn, errorFn]() { - maker->SetTimes(reqId, uber::RawApi::GetEstimatedTime(from)); - maker->MakeProducts(reqId, fn); + string result; + if (!RawApi::GetEstimatedTime(from, result)) + { + errorFn(ErrorCode::RemoteError, reqId); + return; + } + + maker->SetTimes(reqId, result); + maker->MakeProducts(reqId, successFn, errorFn); }).detach(); - threads::SimpleThread([maker, from, to, reqId, fn]() + threads::SimpleThread([maker, from, to, reqId, successFn, errorFn]() { - maker->SetPrices(reqId, uber::RawApi::GetEstimatedPrice(from, to)); - maker->MakeProducts(reqId, fn); + string result; + if (!RawApi::GetEstimatedPrice(from, to, result)) + { + errorFn(ErrorCode::RemoteError, reqId); + return; + } + + maker->SetPrices(reqId, result); + maker->MakeProducts(reqId, successFn, errorFn); }).detach(); return reqId; diff --git a/partners_api/uber_api.hpp b/partners_api/uber_api.hpp index 536e931a69..ada7db24aa 100644 --- a/partners_api/uber_api.hpp +++ b/partners_api/uber_api.hpp @@ -23,21 +23,23 @@ namespace uber class RawApi { public: - /// Returns information about the Uber products offered at a given location. - /// The response includes the display name and other details about each product, and lists the - /// products in the proper display order. This endpoint does not reflect real-time availability - /// of the products. - static string GetProducts(ms::LatLon const & pos); - /// Returns ETAs for all products currently available at a given location, with the ETA for each - /// product expressed as integers in seconds. If a product returned from GetProducts is not - /// returned from this endpoint for a given latitude/longitude pair then there are currently none - /// of that product available to request. Call this endpoint every minute to provide the most - /// accurate, up-to-date ETAs. - static string GetEstimatedTime(ms::LatLon const & pos); - /// Returns an estimated price range for each product offered at a given location. The price - /// estimate is provided as a formatted string with the full price range and the localized - /// currency symbol. - static string GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to); + /// Returns true when http request was executed successfully and response copied into @result, + /// otherwise returns false. The response contains the display name and other details about each + /// product, and lists the products in the proper display order. This endpoint does not reflect + /// real-time availability of the products. + static bool GetProducts(ms::LatLon const & pos, string & result); + /// Returns true when http request was executed successfully and response copied into @result, + /// otherwise returns false. The response contains ETAs for all products currently available + /// at a given location, with the ETA for each product expressed as integers in seconds. If a + /// product returned from GetProducts is not returned from this endpoint for a given + /// latitude/longitude pair then there are currently none of that product available to request. + /// Call this endpoint every minute to provide the most accurate, up-to-date ETAs. + static bool GetEstimatedTime(ms::LatLon const & pos, string & result); + /// Returns true when http request was executed successfully and response copied into @result, + /// otherwise returns false. The response contains an estimated price range for each product + /// offered at a given location. The price estimate is provided as a formatted string with the + /// full price range and the localized currency symbol. + static bool GetEstimatedPrice(ms::LatLon const & from, ms::LatLon const & to, string & result); }; struct Product @@ -48,10 +50,19 @@ struct Product string m_price; // for some currencies this field contains symbol of currency but not always string m_currency; // currency can be empty, for ex. when m_price equal to Metered }; -/// @products - vector of available products for requested route. +/// @products - vector of available products for requested route, cannot be empty. /// @requestId - identificator which was provided to GetAvailableProducts to identify request. using ProductsCallback = function<void(vector<Product> const & products, uint64_t const requestId)>; +enum class ErrorCode +{ + NoProducts, + RemoteError +}; + +/// Callback which is called when an errors occurs. +using ErrorCallback = function<void(ErrorCode const code, uint64_t const requestId)>; + /// Class which used for making products from http requests results. class ProductMaker { @@ -59,7 +70,8 @@ public: void Reset(uint64_t const requestId); void SetTimes(uint64_t const requestId, string const & times); void SetPrices(uint64_t const requestId, string const & prices); - void MakeProducts(uint64_t const requestId, ProductsCallback const & fn); + void MakeProducts(uint64_t const requestId, ProductsCallback const & successFn, + ErrorCallback const & errorFn); private: uint64_t m_requestId = 0; @@ -79,7 +91,7 @@ class Api public: /// Requests list of available products from Uber. Returns request identificator immediately. uint64_t GetAvailableProducts(ms::LatLon const & from, ms::LatLon const & to, - ProductsCallback const & fn); + ProductsCallback const & successFn, ErrorCallback const & errorFn); /// Returns link which allows you to launch the Uber app. static RideRequestLinks GetRideRequestLinks(string const & productId, ms::LatLon const & from, |