summaryrefslogtreecommitdiffstats
path: root/third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc')
-rw-r--r--third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc337
1 files changed, 337 insertions, 0 deletions
diff --git a/third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc b/third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc
new file mode 100644
index 0000000000..b6af420d78
--- /dev/null
+++ b/third_party/libwebrtc/p2p/base/stun_dictionary_unittest.cc
@@ -0,0 +1,337 @@
+/*
+ * Copyright 2020 The WebRTC Project Authors. All rights reserved.
+ *
+ * Use of this source code is governed by a BSD-style license
+ * that can be found in the LICENSE file in the root of the source
+ * tree. An additional intellectual property rights grant can be found
+ * in the file PATENTS. All contributing project authors may
+ * be found in the AUTHORS file in the root of the source tree.
+ */
+
+#include "p2p/base/stun_dictionary.h"
+
+#include <string>
+
+#include "rtc_base/gunit.h"
+#include "rtc_base/logging.h"
+#include "test/gtest.h"
+
+namespace {
+
+void Sync(cricket::StunDictionaryView& dictionary,
+ cricket::StunDictionaryWriter& writer) {
+ int pending = writer.Pending();
+ auto delta = writer.CreateDelta();
+ if (delta == nullptr) {
+ EXPECT_EQ(pending, 0);
+ } else {
+ EXPECT_NE(pending, 0);
+ auto delta_ack = dictionary.ApplyDelta(*delta);
+ if (!delta_ack.ok()) {
+ RTC_LOG(LS_ERROR) << "delta_ack.error(): " << delta_ack.error().message();
+ }
+ EXPECT_TRUE(delta_ack.ok());
+ ASSERT_NE(delta_ack.value().first.get(), nullptr);
+ writer.ApplyDeltaAck(*delta_ack.value().first);
+ EXPECT_FALSE(writer.Pending());
+ }
+}
+
+void XorToggle(cricket::StunByteStringAttribute& attr, size_t byte) {
+ ASSERT_TRUE(attr.length() > byte);
+ uint8_t val = attr.GetByte(byte);
+ uint8_t new_val = val ^ (128 - (byte & 255));
+ attr.SetByte(byte, new_val);
+}
+
+std::unique_ptr<cricket::StunByteStringAttribute> Crop(
+ const cricket::StunByteStringAttribute& attr,
+ int new_length) {
+ auto new_attr =
+ std::make_unique<cricket::StunByteStringAttribute>(attr.type());
+ std::string content = std::string(attr.string_view());
+ content.erase(new_length);
+ new_attr->CopyBytes(content);
+ return new_attr;
+}
+
+} // namespace
+
+namespace cricket {
+
+constexpr int kKey1 = 100;
+
+TEST(StunDictionary, CreateEmptyDictionaryWriter) {
+ StunDictionaryView dictionary;
+ StunDictionaryWriter writer;
+ EXPECT_TRUE(dictionary.empty());
+ EXPECT_TRUE(writer->empty());
+ EXPECT_EQ(writer.Pending(), 0);
+ EXPECT_EQ(writer.CreateDelta().get(), nullptr);
+}
+
+TEST(StunDictionary, SetAndGet) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+ EXPECT_EQ(writer->GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(writer->GetUInt64(kKey1), nullptr);
+ EXPECT_EQ(writer->GetByteString(kKey1), nullptr);
+ EXPECT_EQ(writer->GetAddress(kKey1), nullptr);
+ EXPECT_EQ(writer->GetUInt16List(kKey1), nullptr);
+}
+
+TEST(StunDictionary, SetAndApply) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+
+ StunDictionaryView dictionary;
+ EXPECT_TRUE(dictionary.empty());
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.bytes_stored(), 12);
+}
+
+TEST(StunDictionary, SetSetAndApply) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+ writer.SetUInt32(kKey1)->SetValue(29);
+
+ StunDictionaryView dictionary;
+ EXPECT_TRUE(dictionary.empty());
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 29u);
+ EXPECT_EQ(dictionary.bytes_stored(), 12);
+}
+
+TEST(StunDictionary, SetAndApplyAndSetAndApply) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+
+ StunDictionaryView dictionary;
+ EXPECT_TRUE(dictionary.empty());
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.bytes_stored(), 12);
+
+ writer.SetUInt32(kKey1)->SetValue(29);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 29u);
+ EXPECT_EQ(dictionary.bytes_stored(), 12);
+}
+
+TEST(StunDictionary, ChangeType) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+ EXPECT_EQ(writer->GetUInt32(kKey1)->value(), 27u);
+
+ writer.SetUInt64(kKey1)->SetValue(29);
+ EXPECT_EQ(writer->GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(writer->GetUInt64(kKey1)->value(), 29ull);
+}
+
+TEST(StunDictionary, ChangeTypeApply) {
+ StunDictionaryWriter writer;
+ writer.SetUInt32(kKey1)->SetValue(27);
+ EXPECT_EQ(writer->GetUInt32(kKey1)->value(), 27u);
+
+ StunDictionaryView dictionary;
+ EXPECT_TRUE(dictionary.empty());
+ Sync(dictionary, writer);
+ EXPECT_EQ(writer->GetUInt32(kKey1)->value(), 27u);
+
+ writer.SetUInt64(kKey1)->SetValue(29);
+ EXPECT_EQ(writer->GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(writer->GetUInt64(kKey1)->value(), 29ull);
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1)->value(), 29ull);
+ EXPECT_EQ(dictionary.bytes_stored(), 16);
+}
+
+TEST(StunDictionary, Pending) {
+ StunDictionaryWriter writer;
+ EXPECT_EQ(writer.Pending(), 0);
+ EXPECT_FALSE(writer.Pending(kKey1));
+
+ writer.SetUInt32(kKey1)->SetValue(27);
+ EXPECT_EQ(writer.Pending(), 1);
+ EXPECT_TRUE(writer.Pending(kKey1));
+
+ writer.SetUInt32(kKey1)->SetValue(29);
+ EXPECT_EQ(writer.Pending(), 1);
+ EXPECT_TRUE(writer.Pending(kKey1));
+
+ writer.SetUInt32(kKey1 + 1)->SetValue(31);
+ EXPECT_EQ(writer.Pending(), 2);
+ EXPECT_TRUE(writer.Pending(kKey1));
+ EXPECT_TRUE(writer.Pending(kKey1 + 1));
+
+ StunDictionaryView dictionary;
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(writer.Pending(), 0);
+ EXPECT_FALSE(writer.Pending(kKey1));
+
+ writer.SetUInt32(kKey1)->SetValue(32);
+ EXPECT_EQ(writer.Pending(), 1);
+ EXPECT_TRUE(writer.Pending(kKey1));
+}
+
+TEST(StunDictionary, Delete) {
+ StunDictionaryWriter writer;
+ StunDictionaryView dictionary;
+
+ writer.SetUInt32(kKey1)->SetValue(27);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.bytes_stored(), 12);
+
+ writer.Delete(kKey1);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(dictionary.bytes_stored(), 8);
+
+ writer.Delete(kKey1);
+ EXPECT_EQ(writer.Pending(), 0);
+}
+
+TEST(StunDictionary, MultiWriter) {
+ StunDictionaryWriter writer1;
+ StunDictionaryWriter writer2;
+ StunDictionaryView dictionary;
+
+ writer1.SetUInt32(kKey1)->SetValue(27);
+ Sync(dictionary, writer1);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+
+ writer2.SetUInt32(kKey1 + 1)->SetValue(28);
+ Sync(dictionary, writer2);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1 + 1)->value(), 28u);
+
+ writer1.Delete(kKey1);
+ Sync(dictionary, writer1);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1), nullptr);
+
+ writer2.Delete(kKey1 + 1);
+ Sync(dictionary, writer2);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1 + 1), nullptr);
+}
+
+TEST(StunDictionary, BytesStoredIsCountedCorrectlyAfterMultipleUpdates) {
+ StunDictionaryWriter writer;
+ StunDictionaryView dictionary;
+
+ for (int i = 0; i < 10; i++) {
+ writer.SetUInt32(kKey1)->SetValue(27);
+ writer.SetUInt64(kKey1 + 1)->SetValue(28);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.bytes_stored(), 28);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1)->value(), 28ull);
+ writer.Delete(kKey1);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.bytes_stored(), 24);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1)->value(), 28ull);
+ writer.Delete(kKey1 + 1);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.bytes_stored(), 16);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1), nullptr);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1), nullptr);
+ }
+}
+
+TEST(StunDictionary, MaxBytesStoredCausesErrorOnOverflow) {
+ StunDictionaryWriter writer;
+ StunDictionaryView dictionary;
+
+ dictionary.set_max_bytes_stored(30);
+
+ writer.SetUInt32(kKey1)->SetValue(27);
+ writer.SetUInt64(kKey1 + 1)->SetValue(28);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.bytes_stored(), 28);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1)->value(), 28ull);
+
+ writer.SetByteString(kKey1 + 2)->CopyBytes("k");
+ {
+ auto delta = writer.CreateDelta();
+ auto delta_ack = dictionary.ApplyDelta(*delta);
+ EXPECT_FALSE(delta_ack.ok());
+ }
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1)->value(), 28ull);
+ EXPECT_EQ(dictionary.GetByteString(kKey1 + 2), nullptr);
+
+ writer.Delete(kKey1 + 1);
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1), nullptr);
+ EXPECT_EQ(dictionary.GetByteString(kKey1 + 2)->string_view(), "k");
+}
+
+TEST(StunDictionary, DataTypes) {
+ StunDictionaryWriter writer;
+ StunDictionaryView dictionary;
+
+ rtc::SocketAddress addr("127.0.0.1", 8080);
+
+ writer.SetUInt32(kKey1)->SetValue(27);
+ writer.SetUInt64(kKey1 + 1)->SetValue(28);
+ writer.SetAddress(kKey1 + 2)->SetAddress(addr);
+ writer.SetByteString(kKey1 + 3)->CopyBytes("keso");
+ writer.SetUInt16List(kKey1 + 4)->AddTypeAtIndex(0, 7);
+
+ Sync(dictionary, writer);
+ EXPECT_EQ(dictionary.GetUInt32(kKey1)->value(), 27u);
+ EXPECT_EQ(dictionary.GetUInt64(kKey1 + 1)->value(), 28ull);
+ EXPECT_EQ(dictionary.GetAddress(kKey1 + 2)->GetAddress(), addr);
+ EXPECT_EQ(dictionary.GetByteString(kKey1 + 3)->string_view(), "keso");
+ EXPECT_EQ(dictionary.GetUInt16List(kKey1 + 4)->GetType(0), 7);
+}
+
+TEST(StunDictionary, ParseError) {
+ StunDictionaryWriter writer;
+ StunDictionaryView dictionary;
+
+ rtc::SocketAddress addr("127.0.0.1", 8080);
+
+ writer.SetUInt32(kKey1)->SetValue(27);
+ writer.SetUInt64(kKey1 + 1)->SetValue(28);
+ writer.SetAddress(kKey1 + 2)->SetAddress(addr);
+ writer.SetByteString(kKey1 + 3)->CopyBytes("keso");
+ writer.SetUInt16List(kKey1 + 4)->AddTypeAtIndex(0, 7);
+
+ auto delta = writer.CreateDelta();
+
+ // The first 10 bytes are in the header...
+ // any modification makes parsing fail.
+ for (int i = 0; i < 10; i++) {
+ XorToggle(*delta, i);
+ EXPECT_FALSE(dictionary.ApplyDelta(*delta).ok());
+ XorToggle(*delta, i); // toogle back
+ }
+
+ // Remove bytes from the delta.
+ for (size_t i = 0; i < delta->length(); i++) {
+ // The delta does not contain a footer,
+ // so it it possible to Crop at special values (attribute boundaries)
+ // and apply will still work.
+ const std::vector<int> valid_crop_length = {18, 28, 42, 56, 66, 74};
+ bool valid = std::find(valid_crop_length.begin(), valid_crop_length.end(),
+ i) != valid_crop_length.end();
+ auto cropped_delta = Crop(*delta, i);
+ if (valid) {
+ EXPECT_TRUE(dictionary.ApplyDelta(*cropped_delta).ok());
+ } else {
+ EXPECT_FALSE(dictionary.ApplyDelta(*cropped_delta).ok());
+ }
+ }
+}
+
+} // namespace cricket