// Copyright 2018 Google LLC. All Rights Reserved. This file and proprietary // source code may only be used and distributed under the Widevine Master // License Agreement. #include "test_host.h" #include #include #include "device_cert.h" #include "log.h" using namespace widevine; namespace { constexpr char kCertificateFilename[] = "cert.bin"; } // namespace TestHost::TestHost() { Reset(); } TestHost::~TestHost() { wvcdm::TestSleep::set_callback(nullptr); } void TestHost::Reset() { auto now = std::chrono::steady_clock().now(); now_ = now.time_since_epoch() / std::chrono::milliseconds(1); wvcdm::TestSleep::set_callback(this); save_device_cert_ = false; // Surprisingly, std::priority_queue has no clear(). while (!timers_.empty()) { timers_.pop(); } files_.clear(); files_[kCertificateFilename] = (device_cert_.size() > 0) ? device_cert_ : std::string((const char*)kDeviceCert, kDeviceCertSize); } void TestHost::ElapseTime(int64_t milliseconds) { // Note that, during the time rollback tests, milliseconds will be negative, // so we cannot assume goal_time > now_. int64_t goal_time = now_ + milliseconds; // Walk forward from now_ to goal_time, stepping at each timer along the way // to fire its callback. while (!timers_.empty() && now_ < goal_time) { Timer t = timers_.top(); ASSERT_GE(t.expiry_time(), now_); if (t.expiry_time() <= goal_time) { timers_.pop(); now_ = t.expiry_time(); t.client()->onTimerExpired(t.context()); } else { // The next timer is further in the future than goal_time, so we are done // processing the timers. break; } } // No matter what happened with the timers, update now_ to the goal_time. now_ = goal_time; } int TestHost::NumTimers() const { return timers_.size(); } bool TestHost::read(const std::string& name, std::string* data) { StorageMap::iterator it = files_.find(name); bool ok = it != files_.end(); LOGV("read file: %s: %s", name.c_str(), ok ? "ok" : "fail"); if (!ok) return false; *data = it->second; return true; } bool TestHost::write(const std::string& name, const std::string& data) { LOGV("write file: %s", name.c_str()); files_[name] = data; if (save_device_cert_ && name.compare(kCertificateFilename) == 0) { device_cert_ = data; save_device_cert_ = false; } return true; } bool TestHost::exists(const std::string& name) { StorageMap::iterator it = files_.find(name); bool ok = it != files_.end(); LOGV("exists? %s: %s", name.c_str(), ok ? "true" : "false"); return ok; } bool TestHost::remove(const std::string& name) { LOGV("remove: %s", name.c_str()); if (name.empty()) { // If no name, delete all files (see DeviceFiles::DeleteAllFiles()) files_.clear(); return true; } return files_.erase(name) > 0; } int32_t TestHost::size(const std::string& name) { StorageMap::iterator it = files_.find(name); if (it == files_.end()) return -1; return it->second.size(); } bool TestHost::list(std::vector* names) { names->clear(); for (StorageMap::iterator it = files_.begin(); it != files_.end(); it++) { names->push_back(it->first); } return true; } int64_t TestHost::now() { return now_; } void TestHost::setTimeout(int64_t delay_ms, IClient* client, void* context) { int64_t expiry_time = now_ + delay_ms; timers_.push(Timer(expiry_time, client, context)); } void TestHost::cancel(IClient* client) { // Filter out the timers for this client and put the rest into |others|. std::priority_queue others; while (timers_.size()) { Timer t = timers_.top(); timers_.pop(); if (t.client() != client) { others.push(t); } } // Now swap the queues. std::swap(timers_, others); }