From 8a82379e81faf78b62b2ee45817a97a183cc0dfa Mon Sep 17 00:00:00 2001 From: Alex Dale Date: Tue, 13 Aug 2019 18:13:35 -0700 Subject: [PATCH] Unittests will retry provisioning if failed. [ Merge of http://go/wvgerrit/84490 ] The unit tests will now make at most 10 attempts to provision themselves before declaring failure. This change is made to help with flaky provisioning requests that have been experienced on the Jenkins build server. Bug: 139298083 Test: Linux unit test, Jenkins build and Android unit tests Change-Id: I6415a5ef9fdf10ceb893867d5fc73131338e9f76 --- libwvdrmengine/cdm/core/test/test_base.cpp | 108 +++++++++++++++------ libwvdrmengine/cdm/core/test/test_base.h | 5 +- 2 files changed, 82 insertions(+), 31 deletions(-) diff --git a/libwvdrmengine/cdm/core/test/test_base.cpp b/libwvdrmengine/cdm/core/test/test_base.cpp index 2f240265..c6ed69bd 100644 --- a/libwvdrmengine/cdm/core/test/test_base.cpp +++ b/libwvdrmengine/cdm/core/test/test_base.cpp @@ -11,7 +11,9 @@ #include #include +#include #include +#include #include #include "cdm_engine.h" @@ -253,7 +255,7 @@ void WvCdmTestBase::InstallTestRootOfTrust() { } } -void WvCdmTestBase::Provision() { +void WvCdmTestBase::Provision(size_t max_attempts) { CdmProvisioningRequest prov_request; CdmProvisioningRequest binary_prov_request; std::string provisioning_server_url; @@ -264,6 +266,8 @@ void WvCdmTestBase::Provision() { CdmSessionId session_id; FileSystem file_system; + ASSERT_GE(max_attempts, 1lu) << "|max_attempts| must be at least 1"; + // TODO(fredgc): provision for different SPOIDs. CdmEngine cdm_engine(&file_system, std::shared_ptr(new EngineMetrics)); @@ -284,41 +288,85 @@ void WvCdmTestBase::Provision() { // Ignore URL provided by CdmEngine. Use ours, as configured // for test vs. production server. provisioning_server_url.assign(config_.provisioning_server()); - UrlRequest url_request(provisioning_server_url); - EXPECT_TRUE(url_request.is_connected()); - url_request.PostCertRequestInQueryString(prov_request); + + // Attempt to provision using the same requests a maximum of |max_attempts| + // times. + // TODO(b/139361531): Remove loop once provisioning service is stable. std::string http_message; - bool ok = url_request.GetResponse(&http_message); - EXPECT_TRUE(ok) << http_message; + size_t attempt_num = 0; + bool provision_success = false; + do { + if (attempt_num > 0) { + // Sleep between attempts. + std::this_thread::sleep_for(std::chrono::seconds(1)); + } + ++attempt_num; - LOGV("WvCdmTestBase::Provision: http_message: \n%s\n", http_message.c_str()); + // Make request. + UrlRequest url_request(provisioning_server_url); + if (!url_request.is_connected()) { + LOGE("Failed to connect to provisioning server: url = %s", + provisioning_server_url.c_str()); + continue; + } + url_request.PostCertRequestInQueryString(prov_request); - if (binary_provisioning_) { - // extract provisioning response from received message - // Extracts signed response from JSON string, result is serialized protobuf. - const std::string kMessageStart = "\"signedResponse\": \""; - const std::string kMessageEnd = "\""; - std::string protobuf_response; - EXPECT_TRUE(ExtractSignedMessage(http_message, kMessageStart, kMessageEnd, - &protobuf_response)) - << "Failed to extract signed serialized response from JSON response"; + // Receive and parse response. + if (!url_request.GetResponse(&http_message)) { + LOGE("Failed to get provisioning response"); + continue; + } - LOGV("WvCdmEnginePreProvTest::Provision: extracted response message: \n" - "%s\n", protobuf_response.c_str()); + LOGV("http_message: \n%s\n", http_message.c_str()); - // base64 decode response to yield binary protobuf - std::vector response_vec(Base64SafeDecode( - std::string(protobuf_response.begin(), protobuf_response.end()))); - std::string binary_protobuf_response(response_vec.begin(), - response_vec.end()); - ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse( - binary_protobuf_response, &cert, &wrapped_key)) - << "message = " << http_message; - } else { - ASSERT_EQ(NO_ERROR, cdm_engine.HandleProvisioningResponse( - http_message, &cert, &wrapped_key)) - << "message = " << http_message; + if (binary_provisioning_) { + // extract provisioning response from received message + // Extracts signed response from JSON string, result is serialized + // protobuf. + static const std::string kMessageStart = "\"signedResponse\": \""; + static const std::string kMessageEnd = "\""; + std::string protobuf_response; + if (!ExtractSignedMessage(http_message, kMessageStart, kMessageEnd, + &protobuf_response)) { + LOGE("Failed to extract signed serialized response from JSON response"); + continue; + } + + LOGV("Extracted response message: \n%s\n", protobuf_response.c_str()); + + // base64 decode response to yield binary protobuf + std::vector response_vec(Base64SafeDecode(protobuf_response)); + if (response_vec.empty() && !protobuf_response.empty()) { + LOGE("Failed to decode base64 of response: response = %s", + protobuf_response.c_str()); + continue; + } + + std::string binary_protobuf_response(response_vec.begin(), + response_vec.end()); + + if (cdm_engine.HandleProvisioningResponse(binary_protobuf_response, &cert, + &wrapped_key) != NO_ERROR) { + LOGE("Failed to handle provisioning response"); + continue; + } + } else { + if (cdm_engine.HandleProvisioningResponse(http_message, &cert, + &wrapped_key) != NO_ERROR) { + LOGE("Failed to handle binary provisioning response"); + continue; + } + } + provision_success = true; + } while (attempt_num <= max_attempts && !provision_success); + + if (attempt_num > 1) { + LOGW("Provisioning request failed at least once: attempts = %zu", + attempt_num); } + + ASSERT_TRUE(provision_success) + << "Failed to provision: message = " << http_message; } // TODO(fredgc): Replace this with a pre-defined DRM certificate. We could do diff --git a/libwvdrmengine/cdm/core/test/test_base.h b/libwvdrmengine/cdm/core/test/test_base.h index c93c5365..5496225a 100644 --- a/libwvdrmengine/cdm/core/test/test_base.h +++ b/libwvdrmengine/cdm/core/test/test_base.h @@ -19,6 +19,9 @@ namespace wvcdm { // to configure OEMCrypto to use a test keybox. class WvCdmTestBase : public ::testing::Test { public: + // Default number of provisioning try attempts. + constexpr static size_t kDefaultMaxProvisioningAttempts = 10; + WvCdmTestBase() : config_(default_config_), binary_provisioning_(false) {} ~WvCdmTestBase() override {} void SetUp() override; @@ -32,7 +35,7 @@ class WvCdmTestBase : public ::testing::Test { static void InstallTestRootOfTrust(); // Send provisioning request to the server and handle response. - virtual void Provision(); + virtual void Provision(size_t max_attempts = kDefaultMaxProvisioningAttempts); // Calls Provision() if not already provisioned. virtual void EnsureProvisioned();