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
This commit is contained in:
Alex Dale
2019-08-13 18:13:35 -07:00
parent e884b06e54
commit 8a82379e81
2 changed files with 82 additions and 31 deletions

View File

@@ -11,7 +11,9 @@
#include <openssl/cmac.h>
#include <stdlib.h>
#include <chrono>
#include <string>
#include <thread>
#include <vector>
#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<EngineMetrics>(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<uint8_t> 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<uint8_t> 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

View File

@@ -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();