// Copyright 2017 The Chromium Authors
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

#include "remoting/protocol/ice_config.h"

#include "base/json/json_reader.h"
#include "base/memory/ptr_util.h"
#include "remoting/proto/remoting/v1/network_traversal_messages.pb.h"
#include "testing/gtest/include/gtest/gtest.h"

namespace remoting::protocol {

TEST(IceConfigTest, ParseValid) {
  const char kTestConfigJson[] =
      "{"
      "  \"lifetimeDuration\": \"43200.000s\","
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"turn:8.8.8.8:19234\","
      "        \"turn:[2001:4860:4860::8888]:333\","
      "        \"turn:[2001:4860:4860::8888]\","
      "        \"turn:[2001:4860:4860::8888]:333?transport=tcp\","
      "        \"turns:the_server.com\","
      "        \"turns:the_server.com?transport=udp\""
      "      ],"
      "      \"username\": \"123\","
      "      \"credential\": \"abc\","
      "      \"maxRateKbps\": 8000.0"
      "    },"
      "    {"
      "      \"urls\": ["
      "        \"stun:stun_server.com:18344\","
      "        \"stun:1.2.3.4\""
      "      ]"
      "    }"
      "  ]"
      "}";

  IceConfig config = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson, base::JSON_PARSE_CHROMIUM_EXTENSIONS));

  // lifetimeDuration in the config is set to 12 hours. Verify that the
  // resulting expiration time is within 20 seconds before 12 hours after now.
  EXPECT_TRUE(base::Time::Now() + base::Hours(12) - base::Seconds(20) <
              config.expiration_time);
  EXPECT_TRUE(config.expiration_time < base::Time::Now() + base::Hours(12));

  ASSERT_EQ(config.turn_servers.size(), 6U);
  EXPECT_TRUE(webrtc::RelayServerConfig("8.8.8.8", 19234, "123", "abc",
                                        webrtc::PROTO_UDP,
                                        false) == config.turn_servers[0]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 333, "123",
                                        "abc", webrtc::PROTO_UDP,
                                        false) == config.turn_servers[1]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 3478, "123",
                                        "abc", webrtc::PROTO_UDP,
                                        false) == config.turn_servers[2]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 333, "123",
                                        "abc", webrtc::PROTO_TCP,
                                        false) == config.turn_servers[3]);
  EXPECT_TRUE(webrtc::RelayServerConfig("the_server.com", 5349, "123", "abc",
                                        webrtc::PROTO_TCP,
                                        true) == config.turn_servers[4]);
  EXPECT_TRUE(webrtc::RelayServerConfig("the_server.com", 5349, "123", "abc",
                                        webrtc::PROTO_UDP,
                                        true) == config.turn_servers[5]);

  ASSERT_EQ(config.stun_servers.size(), 2U);
  EXPECT_EQ(config.stun_servers[0],
            webrtc::SocketAddress("stun_server.com", 18344));
  EXPECT_EQ(config.stun_servers[1], webrtc::SocketAddress("1.2.3.4", 3478));
  EXPECT_EQ(config.max_bitrate_kbps, 8000.0);
}

TEST(IceConfigTest, ParseGetIceConfigResponse) {
  apis::v1::GetIceConfigResponse response;
  response.mutable_lifetime_duration()->set_seconds(43200);
  apis::v1::IceServer* turn_server = response.add_servers();
  turn_server->add_urls("turn:8.8.8.8:19234");
  turn_server->add_urls("turn:[2001:4860:4860::8888]:333");
  turn_server->add_urls("turn:[2001:4860:4860::8888]");
  turn_server->add_urls("turn:[2001:4860:4860::8888]:333?transport=tcp");
  turn_server->add_urls("turns:the_server.com");
  turn_server->add_urls("turns:the_server.com?transport=udp");
  turn_server->set_username("123");
  turn_server->set_credential("abc");
  turn_server->set_max_rate_kbps(8000);
  apis::v1::IceServer* stun_server = response.add_servers();
  stun_server->add_urls("stun:stun_server.com:18344");
  stun_server->add_urls("stun:1.2.3.4");
  IceConfig config = IceConfig::Parse(response);

  // lifetimeDuration in the config is set to 12 hours. Verify that the
  // resulting expiration time is within 20 seconds before 12 hours after now.
  EXPECT_TRUE(base::Time::Now() + base::Hours(12) - base::Seconds(20) <
              config.expiration_time);
  EXPECT_TRUE(config.expiration_time < base::Time::Now() + base::Hours(12));

  ASSERT_EQ(config.turn_servers.size(), 6U);
  EXPECT_TRUE(webrtc::RelayServerConfig("8.8.8.8", 19234, "123", "abc",
                                        webrtc::PROTO_UDP,
                                        false) == config.turn_servers[0]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 333, "123",
                                        "abc", webrtc::PROTO_UDP,
                                        false) == config.turn_servers[1]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 3478, "123",
                                        "abc", webrtc::PROTO_UDP,
                                        false) == config.turn_servers[2]);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 333, "123",
                                        "abc", webrtc::PROTO_TCP,
                                        false) == config.turn_servers[3]);
  EXPECT_TRUE(webrtc::RelayServerConfig("the_server.com", 5349, "123", "abc",
                                        webrtc::PROTO_TCP,
                                        true) == config.turn_servers[4]);
  EXPECT_TRUE(webrtc::RelayServerConfig("the_server.com", 5349, "123", "abc",
                                        webrtc::PROTO_UDP,
                                        true) == config.turn_servers[5]);

  ASSERT_EQ(config.stun_servers.size(), 2U);
  EXPECT_EQ(webrtc::SocketAddress("stun_server.com", 18344),
            config.stun_servers[0]);
  EXPECT_EQ(webrtc::SocketAddress("1.2.3.4", 3478), config.stun_servers[1]);
  EXPECT_EQ(8000.0, config.max_bitrate_kbps);
}

TEST(IceConfigTest, ParseDataEnvelope) {
  const char kTestConfigJson[] =
      "{\"data\":{"
      "  \"lifetimeDuration\": \"43200.000s\","
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ]"
      "    }"
      "  ]"
      "}}";

  IceConfig config = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson, base::JSON_PARSE_CHROMIUM_EXTENSIONS));

  ASSERT_EQ(config.stun_servers.size(), 1U);
  EXPECT_EQ(webrtc::SocketAddress("1.2.3.4", 3478), config.stun_servers[0]);
}

// Verify that we can still proceed if some servers cannot be parsed.
TEST(IceConfigTest, ParsePartiallyInvalid) {
  const char kTestConfigJson[] =
      "{"
      "  \"lifetimeDuration\": \"43200.000s\","
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"InvalidURL\","
      "        \"turn:[2001:4860:4860::8888]:333\""
      "      ],"
      "      \"username\": \"123\","
      "      \"credential\": \"abc\""
      "    },"
      "    \"42\""
      "  ]"
      "}";

  IceConfig config = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson, base::JSON_PARSE_CHROMIUM_EXTENSIONS));

  // Config should be already expired because it couldn't be parsed.
  EXPECT_TRUE(config.expiration_time <= base::Time::Now());

  ASSERT_EQ(config.turn_servers.size(), 1U);
  EXPECT_TRUE(webrtc::RelayServerConfig("2001:4860:4860::8888", 333, "123",
                                        "abc", webrtc::PROTO_UDP,
                                        false) == config.turn_servers[0]);
}

TEST(IceConfigTest, InvalidConfig) {
  IceConfig config = IceConfig::Parse(base::DictValue());
  EXPECT_TRUE(config.is_null());
}

TEST(IceConfigTest, UnspecifiedMaxRate_IsZero) {
  const char kTestConfigJson[] =
      "{"
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ]"
      "    }"
      "  ]"
      "}";

  IceConfig config = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson, base::JSON_PARSE_CHROMIUM_EXTENSIONS));
  EXPECT_EQ(config.max_bitrate_kbps, 0);
}

TEST(IceConfigTest, OneSpecifiedMaxRate_IsUsed) {
  const char kTestConfigJson1[] =
      "{"
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ],"
      "      \"maxRateKbps\": 1000.0"
      "    },"
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ]"
      "    }"
      "  ]"
      "}";

  IceConfig config1 = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson1, base::JSON_PARSE_CHROMIUM_EXTENSIONS));
  EXPECT_EQ(config1.max_bitrate_kbps, 1000);

  const char kTestConfigJson2[] =
      "{"
      "  \"iceServers\": ["
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ]"
      "    },"
      "    {"
      "      \"urls\": ["
      "        \"stun:1.2.3.4\""
      "      ],"
      "      \"maxRateKbps\": 2000.0"
      "    }"
      "  ]"
      "}";

  IceConfig config2 = IceConfig::Parse(*base::JSONReader::ReadDict(
      kTestConfigJson2, base::JSON_PARSE_CHROMIUM_EXTENSIONS));
  EXPECT_EQ(config2.max_bitrate_kbps, 2000);
}

}  // namespace remoting::protocol
