Bug 1413999 - Part4: Test case r=dragana
authorKershaw Chang <kechang@mozilla.com>
Wed, 03 Jan 2018 18:59:00 +0200
changeset 449530 d6ad893078b23c1a2c546ca7b1509013fa10e89e
parent 449529 c29cf020715fafc192c31713abc42db87f91dc13
child 449531 f6b74e7c3c0943a212e0d2efd73340b8d2157dbb
push id8527
push userCallek@gmail.com
push dateThu, 11 Jan 2018 21:05:50 +0000
treeherdermozilla-beta@95342d212a7a [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersdragana
bugs1413999
milestone59.0a1
first release with
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
last release without
nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
Bug 1413999 - Part4: Test case r=dragana
netwerk/test/gtest/TestServerTimingHeader.cpp
netwerk/test/gtest/moz.build
netwerk/test/unit/test_header_Server_Timing.js
netwerk/test/unit/xpcshell.ini
new file mode 100644
--- /dev/null
+++ b/netwerk/test/gtest/TestServerTimingHeader.cpp
@@ -0,0 +1,232 @@
+#include "gtest/gtest.h"
+
+#include "mozilla/Unused.h"
+#include "mozilla/net/nsServerTiming.h"
+#include <string>
+#include <vector>
+
+void testServerTimingHeader(const char* headerValue,
+                            std::vector<std::vector<std::string>> expectedResults)
+{
+  nsAutoCString header(headerValue);
+  ServerTimingParser parser(header);
+  parser.Parse();
+
+  nsTArray<nsCOMPtr<nsIServerTiming>> results = parser.TakeServerTimingHeaders();
+
+  ASSERT_EQ(results.Length(), expectedResults.size());
+
+  unsigned i = 0;
+  for (const auto& header : results) {
+    std::vector<std::string> expectedResult(expectedResults[i++]);
+    nsCString name;
+    mozilla::Unused << header->GetName(name);
+    ASSERT_TRUE(name.Equals(expectedResult[0].c_str()));
+
+    double duration;
+    mozilla::Unused << header->GetDuration(&duration);
+    ASSERT_EQ(duration, atof(expectedResult[1].c_str()));
+
+    nsCString description;
+    mozilla::Unused << header->GetDescription(description);
+    ASSERT_TRUE(description.Equals(expectedResult[2].c_str()));
+  }
+}
+
+TEST(TestServerTimingHeader, HeaderParsing) {
+  // Test cases below are copied from
+  // https://cs.chromium.org/chromium/src/third_party/WebKit/Source/platform/network/HTTPParsersTest.cpp
+
+  testServerTimingHeader("", {});
+  testServerTimingHeader("metric", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;dur", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;dur=123.4", {{"metric", "123.4", ""}});
+  testServerTimingHeader("metric;dur=\"123.4\"", {{"metric", "123.4", ""}});
+
+  testServerTimingHeader("metric;desc", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;desc=description",
+                         {{"metric", "0", "description"}});
+  testServerTimingHeader("metric;desc=\"description\"",
+                         {{"metric", "0", "description"}});
+
+  testServerTimingHeader("metric;dur;desc", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;dur=123.4;desc", {{"metric", "123.4", ""}});
+  testServerTimingHeader("metric;dur;desc=description",
+                         {{"metric", "0", "description"}});
+  testServerTimingHeader("metric;dur=123.4;desc=description",
+                         {{"metric", "123.4", "description"}});
+  testServerTimingHeader("metric;desc;dur", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;desc;dur=123.4", {{"metric", "123.4", ""}});
+  testServerTimingHeader("metric;desc=description;dur",
+                         {{"metric", "0", "description"}});
+  testServerTimingHeader("metric;desc=description;dur=123.4",
+                         {{"metric", "123.4", "description"}});
+
+  // special chars in name
+  testServerTimingHeader("aB3!#$%&'*+-.^_`|~",
+                         {{"aB3!#$%&'*+-.^_`|~", "0", ""}});
+
+  // delimiter chars in quoted description
+  testServerTimingHeader("metric;desc=\"descr;,=iption\";dur=123.4",
+                         {{"metric", "123.4", "descr;,=iption"}});
+
+  // whitespace
+  testServerTimingHeader("metric ; ", {{"metric", "0", ""}});
+  testServerTimingHeader("metric , ", {{"metric", "0", ""}});
+  testServerTimingHeader("metric ; dur = 123.4 ; desc = description",
+                         {{"metric", "123.4", "description"}});
+  testServerTimingHeader("metric ; desc = description ; dur = 123.4",
+                         {{"metric", "123.4", "description"}});
+
+  // multiple entries
+  testServerTimingHeader(
+      "metric1;dur=12.3;desc=description1,metric2;dur=45.6;"
+      "desc=description2,metric3;dur=78.9;desc=description3",
+      {{"metric1", "12.3", "description1"},
+       {"metric2", "45.6", "description2"},
+       {"metric3", "78.9", "description3"}});
+  testServerTimingHeader("metric1,metric2 ,metric3, metric4 , metric5",
+                         {{"metric1", "0", ""},
+                          {"metric2", "0", ""},
+                          {"metric3", "0", ""},
+                          {"metric4", "0", ""},
+                          {"metric5", "0", ""}});
+
+  // quoted-strings
+  // metric;desc=\ --> ''
+  testServerTimingHeader("metric;desc=\\", {{"metric", "0", ""}});
+  // metric;desc=" --> ''
+  testServerTimingHeader("metric;desc=\"", {{"metric", "0", ""}});
+  // metric;desc=\\ --> ''
+  testServerTimingHeader("metric;desc=\\\\", {{"metric", "0", ""}});
+  // metric;desc=\" --> ''
+  testServerTimingHeader("metric;desc=\\\"", {{"metric", "0", ""}});
+  // metric;desc="\ --> ''
+  testServerTimingHeader("metric;desc=\"\\", {{"metric", "0", ""}});
+  // metric;desc="" --> ''
+  testServerTimingHeader("metric;desc=\"\"", {{"metric", "0", ""}});
+  // metric;desc=\\\ --> ''
+  testServerTimingHeader("metric;desc=\\\\\\", {{"metric", "0", ""}});
+  // metric;desc=\\" --> ''
+  testServerTimingHeader("metric;desc=\\\\\"", {{"metric", "0", ""}});
+  // metric;desc=\"\ --> ''
+  testServerTimingHeader("metric;desc=\\\"\\", {{"metric", "0", ""}});
+  // metric;desc=\"" --> ''
+  testServerTimingHeader("metric;desc=\\\"\"", {{"metric", "0", ""}});
+  // metric;desc="\\ --> ''
+  testServerTimingHeader("metric;desc=\"\\\\", {{"metric", "0", ""}});
+  // metric;desc="\" --> ''
+  testServerTimingHeader("metric;desc=\"\\\"", {{"metric", "0", ""}});
+  // metric;desc=""\ --> ''
+  testServerTimingHeader("metric;desc=\"\"\\", {{"metric", "0", ""}});
+  // metric;desc=""" --> ''
+  testServerTimingHeader("metric;desc=\"\"\"", {{"metric", "0", ""}});
+  // metric;desc=\\\\ --> ''
+  testServerTimingHeader("metric;desc=\\\\\\\\", {{"metric", "0", ""}});
+  // metric;desc=\\\" --> ''
+  testServerTimingHeader("metric;desc=\\\\\\\"", {{"metric", "0", ""}});
+  // metric;desc=\\"\ --> ''
+  testServerTimingHeader("metric;desc=\\\\\"\\", {{"metric", "0", ""}});
+  // metric;desc=\\"" --> ''
+  testServerTimingHeader("metric;desc=\\\\\"\"", {{"metric", "0", ""}});
+  // metric;desc=\"\\ --> ''
+  testServerTimingHeader("metric;desc=\\\"\\\\", {{"metric", "0", ""}});
+  // metric;desc=\"\" --> ''
+  testServerTimingHeader("metric;desc=\\\"\\\"", {{"metric", "0", ""}});
+  // metric;desc=\""\ --> ''
+  testServerTimingHeader("metric;desc=\\\"\"\\", {{"metric", "0", ""}});
+  // metric;desc=\""" --> ''
+  testServerTimingHeader("metric;desc=\\\"\"\"", {{"metric", "0", ""}});
+  // metric;desc="\\\ --> ''
+  testServerTimingHeader("metric;desc=\"\\\\\\", {{"metric", "0", ""}});
+  // metric;desc="\\" --> '\'
+  testServerTimingHeader("metric;desc=\"\\\\\"", {{"metric", "0", "\\"}});
+  // metric;desc="\"\ --> ''
+  testServerTimingHeader("metric;desc=\"\\\"\\", {{"metric", "0", ""}});
+  // metric;desc="\"" --> '"'
+  testServerTimingHeader("metric;desc=\"\\\"\"", {{"metric", "0", "\""}});
+  // metric;desc=""\\ --> ''
+  testServerTimingHeader("metric;desc=\"\"\\\\", {{"metric", "0", ""}});
+  // metric;desc=""\" --> ''
+  testServerTimingHeader("metric;desc=\"\"\\\"", {{"metric", "0", ""}});
+  // metric;desc="""\ --> ''
+  testServerTimingHeader("metric;desc=\"\"\"\\", {{"metric", "0", ""}});
+  // metric;desc="""" --> ''
+  testServerTimingHeader("metric;desc=\"\"\"\"", {{"metric", "0", ""}});
+
+  // duplicate entry names
+  testServerTimingHeader(
+      "metric;dur=12.3;desc=description1,metric;dur=45.6;"
+      "desc=description2",
+      {{"metric", "12.3", "description1"}, {"metric", "45.6", "description2"}});
+
+  // non-numeric durations
+  testServerTimingHeader("metric;dur=foo", {{"metric", "0", ""}});
+  testServerTimingHeader("metric;dur=\"foo\"", {{"metric", "0", ""}});
+
+  // unrecognized param names
+  testServerTimingHeader(
+      "metric;foo=bar;desc=description;foo=bar;dur=123.4;foo=bar",
+      {{"metric", "123.4", "description"}});
+
+  // duplicate param names
+  testServerTimingHeader("metric;dur=123.4;dur=567.8",
+                         {{"metric", "123.4", ""}});
+  testServerTimingHeader("metric;desc=description1;desc=description2",
+                         {{"metric", "0", "description1"}});
+  testServerTimingHeader("metric;dur=foo;dur=567.8", {{"metric", "", ""}});
+
+  // unspecified param values
+  testServerTimingHeader("metric;dur;dur=123.4", {{"metric", "123.4", ""}});
+  testServerTimingHeader("metric;desc;desc=description",
+                         {{"metric", "0", "description"}});
+
+  // param name case
+  testServerTimingHeader("metric;DuR=123.4;DeSc=description",
+                         {{"metric", "123.4", "description"}});
+
+  // nonsense
+  testServerTimingHeader("metric=foo;dur;dur=123.4,metric2",
+                         {{"metric", "123.4", ""}, {"metric2", "0", ""}});
+  testServerTimingHeader("metric\"foo;dur;dur=123.4,metric2",
+                         {{"metric", "", ""}});
+
+  // nonsense - return zero entries
+  testServerTimingHeader(" ", {});
+  testServerTimingHeader("=", {});
+  testServerTimingHeader("[", {});
+  testServerTimingHeader("]", {});
+  testServerTimingHeader(";", {});
+  testServerTimingHeader(",", {});
+  testServerTimingHeader("=;", {});
+  testServerTimingHeader(";=", {});
+  testServerTimingHeader("=,", {});
+  testServerTimingHeader(",=", {});
+  testServerTimingHeader(";,", {});
+  testServerTimingHeader(",;", {});
+  testServerTimingHeader("=;,", {});
+
+  // Invalid token
+  testServerTimingHeader("met=ric", {{"met", "0", ""}});
+  testServerTimingHeader("met ric", {{"met", "0", ""}});
+  testServerTimingHeader("met[ric", {{"met", "0", ""}});
+  testServerTimingHeader("met]ric", {{"met", "0", ""}});
+  testServerTimingHeader("metric;desc=desc=123, metric2",
+                         {{"metric", "0", "desc"}, {"metric2", "0", ""}});
+  testServerTimingHeader("met ric;desc=de sc  , metric2",
+                         {{"met", "0", "de"}, {"metric2", "0", ""}});
+
+  // test cases from https://w3c.github.io/server-timing/#examples
+  testServerTimingHeader(" miss, ,db;dur=53, app;dur=47.2 ",
+                         {{"miss", "0", ""}, {"db", "53", ""}, {"app", "47.2", ""}});
+  testServerTimingHeader(" customView, dc;desc=atl ",
+                         {{"customView", "0", ""}, {"dc", "0", "atl"}});
+  testServerTimingHeader(" total;dur=123.4 ",
+                         {{"total", "123.4", ""}});
+
+  // test cases for comma in quoted string
+  testServerTimingHeader("     metric ; desc=\"descr\\\"\\\";,=iption\";dur=123.4",
+                         {{"metric", "123.4", "descr\"\";,=iption"}});
+  testServerTimingHeader(" metric2;dur=\"123.4\";;desc=\",;\\\",;,\";;,  metric  ;  desc = \" \\\", ;\\\" \"; dur=123.4,",
+                         {{"metric2", "123.4", ",;\",;,"}, {"metric", "123.4", " \", ;\" "}});
+}
\ No newline at end of file
--- a/netwerk/test/gtest/moz.build
+++ b/netwerk/test/gtest/moz.build
@@ -7,16 +7,17 @@
 UNIFIED_SOURCES += [
     'TestBufferedInputStream.cpp',
     'TestHeaders.cpp',
     'TestHttpAuthUtils.cpp',
     'TestMozURL.cpp',
     'TestPartiallySeekableInputStream.cpp',
     'TestProtocolProxyService.cpp',
     'TestReadStreamToString.cpp',
+    'TestServerTimingHeader.cpp',
     'TestStandardURL.cpp',
     'TestURIMutator.cpp',
 ]
 
 TEST_DIRS += [
     'parse-ftp',
 ]
 
new file mode 100644
--- /dev/null
+++ b/netwerk/test/unit/test_header_Server_Timing.js
@@ -0,0 +1,84 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+//
+//  HTTP Server-Timing header test
+//
+
+Cu.import("resource://testing-common/httpd.js");
+Cu.import("resource://gre/modules/NetUtil.jsm");
+
+XPCOMUtils.defineLazyGetter(this, "URL", function() {
+  return "http://localhost:" + httpServer.identity.primaryPort + "/content";
+});
+
+let httpServer = null;
+
+function make_and_open_channel(url, callback) {
+  let chan = NetUtil.newChannel({uri: url, loadUsingSystemPrincipal: true});
+  chan.asyncOpen2(new ChannelListener(callback, null, CL_ALLOW_UNKNOWN_CL));
+}
+
+var respnseServerTiming = [{metric:"metric", duration:"123.4", description:"description"},
+                           {metric:"metric2", duration:"456.78", description:"description1"}];
+var trailerServerTiming = [{metric:"metric3", duration:"789.11", description:"description2"},
+                           {metric:"metric4", duration:"1112.13", description:"description3"}];
+
+function createServerTimingHeader(headerData) {
+  var header = "";
+  for (var i = 0; i < headerData.length; i++) {
+    header += "Server-Timing:" + headerData[i].metric + ";" +
+              "dur=" + headerData[i].duration + ";" +
+              "desc=" + headerData[i].description + "\r\n";
+  }
+  return header;
+}
+
+function contentHandler(metadata, response)
+{
+  var body = "c\r\ndata reached\r\n3\r\nhej\r\n0\r\n";
+
+  response.seizePower();
+  response.write("HTTP/1.1 200 OK\r\n");
+  response.write("Content-Type: text/plain\r\n");
+  response.write(createServerTimingHeader(respnseServerTiming));
+
+  response.write("Transfer-Encoding: chunked\r\n");
+  response.write("\r\n");
+  response.write(body);
+  response.write(createServerTimingHeader(trailerServerTiming));
+  response.write("\r\n");
+  response.finish();
+}
+
+function run_test()
+{
+  httpServer = new HttpServer();
+  httpServer.registerPathHandler("/content", contentHandler);
+  httpServer.start(-1);
+
+  do_test_pending();
+  make_and_open_channel(URL, readServerContent);
+}
+
+function checkServerTimingContent(headers) {
+  var expectedResult = respnseServerTiming.concat(trailerServerTiming);
+  Assert.equal(headers.length, expectedResult.length);
+
+  for (var i = 0; i < expectedResult.length; i++) {
+    let header = headers.queryElementAt(i, Ci.nsIServerTiming);
+    Assert.equal(header.name, expectedResult[i].metric);
+    Assert.equal(header.description, expectedResult[i].description);
+    Assert.equal(header.duration, parseFloat(expectedResult[i].duration));
+  }
+}
+
+function readServerContent(request, buffer)
+{
+  let channel = request.QueryInterface(Ci.nsITimedChannel);
+  let headers = channel.serverTiming.QueryInterface(Ci.nsIArray);
+  checkServerTimingContent(headers);
+
+  httpServer.stop(do_test_finished);
+}
--- a/netwerk/test/unit/xpcshell.ini
+++ b/netwerk/test/unit/xpcshell.ini
@@ -405,8 +405,9 @@ skip-if = os == "android"
 [test_1351443-missing-NewChannel2.js]
 [test_bug1312782_http1.js]
 [test_bug1355539_http1.js]
 [test_bug1378385_http1.js]
 [test_tls_flags_separate_connections.js]
 [test_tls_flags.js]
 [test_uri_mutator.js]
 [test_bug1411316_http1.js]
+[test_header_Server_Timing.js]