You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@impala.apache.org by ta...@apache.org on 2018/06/22 18:11:17 UTC

[5/8] impala git commit: IMPALA-3307: Add support for IANA time-zone db

http://git-wip-us.apache.org/repos/asf/impala/blob/17749dbc/be/src/exprs/timezone_db-test.cc
----------------------------------------------------------------------
diff --git a/be/src/exprs/timezone_db-test.cc b/be/src/exprs/timezone_db-test.cc
new file mode 100644
index 0000000..b2ef399
--- /dev/null
+++ b/be/src/exprs/timezone_db-test.cc
@@ -0,0 +1,230 @@
+// Licensed to the Apache Software Foundation (ASF) under one
+// or more contributor license agreements.  See the NOTICE file
+// distributed with this work for additional information
+// regarding copyright ownership.  The ASF licenses this file
+// to you under the Apache License, Version 2.0 (the
+// "License"); you may not use this file except in compliance
+// with the License.  You may obtain a copy of the License at
+//
+//   http://www.apache.org/licenses/LICENSE-2.0
+//
+// Unless required by applicable law or agreed to in writing,
+// software distributed under the License is distributed on an
+// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
+// KIND, either express or implied.  See the License for the
+// specific language governing permissions and limitations
+// under the License.
+
+#include "exprs/timezone_db.h"
+#include "testutil/gtest-util.h"
+
+#include "common/names.h"
+
+using std::ios_base;
+
+namespace impala {
+
+class TimezoneDbNamesTest : public testing::Test {
+ protected:
+  void TestValidTimezoneOffset(const string& tz_offset, int64_t expected_offset) {
+    int64_t result;
+    EXPECT_TRUE(TimezoneDatabase::IsTimezoneOffsetValid(tz_offset, &result));
+    EXPECT_EQ(expected_offset, result);
+  }
+
+  void TestInvalidTimezoneOffset(const string& tz_offset) {
+    int64_t result;
+    EXPECT_FALSE(TimezoneDatabase::IsTimezoneOffsetValid(tz_offset, &result));
+  }
+
+  void TestValidTimezoneName(const string& tz_name) {
+    EXPECT_TRUE(TimezoneDatabase::IsTimezoneNameValid(tz_name));
+  }
+
+  void TestInvalidTimezoneName(const string& tz_name) {
+    EXPECT_FALSE(TimezoneDatabase::IsTimezoneNameValid(tz_name));
+  }
+};
+
+TEST_F(TimezoneDbNamesTest, TzOffset) {
+  TestValidTimezoneOffset("0", 0);
+  TestValidTimezoneOffset("+00", 0);
+  TestValidTimezoneOffset("+1", 1);
+  TestValidTimezoneOffset("-1234", -1234);
+  TestValidTimezoneOffset("86399", 86399);
+  TestValidTimezoneOffset("+86399", 86399);
+  TestValidTimezoneOffset("-86399", -86399);
+
+  // Inalid UTC offsets.
+  TestInvalidTimezoneOffset("");
+  TestInvalidTimezoneOffset(".");
+  TestInvalidTimezoneOffset("0.1");
+  TestInvalidTimezoneOffset("PST");
+  TestInvalidTimezoneOffset(":0");
+  TestInvalidTimezoneOffset("0&");
+  // UTC offset has to be less then 24 hours in seconds.
+  TestInvalidTimezoneOffset("86400");
+  TestInvalidTimezoneOffset("-86400");
+}
+
+TEST_F(TimezoneDbNamesTest, TzName) {
+  TestValidTimezoneName("PST");
+  TestValidTimezoneName("PST8PDT");
+  TestValidTimezoneName("UTC+1");
+  TestValidTimezoneName("UTC-10");
+  TestValidTimezoneName("GMT-10:00");
+  TestValidTimezoneName("W-SU");
+  TestValidTimezoneName("Singapore");
+  TestValidTimezoneName("Etc/GMT+5");
+  TestValidTimezoneName("America/Tijuana");
+  TestValidTimezoneName("America/Argentina/San_Jose");
+
+  // Misformatted time-zone names.
+  TestInvalidTimezoneName("");
+  TestInvalidTimezoneName(".");
+  TestInvalidTimezoneName("zone.tab");
+  TestInvalidTimezoneName("/");
+  TestInvalidTimezoneName("/PST");
+  TestInvalidTimezoneName(":GMT-10");
+  TestInvalidTimezoneName("PST8PDT/");
+  TestInvalidTimezoneName("America//Tijuana");
+  TestInvalidTimezoneName("America/Tijuana/");
+
+  // Time-zone name segments must start with uppercase letters.
+  TestInvalidTimezoneName("pST");
+  TestInvalidTimezoneName("pst");
+  TestInvalidTimezoneName("singapore");
+  TestInvalidTimezoneName("america/Tijuana");
+  TestInvalidTimezoneName("America/tijuana");
+  TestInvalidTimezoneName("America/Argentina/san_Jose");
+  TestInvalidTimezoneName("posixrules");
+}
+
+
+class TimezoneDbLoadAliasTest : public testing::Test {
+ protected:
+  virtual void SetUp() {
+    TimezoneDatabase::tz_name_map_["UTC"] =
+        make_shared<Timezone>(TimezoneDatabase::GetUtcTimezone());
+    TimezoneDatabase::tz_name_map_["Etc/GMT"] =
+        make_shared<Timezone>(TimezoneDatabase::GetUtcTimezone());
+    TimezoneDatabase::tz_name_map_["Etc/GMT-0"] =
+        make_shared<Timezone>(TimezoneDatabase::GetUtcTimezone());
+    TimezoneDatabase::tz_name_map_["Zulu"] =
+        make_shared<Timezone>(TimezoneDatabase::GetUtcTimezone());
+  }
+
+  virtual void TearDown() {
+    TimezoneDatabase::tz_name_map_.clear();
+  }
+
+  void TestLoadZoneAliasesSuccess(const string& aliases,
+      const vector<pair<string, string>>& expected_aliases,
+      const vector<pair<string, int>>& expected_offsets) {
+    stringstream ss(aliases, ios_base::in);
+    Status status = TimezoneDatabase::LoadZoneAliases(ss);
+    EXPECT_TRUE(status.ok());
+
+    // Check aliases defined as existing time-zones.
+    for (const auto& alias : expected_aliases) {
+      const Timezone* tz1 = TimezoneDatabase::FindTimezone(alias.first);
+      const Timezone* tz2 = TimezoneDatabase::FindTimezone(alias.second);
+      EXPECT_TRUE(tz1 != nullptr && tz1 == tz2);
+    }
+
+    // Check aliases defined as UTC offsets.
+    cctz::time_point<cctz::sys_seconds> epoch =
+        std::chrono::time_point_cast<cctz::sys_seconds>(
+             std::chrono::system_clock::from_time_t(0));
+    for (const auto& offset : expected_offsets) {
+      const Timezone* tz = TimezoneDatabase::FindTimezone(offset.first);
+      EXPECT_TRUE(tz != nullptr && tz->lookup(epoch).offset == offset.second);
+    }
+  }
+
+  void TestLoadZoneAliasesFailure(const string& aliases,
+      const string& expected_err_msg) {
+    stringstream ss(aliases, ios_base::in);
+    Status status = TimezoneDatabase::LoadZoneAliases(ss);
+    EXPECT_FALSE(status.ok());
+    ASSERT_NE(string::npos, status.msg().msg().find(expected_err_msg));
+  }
+};
+
+TEST_F(TimezoneDbLoadAliasTest, LoadZoneAliases) {
+  TestLoadZoneAliasesSuccess(
+      "# Test time-zone aliases\n"
+      "# First = Zulu   # Entire line is commented out\n"
+      "First = UTC \n"
+      "Second =   Zulu ###  \n"
+      "Second =   UTC  # This line will be skipped: Second is already defined\n"
+      "Third  = Etc/GMT  \n"
+      "Fourth =Etc/GMT-0 \n"
+      "Fourth = 1234   # This line will be skipped: Fourth is already defined\n"
+      "Fifth = ZULU    # This line will be skipped: value is an invalid time-zone name\n"
+      "Fifth  =1234    # Alias defined as UTC offset in seconds\n"
+      "# Aliases may contain non-alphabetic characters\n"
+      "+00:00  = Etc/GMT-0  \n"
+      "Coordinated Universal Time  = UTC\n",
+      { make_pair("First", "UTC"), make_pair("Second", "Zulu"),
+      make_pair("Third", "Etc/GMT"), make_pair("Fourth", "Etc/GMT-0"),
+      make_pair("+00:00", "Etc/GMT-0"),
+      make_pair("Coordinated Universal Time", "UTC") },
+      { make_pair("Fifth", 1234) });
+
+  // Value is commented out.
+  TestLoadZoneAliasesFailure("UTC1= # Zulu\n", "Error in line 1. Missing value.");
+
+  // '=' delimiter is missing.
+  TestLoadZoneAliasesFailure("UTC2  Zulu\n", "Error in line 1. '=' is missing.");
+
+  // Missing alias
+  TestLoadZoneAliasesFailure("   = Zulu\n",
+      "Error in line 1. Time-zone alias name is missing.");
+}
+
+
+class TimezoneDbLoadZoneInfoTest : public testing::Test {
+ protected:
+  void TestLoadZoneInfoSuccess(const string& path) {
+    EXPECT_OK(TimezoneDatabase::LoadZoneInfo(path));
+  }
+
+  void TestFindTimezoneSuccess(const vector<string>& expected_names) {
+    // Check that all the expected time-zones have been loaded.
+    for (const auto& tz_name : expected_names) {
+      ASSERT_NE(nullptr, TimezoneDatabase::FindTimezone(tz_name));
+    }
+  }
+
+  void TestFindTimezoneFailure(const vector<string>& expected_names) {
+    // Check that all the expected time-zones have been loaded.
+    for (const auto& tz_name : expected_names) {
+      ASSERT_EQ(nullptr, TimezoneDatabase::FindTimezone(tz_name));
+    }
+  }
+};
+
+TEST_F(TimezoneDbLoadZoneInfoTest, LoadZoneInfo) {
+  const string& path = Substitute("$0/testdata/tzdb_tiny", getenv("IMPALA_HOME"));
+  TestLoadZoneInfoSuccess(path);
+
+  // Test that timezones containing non-alphabetic characters were loaded successfully.
+  TestFindTimezoneSuccess({ "Etc/GMT+4" });
+
+  // Test that symbolic links are handled properly.
+  // "UTC" is a symbolic link to "Zulu". Both should be loaded.
+  TestFindTimezoneSuccess({ "UTC", "Zulu" });
+  // "America/New_York" and "US/Eastern" are symbolic links to "posixrules". It is
+  // expected that "posixrules" is not loaded, but "America/New_York" and "US/Eastern"
+  // are.
+  TestFindTimezoneFailure({ "posixrules" });
+  TestFindTimezoneSuccess({ "America/New_York", "US/Eastern" });
+
+  // Test that "posix" directory was skipped.
+  TestFindTimezoneFailure({ "posix/UTC" });
+}
+
+}
+
+IMPALA_TEST_MAIN();