You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@trafficserver.apache.org by zw...@apache.org on 2020/09/03 19:08:58 UTC

[trafficserver] 01/05: Convert Mime and URL unit tests in proxy/hdrs to Catch.

This is an automated email from the ASF dual-hosted git repository.

zwoop pushed a commit to branch 9.0.x
in repository https://gitbox.apache.org/repos/asf/trafficserver.git

commit 40e9d411229ddab4860c9287cc48abee500dc414
Author: Walter Karas <wk...@verizonmedia.com>
AuthorDate: Wed Mar 18 13:01:13 2020 -0500

    Convert Mime and URL unit tests in proxy/hdrs to Catch.
    
    (cherry picked from commit 051661e1e9ff3a3d74250f31f0a72da414484b0e)
    
     Conflicts:
    	proxy/hdrs/test_mime.cc
---
 proxy/hdrs/Makefile.am             |  17 +--
 proxy/hdrs/URL.cc                  |  85 ++-----------
 proxy/hdrs/test_mime.cc            | 104 ----------------
 proxy/hdrs/unit_tests/test_URL.cc  |  95 ++++++++++++++
 proxy/hdrs/unit_tests/test_mime.cc | 249 +++++++++++++++++++++++++++++++++++++
 5 files changed, 356 insertions(+), 194 deletions(-)

diff --git a/proxy/hdrs/Makefile.am b/proxy/hdrs/Makefile.am
index 950dd2b..7fcd248 100644
--- a/proxy/hdrs/Makefile.am
+++ b/proxy/hdrs/Makefile.am
@@ -60,7 +60,6 @@ load_http_hdr_LDADD = -L. -lhdrs \
 	$(top_builddir)/src/tscpp/util/libtscpputil.la
 
 check_PROGRAMS = \
-	test_mime \
 	test_proxy_hdrs \
 	test_hdr_heap \
 	test_Huffmancode \
@@ -68,25 +67,15 @@ check_PROGRAMS = \
 
 TESTS = $(check_PROGRAMS)
 
-test_mime_LDADD = -L. -lhdrs \
-	$(top_builddir)/src/tscore/libtscore.la \
-	$(top_builddir)/src/tscpp/util/libtscpputil.la \
-	$(top_builddir)/iocore/eventsystem/libinkevent.a \
-	$(top_builddir)/lib/records/librecords_p.a \
-	$(top_builddir)/mgmt/libmgmt_p.la \
-	$(top_builddir)/proxy/shared/libUglyLogStubs.a \
-	@HWLOC_LIBS@ \
-	@LIBCAP@
-
-test_mime_SOURCES = test_mime.cc
-
 test_proxy_hdrs_CPPFLAGS = $(AM_CPPFLAGS) \
 	-I$(abs_top_srcdir)/tests/include
 
 test_proxy_hdrs_SOURCES = \
 	unit_tests/unit_test_main.cc \
 	unit_tests/test_Hdrs.cc \
-	unit_tests/test_HdrUtils.cc
+	unit_tests/test_HdrUtils.cc \
+	unit_tests/test_URL.cc \
+	unit_tests/test_mime.cc
 
 test_proxy_hdrs_LDADD = \
 	$(top_builddir)/src/tscore/libtscore.la \
diff --git a/proxy/hdrs/URL.cc b/proxy/hdrs/URL.cc
index ad100a5..c528ee8 100644
--- a/proxy/hdrs/URL.cc
+++ b/proxy/hdrs/URL.cc
@@ -1160,11 +1160,16 @@ url_parse_scheme(HdrHeap *heap, URLImpl *url, const char **start, const char *en
   return PARSE_RESULT_ERROR; // no non-whitespace found
 }
 
+// This implementation namespace is necessary because this function is tested by a Catch unit test
+// in another source file.
+//
+namespace UrlImpl
+{
 /**
  *  This method will return TRUE if the uri is strictly compliant with
  *  RFC 3986 and it will return FALSE if not.
  */
-static bool
+bool
 url_is_strictly_compliant(const char *start, const char *end)
 {
   for (const char *i = start; i < end; ++i) {
@@ -1176,6 +1181,9 @@ url_is_strictly_compliant(const char *start, const char *end)
   return true;
 }
 
+} // namespace UrlImpl
+using namespace UrlImpl;
+
 ParseResult
 url_parse(HdrHeap *heap, URLImpl *url, const char **start, const char *end, bool copy_strings_p, bool strict_uri_parsing)
 {
@@ -1801,78 +1809,3 @@ url_host_CryptoHash_get(URLImpl *url, CryptoHash *hash)
   ctx.update(&port, sizeof(port));
   ctx.finalize(*hash);
 }
-
-/*-------------------------------------------------------------------------
- * Regression tests
-  -------------------------------------------------------------------------*/
-#if TS_HAS_TESTS
-#include "tscore/TestBox.h"
-
-const static struct {
-  const char *const text;
-  bool valid;
-} http_validate_hdr_field_test_case[] = {{"yahoo", true},
-                                         {"yahoo.com", true},
-                                         {"yahoo.wow.com", true},
-                                         {"yahoo.wow.much.amaze.com", true},
-                                         {"209.131.52.50", true},
-                                         {"192.168.0.1", true},
-                                         {"localhost", true},
-                                         {"3ffe:1900:4545:3:200:f8ff:fe21:67cf", true},
-                                         {"fe80:0:0:0:200:f8ff:fe21:67cf", true},
-                                         {"fe80::200:f8ff:fe21:67cf", true},
-                                         {"<svg onload=alert(1)>", false}, // Sample host header XSS attack
-                                         {"jlads;f8-9349*(D&F*D(234jD*(FSD*(VKLJ#(*$@()#$)))))", false},
-                                         {"\"\t\n", false},
-                                         {"!@#$%^ &*(*&^%$#@#$%^&*(*&^%$#))", false},
-                                         {":):(:O!!!!!!", false}};
-
-REGRESSION_TEST(VALIDATE_HDR_FIELD)(RegressionTest *t, int /* level ATS_UNUSED */, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  for (auto i : http_validate_hdr_field_test_case) {
-    const char *const txt = i.text;
-    box.check(validate_host_name({txt}) == i.valid, "Validation of FQDN (host) header: \"%s\", expected %s, but not", txt,
-              (i.valid ? "true" : "false"));
-  }
-}
-
-REGRESSION_TEST(ParseRules_strict_URI)(RegressionTest *t, int /* level ATS_UNUSED */, int *pstatus)
-{
-  const struct {
-    const char *const uri;
-    bool valid;
-  } http_strict_uri_parsing_test_case[] = {{"/home", true},
-                                           {"/path/data?key=value#id", true},
-                                           {"/ABCDEFGHIJKLMNOPQRSTUVWXYZ", true},
-                                           {"/abcdefghijklmnopqrstuvwxyz", true},
-                                           {"/0123456789", true},
-                                           {":/?#[]@", true},
-                                           {"!$&'()*+,;=", true},
-                                           {"-._~", true},
-                                           {"%", true},
-                                           {"\n", false},
-                                           {"\"", false},
-                                           {"<", false},
-                                           {">", false},
-                                           {"\\", false},
-                                           {"^", false},
-                                           {"`", false},
-                                           {"{", false},
-                                           {"|", false},
-                                           {"}", false},
-                                           {"é", false}};
-
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  for (auto i : http_strict_uri_parsing_test_case) {
-    const char *const uri = i.uri;
-    box.check(url_is_strictly_compliant(uri, uri + strlen(uri)) == i.valid, "Strictly parse URI: \"%s\", expected %s, but not", uri,
-              (i.valid ? "true" : "false"));
-  }
-}
-
-#endif // TS_HAS_TESTS
diff --git a/proxy/hdrs/test_mime.cc b/proxy/hdrs/test_mime.cc
deleted file mode 100644
index eba287d..0000000
--- a/proxy/hdrs/test_mime.cc
+++ /dev/null
@@ -1,104 +0,0 @@
-/** @file
-
-  A brief file description
-
-  @section license License
-
-  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 "tscore/TestBox.h"
-#include "I_EventSystem.h"
-#include "MIME.h"
-
-REGRESSION_TEST(MIME)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
-{
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  MIMEField *field;
-  MIMEHdr hdr;
-  hdr.create(NULL);
-
-  hdr.field_create("Test1", 5);
-  hdr.field_create("Test2", 5);
-  hdr.field_create("Test3", 5);
-  hdr.field_create("Test4", 5);
-  field = hdr.field_create("Test5", 5);
-
-  box.check(hdr.m_mime->m_first_fblock.contains(field), "The field block doesn't contain the field but it should");
-  box.check(!hdr.m_mime->m_first_fblock.contains(field + (1L << 32)), "The field block contains the field but it shouldn't");
-
-  int slot_num = mime_hdr_field_slotnum(hdr.m_mime, field);
-  box.check(slot_num == 4, "Slot number is %d but should be 4", slot_num);
-
-  slot_num = mime_hdr_field_slotnum(hdr.m_mime, field + (1L << 32));
-  box.check(slot_num == -1, "Slot number is %d but should be -1", slot_num);
-
-  hdr.destroy();
-}
-
-REGRESSION_TEST(MIME_PARSERS)(RegressionTest *t, int /* atype ATS_UNUSED */, int *pstatus)
-{
-  const char *end;
-  int value;
-  TestBox box(t, pstatus);
-  box = REGRESSION_TEST_PASSED;
-
-  std::vector<std::pair<const char *, int>> tests = {{"0", 0},
-                                                     {"1234", 1234},
-                                                     {"-1234", -1234},
-                                                     {"2147483647", 2147483647},
-                                                     {"-2147483648", 2147483648},
-                                                     {"2147483648", INT_MAX},
-                                                     {"-2147483649", INT_MIN},
-                                                     {"2147483647", INT_MAX},
-                                                     {"-2147483648", INT_MIN},
-                                                     {"999999999999", INT_MAX},
-                                                     {"-999999999999", INT_MIN}};
-
-  for (const auto &it : tests) {
-    auto [buf, val] = it;
-
-    end = buf + strlen(buf);
-    box.check(mime_parse_int(buf, end) == val, "Failed mime_parse_int");
-    box.check(mime_parse_integer(buf, end, &value), "Failed mime_parse_integer call");
-    box.check(value == val, "Failed mime_parse_integer value");
-  }
-
-  // Also check the date parser, which relies heavily on the mime_parse_integer() function
-  const char *date1 = "Sun, 05 Dec 1999 08:49:37 GMT";
-  const char *date2 = "Sunday, 05-Dec-1999 08:49:37 GMT";
-
-  int d1 = mime_parse_date(date1, date1 + strlen(date1));
-  int d2 = mime_parse_date(date2, date2 + strlen(date2));
-
-  box.check(d1 == d2, "Failed mime_parse_date");
-
-  printf("Date1: %d\n", d1);
-  printf("Date2: %d\n", d2);
-}
-
-int
-main(int argc, const char **argv)
-{
-  Thread *main_thread = new EThread();
-  main_thread->set_specific();
-  mime_init();
-
-  return RegressionTest::main(argc, argv, REGRESSION_TEST_QUICK);
-}
diff --git a/proxy/hdrs/unit_tests/test_URL.cc b/proxy/hdrs/unit_tests/test_URL.cc
new file mode 100644
index 0000000..9ebcd9d
--- /dev/null
+++ b/proxy/hdrs/unit_tests/test_URL.cc
@@ -0,0 +1,95 @@
+/** @file
+
+   Catch-based unit tests for URL
+
+   @section license License
+
+   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 <cstdio>
+
+#include "catch.hpp"
+
+#include "URL.h"
+
+TEST_CASE("ValidateURL", "[proxy][validurl]")
+{
+  static const struct {
+    const char *const text;
+    bool valid;
+  } http_validate_hdr_field_test_case[] = {{"yahoo", true},
+                                           {"yahoo.com", true},
+                                           {"yahoo.wow.com", true},
+                                           {"yahoo.wow.much.amaze.com", true},
+                                           {"209.131.52.50", true},
+                                           {"192.168.0.1", true},
+                                           {"localhost", true},
+                                           {"3ffe:1900:4545:3:200:f8ff:fe21:67cf", true},
+                                           {"fe80:0:0:0:200:f8ff:fe21:67cf", true},
+                                           {"fe80::200:f8ff:fe21:67cf", true},
+                                           {"<svg onload=alert(1)>", false}, // Sample host header XSS attack
+                                           {"jlads;f8-9349*(D&F*D(234jD*(FSD*(VKLJ#(*$@()#$)))))", false},
+                                           {"\"\t\n", false},
+                                           {"!@#$%^ &*(*&^%$#@#$%^&*(*&^%$#))", false},
+                                           {":):(:O!!!!!!", false}};
+  for (auto i : http_validate_hdr_field_test_case) {
+    const char *const txt = i.text;
+    if (validate_host_name({txt}) != i.valid) {
+      std::printf("Validation of FQDN (host) header: \"%s\", expected %s, but not\n", txt, (i.valid ? "true" : "false"));
+      CHECK(false);
+    }
+  }
+}
+
+namespace UrlImpl
+{
+bool url_is_strictly_compliant(const char *start, const char *end);
+}
+using namespace UrlImpl;
+
+TEST_CASE("ParseRulesStrictURI", "[proxy][parseuri]")
+{
+  const struct {
+    const char *const uri;
+    bool valid;
+  } http_strict_uri_parsing_test_case[] = {{"/home", true},
+                                           {"/path/data?key=value#id", true},
+                                           {"/ABCDEFGHIJKLMNOPQRSTUVWXYZ", true},
+                                           {"/abcdefghijklmnopqrstuvwxyz", true},
+                                           {"/0123456789", true},
+                                           {":/?#[]@", true},
+                                           {"!$&'()*+,;=", true},
+                                           {"-._~", true},
+                                           {"%", true},
+                                           {"\n", false},
+                                           {"\"", false},
+                                           {"<", false},
+                                           {">", false},
+                                           {"\\", false},
+                                           {"^", false},
+                                           {"`", false},
+                                           {"{", false},
+                                           {"|", false},
+                                           {"}", false},
+                                           {"é", false}};
+
+  for (auto i : http_strict_uri_parsing_test_case) {
+    const char *const uri = i.uri;
+    if (url_is_strictly_compliant(uri, uri + strlen(uri)) != i.valid) {
+      std::printf("Strictly parse URI: \"%s\", expected %s, but not\n", uri, (i.valid ? "true" : "false"));
+      CHECK(false);
+    }
+  }
+}
diff --git a/proxy/hdrs/unit_tests/test_mime.cc b/proxy/hdrs/unit_tests/test_mime.cc
new file mode 100644
index 0000000..0ad7038
--- /dev/null
+++ b/proxy/hdrs/unit_tests/test_mime.cc
@@ -0,0 +1,249 @@
+/** @file
+
+  A brief file description
+
+  @section license License
+
+  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 <cstdio>
+
+#include "catch.hpp"
+
+#include "I_EventSystem.h"
+#include "MIME.h"
+
+TEST_CASE("Mime", "[proxy][mime]")
+{
+  MIMEField *field;
+  MIMEHdr hdr;
+  hdr.create(NULL);
+
+  hdr.field_create("Test1", 5);
+  hdr.field_create("Test2", 5);
+  hdr.field_create("Test3", 5);
+  hdr.field_create("Test4", 5);
+  field = hdr.field_create("Test5", 5);
+
+  if (!hdr.m_mime->m_first_fblock.contains(field)) {
+    std::printf("The field block doesn't contain the field but it should\n");
+    CHECK(false);
+  }
+  if (hdr.m_mime->m_first_fblock.contains(field + (1L << 32))) {
+    std::printf("The field block contains the field but it shouldn't\n");
+    CHECK(false);
+  }
+
+  int slot_num = mime_hdr_field_slotnum(hdr.m_mime, field);
+  if (slot_num != 4) {
+    std::printf("Slot number is %d but should be 4\n", slot_num);
+    CHECK(false);
+  }
+
+  slot_num = mime_hdr_field_slotnum(hdr.m_mime, field + (1L << 32));
+  if (slot_num != -1) {
+    std::printf("Slot number is %d but should be -1\n", slot_num);
+    CHECK(false);
+  }
+
+  hdr.destroy();
+}
+
+TEST_CASE("MimeGetHostPortValues", "[proxy][mimeport]")
+{
+  MIMEHdr hdr;
+  hdr.create(NULL);
+
+  const char *header_value;
+  const char *host;
+  int host_len;
+  const char *port;
+  int port_len;
+
+  header_value = "host";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 4) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "host", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 0) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (port != nullptr) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  header_value = "host:";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 4) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "host", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 0) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (port != nullptr) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  header_value = "[host]";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 6) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "[host]", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 0) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (port != nullptr) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  header_value = "host:port";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 4) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "host", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 4) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(port, "port", port_len) != 0) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  header_value = "[host]:port";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 6) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "[host]", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 4) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(port, "port", port_len) != 0) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  header_value = "[host]:";
+  hdr.value_set("Host", 4, header_value, strlen(header_value));
+  hdr.get_host_port_values(&host, &host_len, &port, &port_len);
+  if (host_len != 6) {
+    std::printf("host length doesn't match\n");
+    CHECK(false);
+  }
+  if (strncmp(host, "[host]", host_len) != 0) {
+    std::printf("host string doesn't match\n");
+    CHECK(false);
+  }
+  if (port_len != 0) {
+    std::printf("port length doesn't match\n");
+    CHECK(false);
+  }
+  if (port != nullptr) {
+    std::printf("port string doesn't match\n");
+    CHECK(false);
+  }
+
+  hdr.destroy();
+}
+
+TEST_CASE("MimeParsers", "[proxy][mimeparsers]")
+{
+  const char *end;
+  int value;
+
+  static const std::vector<std::pair<const char *, int>> tests = {{"0", 0},
+                                                                  {"1234", 1234},
+                                                                  {"-1234", -1234},
+                                                                  {"2147483647", 2147483647},
+                                                                  {"-2147483648", 2147483648},
+                                                                  {"2147483648", INT_MAX},
+                                                                  {"-2147483649", INT_MIN},
+                                                                  {"2147483647", INT_MAX},
+                                                                  {"-2147483648", INT_MIN},
+                                                                  {"999999999999", INT_MAX},
+                                                                  {"-999999999999", INT_MIN}};
+
+  for (const auto &it : tests) {
+    auto [buf, val] = it;
+
+    end = buf + strlen(buf);
+    if (mime_parse_int(buf, end) != val) {
+      std::printf("Failed mime_parse_int\n");
+      CHECK(false);
+    }
+    if (!mime_parse_integer(buf, end, &value)) {
+      std::printf("Failed mime_parse_integer call\n");
+      CHECK(false);
+    } else if (value != val) {
+      std::printf("Failed mime_parse_integer value\n");
+      CHECK(false);
+    }
+  }
+
+  // Also check the date parser, which relies heavily on the mime_parse_integer() function
+  const char *date1 = "Sun, 05 Dec 1999 08:49:37 GMT";
+  const char *date2 = "Sunday, 05-Dec-1999 08:49:37 GMT";
+
+  int d1 = mime_parse_date(date1, date1 + strlen(date1));
+  int d2 = mime_parse_date(date2, date2 + strlen(date2));
+
+  if (d1 != d2) {
+    std::printf("Failed mime_parse_date\n");
+    CHECK(false);
+  }
+
+  std::printf("Date1: %d\n", d1);
+  std::printf("Date2: %d\n", d2);
+}