Upstream version 10.39.225.0
[platform/framework/web/crosswalk.git] / src / media / cdm / aes_decryptor_unittest.cc
index 3adc861..de52d69 100644 (file)
@@ -7,11 +7,13 @@
 
 #include "base/basictypes.h"
 #include "base/bind.h"
+#include "base/json/json_reader.h"
+#include "base/values.h"
+#include "media/base/cdm_promise.h"
 #include "media/base/decoder_buffer.h"
 #include "media/base/decrypt_config.h"
 #include "media/base/mock_filters.h"
 #include "media/cdm/aes_decryptor.h"
-#include "media/webm/webm_constants.h"
 #include "testing/gmock/include/gmock/gmock.h"
 #include "testing/gtest/include/gtest/gtest.h"
 
@@ -23,6 +25,14 @@ using ::testing::SaveArg;
 using ::testing::StrNe;
 
 MATCHER(IsEmpty, "") { return arg.empty(); }
+MATCHER(IsNotEmpty, "") { return !arg.empty(); }
+MATCHER(IsJSONDictionary, "") {
+  std::string result(arg.begin(), arg.end());
+  scoped_ptr<base::Value> root(base::JSONReader().ReadToValue(result));
+  return (root.get() && root->GetType() == base::Value::TYPE_DICTIONARY);
+}
+
+class GURL;
 
 namespace media {
 
@@ -38,12 +48,8 @@ const uint8 kKeyId[] = {
     0x00, 0x01, 0x02, 0x03
 };
 
-const uint8 kKey[] = {
-    // base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw
-    0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b,
-    0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13
-};
-
+// Key is 0x0405060708090a0b0c0d0e0f10111213,
+// base64 equivalent is BAUGBwgJCgsMDQ4PEBESEw.
 const char kKeyAsJWK[] =
     "{"
     "  \"keys\": ["
@@ -52,6 +58,19 @@ const char kKeyAsJWK[] =
     "      \"kid\": \"AAECAw\","
     "      \"k\": \"BAUGBwgJCgsMDQ4PEBESEw\""
     "    }"
+    "  ],"
+    "  \"type\": \"temporary\""
+    "}";
+
+// Same kid as kKeyAsJWK, key to decrypt kEncryptedData2
+const char kKeyAlternateAsJWK[] =
+    "{"
+    "  \"keys\": ["
+    "    {"
+    "      \"kty\": \"oct\","
+    "      \"kid\": \"AAECAw\","
+    "      \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
+    "    }"
     "  ]"
     "}";
 
@@ -169,12 +188,10 @@ static scoped_refptr<DecoderBuffer> CreateEncryptedBuffer(
     const std::vector<uint8>& data,
     const std::vector<uint8>& key_id,
     const std::vector<uint8>& iv,
-    int offset,
     const std::vector<SubsampleEntry>& subsample_entries) {
   DCHECK(!data.empty());
-  int padded_size = offset + data.size();
-  scoped_refptr<DecoderBuffer> encrypted_buffer(new DecoderBuffer(padded_size));
-  memcpy(encrypted_buffer->writable_data() + offset, &data[0], data.size());
+  scoped_refptr<DecoderBuffer> encrypted_buffer(new DecoderBuffer(data.size()));
+  memcpy(encrypted_buffer->writable_data(), &data[0], data.size());
   CHECK(encrypted_buffer.get());
   std::string key_id_string(
       reinterpret_cast<const char*>(key_id.empty() ? NULL : &key_id[0]),
@@ -182,17 +199,21 @@ static scoped_refptr<DecoderBuffer> CreateEncryptedBuffer(
   std::string iv_string(
       reinterpret_cast<const char*>(iv.empty() ? NULL : &iv[0]), iv.size());
   encrypted_buffer->set_decrypt_config(scoped_ptr<DecryptConfig>(
-      new DecryptConfig(key_id_string, iv_string, offset, subsample_entries)));
+      new DecryptConfig(key_id_string, iv_string, subsample_entries)));
   return encrypted_buffer;
 }
 
+enum PromiseResult { RESOLVED, REJECTED };
+
 class AesDecryptorTest : public testing::Test {
  public:
   AesDecryptorTest()
-      : decryptor_(
-            base::Bind(&AesDecryptorTest::KeyAdded, base::Unretained(this)),
-            base::Bind(&AesDecryptorTest::KeyError, base::Unretained(this)),
-            base::Bind(&AesDecryptorTest::KeyMessage, base::Unretained(this))),
+      : decryptor_(base::Bind(&AesDecryptorTest::OnSessionMessage,
+                              base::Unretained(this)),
+                   base::Bind(&AesDecryptorTest::OnSessionClosed,
+                              base::Unretained(this)),
+                   base::Bind(&AesDecryptorTest::OnSessionKeysChange,
+                              base::Unretained(this))),
         decrypt_cb_(base::Bind(&AesDecryptorTest::BufferDecrypted,
                                base::Unretained(this))),
         original_data_(kOriginalData, kOriginalData + kOriginalDataSize),
@@ -209,54 +230,134 @@ class AesDecryptorTest : public testing::Test {
   }
 
  protected:
-  void GenerateKeyRequest(const std::vector<uint8>& key_id) {
-    DCHECK(!key_id.empty());
-    EXPECT_CALL(*this, KeyMessage(StrNe(std::string()), key_id, ""))
-        .WillOnce(SaveArg<0>(&session_id_string_));
-    EXPECT_TRUE(decryptor_.GenerateKeyRequest(
-        std::string(), &key_id[0], key_id.size()));
+  void OnResolveWithSession(PromiseResult expected_result,
+                            const std::string& web_session_id) {
+    EXPECT_EQ(expected_result, RESOLVED) << "Unexpectedly resolved.";
+    EXPECT_GT(web_session_id.length(), 0ul);
+    web_session_id_ = web_session_id;
   }
 
-  enum AddKeyExpectation {
-    KEY_ADDED,
-    KEY_ERROR
-  };
+  void OnResolve(PromiseResult expected_result) {
+    EXPECT_EQ(expected_result, RESOLVED) << "Unexpectedly resolved.";
+  }
+
+  void OnResolveWithUsableKeyIds(PromiseResult expected_result,
+                                 uint32 expected_count,
+                                 const KeyIdsVector& useable_key_ids) {
+    EXPECT_EQ(expected_result, RESOLVED) << "Unexpectedly resolved.";
+    EXPECT_EQ(expected_count, useable_key_ids.size());
+    useable_key_ids_ = useable_key_ids;
+  }
+
+  void OnReject(PromiseResult expected_result,
+                MediaKeys::Exception exception_code,
+                uint32 system_code,
+                const std::string& error_message) {
+    EXPECT_EQ(expected_result, REJECTED) << "Unexpectedly rejected.";
+  }
+
+  scoped_ptr<SimpleCdmPromise> CreatePromise(PromiseResult expected_result) {
+    scoped_ptr<SimpleCdmPromise> promise(
+        new SimpleCdmPromise(base::Bind(&AesDecryptorTest::OnResolve,
+                                        base::Unretained(this),
+                                        expected_result),
+                             base::Bind(&AesDecryptorTest::OnReject,
+                                        base::Unretained(this),
+                                        expected_result)));
+    return promise.Pass();
+  }
+
+  scoped_ptr<NewSessionCdmPromise> CreateSessionPromise(
+      PromiseResult expected_result) {
+    scoped_ptr<NewSessionCdmPromise> promise(new NewSessionCdmPromise(
+        base::Bind(&AesDecryptorTest::OnResolveWithSession,
+                   base::Unretained(this),
+                   expected_result),
+        base::Bind(&AesDecryptorTest::OnReject,
+                   base::Unretained(this),
+                   expected_result)));
+    return promise.Pass();
+  }
 
-  void AddRawKeyAndExpect(const std::vector<uint8>& key_id,
-                          const std::vector<uint8>& key,
-                          AddKeyExpectation result) {
-    // TODO(jrummell): Remove once raw keys no longer supported.
+  scoped_ptr<KeyIdsPromise> CreateUsableKeyIdsPromise(
+      PromiseResult expected_result,
+      uint32 expected_count) {
+    scoped_ptr<KeyIdsPromise> promise(new KeyIdsPromise(
+        base::Bind(&AesDecryptorTest::OnResolveWithUsableKeyIds,
+                   base::Unretained(this),
+                   expected_result,
+                   expected_count),
+        base::Bind(&AesDecryptorTest::OnReject,
+                   base::Unretained(this),
+                   expected_result)));
+    return promise.Pass();
+  }
+
+  // Creates a new session using |key_id|. Returns the session ID.
+  std::string CreateSession(const std::vector<uint8>& key_id) {
     DCHECK(!key_id.empty());
-    DCHECK(!key.empty());
+    EXPECT_CALL(*this,
+                OnSessionMessage(
+                    IsNotEmpty(), IsJSONDictionary(), GURL::EmptyGURL()));
+    decryptor_.CreateSession(std::string(),
+                             &key_id[0],
+                             key_id.size(),
+                             MediaKeys::TEMPORARY_SESSION,
+                             CreateSessionPromise(RESOLVED));
+    // This expects the promise to be called synchronously, which is the case
+    // for AesDecryptor.
+    return web_session_id_;
+  }
 
-    if (result == KEY_ADDED) {
-      EXPECT_CALL(*this, KeyAdded(session_id_string_));
-    } else if (result == KEY_ERROR) {
-      EXPECT_CALL(*this, KeyError(session_id_string_,
-                                  MediaKeys::kUnknownError, 0));
-    } else {
-      NOTREACHED();
-    }
+  // Closes the session specified by |session_id|.
+  void CloseSession(const std::string& session_id) {
+    EXPECT_CALL(*this, OnSessionClosed(session_id));
+    decryptor_.CloseSession(session_id, CreatePromise(RESOLVED));
+  }
 
-    decryptor_.AddKey(&key[0], key.size(), &key_id[0], key_id.size(),
-                      session_id_string_);
+  // Removes the session specified by |session_id|. This should simply do a
+  // CloseSession().
+  // TODO(jrummell): Clean this up when the prefixed API is removed.
+  // http://crbug.com/249976.
+  void RemoveSession(const std::string& session_id) {
+    EXPECT_CALL(*this, OnSessionClosed(session_id));
+    decryptor_.RemoveSession(session_id, CreatePromise(RESOLVED));
   }
 
-  void AddKeyAndExpect(const std::string& key, AddKeyExpectation result) {
+  // Updates the session specified by |session_id| with |key|. |result|
+  // tests that the update succeeds or generates an error.
+  void UpdateSessionAndExpect(std::string session_id,
+                              const std::string& key,
+                              PromiseResult expected_result) {
     DCHECK(!key.empty());
 
-    if (result == KEY_ADDED) {
-      EXPECT_CALL(*this, KeyAdded(session_id_string_));
-    } else if (result == KEY_ERROR) {
-      EXPECT_CALL(*this,
-                  KeyError(session_id_string_, MediaKeys::kUnknownError, 0));
+    if (expected_result == RESOLVED) {
+      EXPECT_CALL(*this, OnSessionKeysChange(session_id, true));
     } else {
-      NOTREACHED();
+      EXPECT_CALL(*this, OnSessionKeysChange(_, _)).Times(0);
     }
 
-    decryptor_.AddKey(reinterpret_cast<const uint8*>(key.c_str()), key.length(),
-                      NULL, 0,
-                      session_id_string_);
+    decryptor_.UpdateSession(session_id,
+                             reinterpret_cast<const uint8*>(key.c_str()),
+                             key.length(),
+                             CreatePromise(expected_result));
+  }
+
+  void GetUsableKeyIdsAndExpect(const std::string& session_id,
+                                PromiseResult expected_result,
+                                uint32 expected_count) {
+    decryptor_.GetUsableKeyIds(
+        session_id, CreateUsableKeyIdsPromise(expected_result, expected_count));
+  }
+
+  bool UsableKeyIdsContains(std::vector<uint8> expected) {
+    for (KeyIdsVector::iterator it = useable_key_ids_.begin();
+         it != useable_key_ids_.end();
+         ++it) {
+      if (*it == expected)
+        return true;
+    }
+    return false;
   }
 
   MOCK_METHOD2(BufferDecrypted, void(Decryptor::Status,
@@ -266,7 +367,8 @@ class AesDecryptorTest : public testing::Test {
     SUCCESS,
     DATA_MISMATCH,
     DATA_AND_SIZE_MISMATCH,
-    DECRYPT_ERROR
+    DECRYPT_ERROR,
+    NO_KEY
   };
 
   void DecryptAndExpect(const scoped_refptr<DecoderBuffer>& encrypted,
@@ -274,18 +376,27 @@ class AesDecryptorTest : public testing::Test {
                         DecryptExpectation result) {
     scoped_refptr<DecoderBuffer> decrypted;
 
-    if (result != DECRYPT_ERROR) {
-      EXPECT_CALL(*this, BufferDecrypted(Decryptor::kSuccess, NotNull()))
-          .WillOnce(SaveArg<1>(&decrypted));
-    } else {
-      EXPECT_CALL(*this, BufferDecrypted(Decryptor::kError, IsNull()))
-          .WillOnce(SaveArg<1>(&decrypted));
+    switch (result) {
+      case SUCCESS:
+      case DATA_MISMATCH:
+      case DATA_AND_SIZE_MISMATCH:
+        EXPECT_CALL(*this, BufferDecrypted(Decryptor::kSuccess, NotNull()))
+            .WillOnce(SaveArg<1>(&decrypted));
+        break;
+      case DECRYPT_ERROR:
+        EXPECT_CALL(*this, BufferDecrypted(Decryptor::kError, IsNull()))
+            .WillOnce(SaveArg<1>(&decrypted));
+        break;
+      case NO_KEY:
+        EXPECT_CALL(*this, BufferDecrypted(Decryptor::kNoKey, IsNull()))
+            .WillOnce(SaveArg<1>(&decrypted));
+        break;
     }
 
     decryptor_.Decrypt(Decryptor::kVideo, encrypted, decrypt_cb_);
 
     std::vector<uint8> decrypted_text;
-    if (decrypted && decrypted->data_size()) {
+    if (decrypted.get() && decrypted->data_size()) {
       decrypted_text.assign(
         decrypted->data(), decrypted->data() + decrypted->data_size());
     }
@@ -302,21 +413,28 @@ class AesDecryptorTest : public testing::Test {
         EXPECT_NE(plain_text.size(), decrypted_text.size());
         break;
       case DECRYPT_ERROR:
+      case NO_KEY:
         EXPECT_TRUE(decrypted_text.empty());
         break;
     }
   }
 
-  MOCK_METHOD1(KeyAdded, void(const std::string&));
-  MOCK_METHOD3(KeyError, void(const std::string&,
-                              MediaKeys::KeyError, int));
-  MOCK_METHOD3(KeyMessage, void(const std::string& session_id,
-                                const std::vector<uint8>& message,
-                                const std::string& default_url));
+  MOCK_METHOD3(OnSessionMessage,
+               void(const std::string& web_session_id,
+                    const std::vector<uint8>& message,
+                    const GURL& destination_url));
+  MOCK_METHOD2(OnSessionKeysChange,
+               void(const std::string& web_session_id,
+                    bool has_additional_usable_key));
+  MOCK_METHOD1(OnSessionClosed, void(const std::string& web_session_id));
 
   AesDecryptor decryptor_;
-  std::string session_id_string_;
   AesDecryptor::DecryptCB decrypt_cb_;
+  std::string web_session_id_;
+
+  // Copy of the vector from the last successful call to
+  // OnResolveWithUsableKeyIds().
+  KeyIdsVector useable_key_ids_;
 
   // Constants for testing.
   const std::vector<uint8> original_data_;
@@ -328,81 +446,100 @@ class AesDecryptorTest : public testing::Test {
   const std::vector<SubsampleEntry> no_subsample_entries_;
 };
 
-TEST_F(AesDecryptorTest, GenerateKeyRequestWithNullInitData) {
-  EXPECT_CALL(*this, KeyMessage(StrNe(std::string()), IsEmpty(), ""));
-  EXPECT_TRUE(decryptor_.GenerateKeyRequest(std::string(), NULL, 0));
+TEST_F(AesDecryptorTest, CreateSessionWithNullInitData) {
+  EXPECT_CALL(*this,
+              OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+  decryptor_.CreateSession(std::string(),
+                           NULL,
+                           0,
+                           MediaKeys::TEMPORARY_SESSION,
+                           CreateSessionPromise(RESOLVED));
 }
 
-TEST_F(AesDecryptorTest, NormalDecryption) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
-  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, no_subsample_entries_);
-  DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
+TEST_F(AesDecryptorTest, MultipleCreateSession) {
+  EXPECT_CALL(*this,
+              OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+  decryptor_.CreateSession(std::string(),
+                           NULL,
+                           0,
+                           MediaKeys::TEMPORARY_SESSION,
+                           CreateSessionPromise(RESOLVED));
+
+  EXPECT_CALL(*this,
+              OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+  decryptor_.CreateSession(std::string(),
+                           NULL,
+                           0,
+                           MediaKeys::TEMPORARY_SESSION,
+                           CreateSessionPromise(RESOLVED));
+
+  EXPECT_CALL(*this,
+              OnSessionMessage(IsNotEmpty(), IsEmpty(), GURL::EmptyGURL()));
+  decryptor_.CreateSession(std::string(),
+                           NULL,
+                           0,
+                           MediaKeys::TEMPORARY_SESSION,
+                           CreateSessionPromise(RESOLVED));
 }
 
-TEST_F(AesDecryptorTest, DecryptionWithOffset) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+TEST_F(AesDecryptorTest, NormalDecryption) {
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 23, no_subsample_entries_);
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
 TEST_F(AesDecryptorTest, UnencryptedFrame) {
   // An empty iv string signals that the frame is unencrypted.
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      original_data_, key_id_, std::vector<uint8>(), 0, no_subsample_entries_);
+      original_data_, key_id_, std::vector<uint8>(), no_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
 TEST_F(AesDecryptorTest, WrongKey) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kWrongKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, no_subsample_entries_);
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
 }
 
 TEST_F(AesDecryptorTest, NoKey) {
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, no_subsample_entries_);
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
   EXPECT_CALL(*this, BufferDecrypted(AesDecryptor::kNoKey, IsNull()));
   decryptor_.Decrypt(Decryptor::kVideo, encrypted_buffer, decrypt_cb_);
 }
 
 TEST_F(AesDecryptorTest, KeyReplacement) {
-  GenerateKeyRequest(key_id_);
+  std::string session_id = CreateSession(key_id_);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, no_subsample_entries_);
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
 
-  AddKeyAndExpect(kWrongKeyAsJWK, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kWrongKeyAsJWK, RESOLVED);
   ASSERT_NO_FATAL_FAILURE(DecryptAndExpect(
       encrypted_buffer, original_data_, DATA_MISMATCH));
 
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   ASSERT_NO_FATAL_FAILURE(
       DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
 }
 
 TEST_F(AesDecryptorTest, WrongSizedKey) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kWrongSizedKeyAsJWK, KEY_ERROR);
-
-  // Repeat for a raw key. Use "-1" to create a wrong sized key.
-  std::vector<uint8> wrong_sized_key(kKey, kKey + arraysize(kKey) - 1);
-  AddRawKeyAndExpect(key_id_, wrong_sized_key, KEY_ERROR);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kWrongSizedKeyAsJWK, REJECTED);
 }
 
 TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 10, no_subsample_entries_);
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
   ASSERT_NO_FATAL_FAILURE(
       DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
 
-  AddKeyAndExpect(kKey2AsJWK, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kKey2AsJWK, RESOLVED);
 
   // The first key is still available after we added a second key.
   ASSERT_NO_FATAL_FAILURE(
@@ -414,7 +551,6 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
                          kEncryptedData2 + arraysize(kEncryptedData2)),
       std::vector<uint8>(kKeyId2, kKeyId2 + arraysize(kKeyId2)),
       std::vector<uint8>(kIv2, kIv2 + arraysize(kIv2)),
-      30,
       no_subsample_entries_);
   ASSERT_NO_FATAL_FAILURE(DecryptAndExpect(
       encrypted_buffer,
@@ -424,43 +560,43 @@ TEST_F(AesDecryptorTest, MultipleKeysAndFrames) {
 }
 
 TEST_F(AesDecryptorTest, CorruptedIv) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<uint8> bad_iv = iv_;
   bad_iv[1]++;
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, bad_iv, 0, no_subsample_entries_);
+      encrypted_data_, key_id_, bad_iv, no_subsample_entries_);
 
   DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
 }
 
 TEST_F(AesDecryptorTest, CorruptedData) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<uint8> bad_data = encrypted_data_;
   bad_data[1]++;
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      bad_data, key_id_, iv_, 0, no_subsample_entries_);
+      bad_data, key_id_, iv_, no_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
 }
 
 TEST_F(AesDecryptorTest, EncryptedAsUnencryptedFailure) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, std::vector<uint8>(), 0, no_subsample_entries_);
+      encrypted_data_, key_id_, std::vector<uint8>(), no_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
 }
 
 TEST_F(AesDecryptorTest, SubsampleDecryption) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      subsample_encrypted_data_, key_id_, iv_, 0, normal_subsample_entries_);
+      subsample_encrypted_data_, key_id_, iv_, normal_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
@@ -468,29 +604,29 @@ TEST_F(AesDecryptorTest, SubsampleDecryption) {
 // expect to encounter this in the wild, but since the DecryptConfig doesn't
 // disallow such a configuration, it should be covered.
 TEST_F(AesDecryptorTest, SubsampleDecryptionWithOffset) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      subsample_encrypted_data_, key_id_, iv_, 23, normal_subsample_entries_);
+      subsample_encrypted_data_, key_id_, iv_, normal_subsample_entries_);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
 TEST_F(AesDecryptorTest, SubsampleWrongSize) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<SubsampleEntry> subsample_entries_wrong_size(
       kSubsampleEntriesWrongSize,
       kSubsampleEntriesWrongSize + arraysize(kSubsampleEntriesWrongSize));
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      subsample_encrypted_data_, key_id_, iv_, 0, subsample_entries_wrong_size);
+      subsample_encrypted_data_, key_id_, iv_, subsample_entries_wrong_size);
   DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH);
 }
 
 TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<SubsampleEntry> subsample_entries_invalid_total_size(
       kSubsampleEntriesInvalidTotalSize,
@@ -498,51 +634,134 @@ TEST_F(AesDecryptorTest, SubsampleInvalidTotalSize) {
           arraysize(kSubsampleEntriesInvalidTotalSize));
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      subsample_encrypted_data_, key_id_, iv_, 0,
+      subsample_encrypted_data_, key_id_, iv_,
       subsample_entries_invalid_total_size);
   DecryptAndExpect(encrypted_buffer, original_data_, DECRYPT_ERROR);
 }
 
 // No cypher bytes in any of the subsamples.
 TEST_F(AesDecryptorTest, SubsampleClearBytesOnly) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<SubsampleEntry> clear_only_subsample_entries(
       kSubsampleEntriesClearOnly,
       kSubsampleEntriesClearOnly + arraysize(kSubsampleEntriesClearOnly));
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      original_data_, key_id_, iv_, 0, clear_only_subsample_entries);
+      original_data_, key_id_, iv_, clear_only_subsample_entries);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
 // No clear bytes in any of the subsamples.
 TEST_F(AesDecryptorTest, SubsampleCypherBytesOnly) {
-  GenerateKeyRequest(key_id_);
-  AddKeyAndExpect(kKeyAsJWK, KEY_ADDED);
+  std::string session_id = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
 
   std::vector<SubsampleEntry> cypher_only_subsample_entries(
       kSubsampleEntriesCypherOnly,
       kSubsampleEntriesCypherOnly + arraysize(kSubsampleEntriesCypherOnly));
 
   scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, cypher_only_subsample_entries);
+      encrypted_data_, key_id_, iv_, cypher_only_subsample_entries);
   DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
 }
 
+TEST_F(AesDecryptorTest, CloseSession) {
+  std::string session_id = CreateSession(key_id_);
+  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
+
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+  CloseSession(session_id);
+}
+
+TEST_F(AesDecryptorTest, RemoveSession) {
+  // TODO(jrummell): Clean this up when the prefixed API is removed.
+  // http://crbug.com/249976.
+  std::string session_id = CreateSession(key_id_);
+  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
+
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+  RemoveSession(session_id);
+}
+
+TEST_F(AesDecryptorTest, NoKeyAfterCloseSession) {
+  std::string session_id = CreateSession(key_id_);
+  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
+
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+  CloseSession(session_id);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, NO_KEY));
+}
+
+TEST_F(AesDecryptorTest, LatestKeyUsed) {
+  std::string session_id1 = CreateSession(key_id_);
+  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
+
+  // Add alternate key, buffer should not be decoded properly.
+  UpdateSessionAndExpect(session_id1, kKeyAlternateAsJWK, RESOLVED);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH));
+
+  // Create a second session with a correct key value for key_id_.
+  std::string session_id2 = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id2, kKeyAsJWK, RESOLVED);
+
+  // Should be able to decode with latest key.
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+}
+
+TEST_F(AesDecryptorTest, LatestKeyUsedAfterCloseSession) {
+  std::string session_id1 = CreateSession(key_id_);
+  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
+      encrypted_data_, key_id_, iv_, no_subsample_entries_);
+  UpdateSessionAndExpect(session_id1, kKeyAsJWK, RESOLVED);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+
+  // Create a second session with a different key value for key_id_.
+  std::string session_id2 = CreateSession(key_id_);
+  UpdateSessionAndExpect(session_id2, kKeyAlternateAsJWK, RESOLVED);
+
+  // Should not be able to decode with new key.
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, DATA_MISMATCH));
+
+  // Close second session, should revert to original key.
+  CloseSession(session_id2);
+  ASSERT_NO_FATAL_FAILURE(
+      DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS));
+}
+
 TEST_F(AesDecryptorTest, JWKKey) {
+  std::string session_id = CreateSession(key_id_);
+
   // Try a simple JWK key (i.e. not in a set)
-  const std::string key1 =
+  const std::string kJwkSimple =
       "{"
       "  \"kty\": \"oct\","
       "  \"kid\": \"AAECAwQFBgcICQoLDA0ODxAREhM\","
       "  \"k\": \"FBUWFxgZGhscHR4fICEiIw\""
       "}";
-  AddKeyAndExpect(key1, KEY_ERROR);
+  UpdateSessionAndExpect(session_id, kJwkSimple, REJECTED);
 
   // Try a key list with multiple entries.
-  const std::string key2 =
+  const std::string kJwksMultipleEntries =
       "{"
       "  \"keys\": ["
       "    {"
@@ -557,42 +776,41 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key2, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kJwksMultipleEntries, RESOLVED);
 
   // Try a key with no spaces and some \n plus additional fields.
-  const std::string key3 =
+  const std::string kJwksNoSpaces =
       "\n\n{\"something\":1,\"keys\":[{\n\n\"kty\":\"oct\",\"alg\":\"A128KW\","
       "\"kid\":\"AAECAwQFBgcICQoLDA0ODxAREhM\",\"k\":\"GawgguFyGrWKav7AX4VKUg"
       "\",\"foo\":\"bar\"}]}\n\n";
-  AddKeyAndExpect(key3, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kJwksNoSpaces, RESOLVED);
 
   // Try some non-ASCII characters.
-  AddKeyAndExpect("This is not ASCII due to \xff\xfe\xfd in it.", KEY_ERROR);
+  UpdateSessionAndExpect(
+      session_id, "This is not ASCII due to \xff\xfe\xfd in it.", REJECTED);
 
   // Try a badly formatted key. Assume that the JSON parser is fully tested,
   // so we won't try a lot of combinations. However, need a test to ensure
   // that the code doesn't crash if invalid JSON received.
-  AddKeyAndExpect("This is not a JSON key.", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "This is not a JSON key.", REJECTED);
 
   // Try passing some valid JSON that is not a dictionary at the top level.
-  AddKeyAndExpect("40", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "40", REJECTED);
 
   // Try an empty dictionary.
-  AddKeyAndExpect("{ }", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "{ }", REJECTED);
 
   // Try an empty 'keys' dictionary.
-  AddKeyAndExpect("{ \"keys\": [] }", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "{ \"keys\": [] }", REJECTED);
 
   // Try with 'keys' not a dictionary.
-  AddKeyAndExpect("{ \"keys\":\"1\" }", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "{ \"keys\":\"1\" }", REJECTED);
 
   // Try with 'keys' a list of integers.
-  AddKeyAndExpect("{ \"keys\": [ 1, 2, 3 ] }", KEY_ERROR);
+  UpdateSessionAndExpect(session_id, "{ \"keys\": [ 1, 2, 3 ] }", REJECTED);
 
-  // TODO(jrummell): The next 2 tests should fail once checking for padding
-  // characters is enabled.
-  // Try a key with padding(=) at end of base64 string.
-  const std::string key4 =
+  // Try padding(=) at end of 'k' base64 string.
+  const std::string kJwksWithPaddedKey =
       "{"
       "  \"keys\": ["
       "    {"
@@ -602,10 +820,10 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key4, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kJwksWithPaddedKey, REJECTED);
 
-  // Try a key ID with padding(=) at end of base64 string.
-  const std::string key5 =
+  // Try padding(=) at end of 'kid' base64 string.
+  const std::string kJwksWithPaddedKeyId =
       "{"
       "  \"keys\": ["
       "    {"
@@ -615,10 +833,10 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key5, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kJwksWithPaddedKeyId, REJECTED);
 
   // Try a key with invalid base64 encoding.
-  const std::string key6 =
+  const std::string kJwksWithInvalidBase64 =
       "{"
       "  \"keys\": ["
       "    {"
@@ -628,12 +846,12 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key6, KEY_ERROR);
+  UpdateSessionAndExpect(session_id, kJwksWithInvalidBase64, REJECTED);
 
-  // Try a key where no padding is required. 'k' has to be 16 bytes, so it
-  // will always require padding. (Test above using |key2| has 2 'kid's that
-  // require 1 and 2 padding bytes).
-  const std::string key7 =
+  // Try a 3-byte 'kid' where no base64 padding is required.
+  // |kJwksMultipleEntries| above has 2 'kid's that require 1 and 2 padding
+  // bytes. Note that 'k' has to be 16 bytes, so it will always require padding.
+  const std::string kJwksWithNoPadding =
       "{"
       "  \"keys\": ["
       "    {"
@@ -643,10 +861,10 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key7, KEY_ADDED);
+  UpdateSessionAndExpect(session_id, kJwksWithNoPadding, RESOLVED);
 
   // Empty key id.
-  const std::string key8 =
+  const std::string kJwksWithEmptyKeyId =
       "{"
       "  \"keys\": ["
       "    {"
@@ -656,18 +874,30 @@ TEST_F(AesDecryptorTest, JWKKey) {
       "    }"
       "  ]"
       "}";
-  AddKeyAndExpect(key8, KEY_ERROR);
+  UpdateSessionAndExpect(session_id, kJwksWithEmptyKeyId, REJECTED);
+  CloseSession(session_id);
 }
 
-TEST_F(AesDecryptorTest, RawKey) {
-  // Verify that v0.1b keys (raw key) is still supported. Raw keys are
-  // 16 bytes long. Use the undecoded value of |kKey|.
-  GenerateKeyRequest(key_id_);
-  AddRawKeyAndExpect(
-      key_id_, std::vector<uint8>(kKey, kKey + arraysize(kKey)), KEY_ADDED);
-  scoped_refptr<DecoderBuffer> encrypted_buffer = CreateEncryptedBuffer(
-      encrypted_data_, key_id_, iv_, 0, no_subsample_entries_);
-  DecryptAndExpect(encrypted_buffer, original_data_, SUCCESS);
+TEST_F(AesDecryptorTest, GetKeyIds) {
+  std::vector<uint8> key_id1(kKeyId, kKeyId + arraysize(kKeyId));
+  std::vector<uint8> key_id2(kKeyId2, kKeyId2 + arraysize(kKeyId2));
+
+  std::string session_id = CreateSession(key_id_);
+  GetUsableKeyIdsAndExpect(session_id, RESOLVED, 0);
+  EXPECT_FALSE(UsableKeyIdsContains(key_id1));
+  EXPECT_FALSE(UsableKeyIdsContains(key_id2));
+
+  // Add 1 key, verify ID is returned.
+  UpdateSessionAndExpect(session_id, kKeyAsJWK, RESOLVED);
+  GetUsableKeyIdsAndExpect(session_id, RESOLVED, 1);
+  EXPECT_TRUE(UsableKeyIdsContains(key_id1));
+  EXPECT_FALSE(UsableKeyIdsContains(key_id2));
+
+  // Add second key, verify both IDs returned.
+  UpdateSessionAndExpect(session_id, kKey2AsJWK, RESOLVED);
+  GetUsableKeyIdsAndExpect(session_id, RESOLVED, 2);
+  EXPECT_TRUE(UsableKeyIdsContains(key_id1));
+  EXPECT_TRUE(UsableKeyIdsContains(key_id2));
 }
 
 }  // namespace media