Bug 1009988 - OCSP tests: Precompute responses to prevent timeouts. r=cviecco, a=test-only
authorDavid Keeler <dkeeler@mozilla.com>
Mon, 02 Jun 2014 11:35:27 -0700
changeset 200476 f9c90428260b5f70151c99a8b272cf584439b37c
parent 200475 7ac15391741f63fb0ab24fd2962fb499c77d90c3
child 200477 83b7e03162f26f49a1a9281dfff15a4ae52fb563
push id486
push userasasaki@mozilla.com
push dateMon, 14 Jul 2014 18:39:42 +0000
treeherdermozilla-release@d33428174ff1 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewerscviecco, test-only
bugs1009988
milestone31.0a2
Bug 1009988 - OCSP tests: Precompute responses to prevent timeouts. r=cviecco, a=test-only
security/manager/ssl/tests/unit/head_psm.js
security/manager/ssl/tests/unit/test_ocsp_caching.js
--- a/security/manager/ssl/tests/unit/head_psm.js
+++ b/security/manager/ssl/tests/unit/head_psm.js
@@ -416,70 +416,77 @@ function getFailingHttpServer(serverPort
   });
   httpServer.start(serverPort);
   return httpServer;
 }
 
 // Starts an http OCSP responder that serves good OCSP responses and
 // returns an object with a method stop that should be called to stop
 // the http server.
+// NB: Because generating OCSP responses inside the HTTP request
+// handler can cause timeouts, the expected responses are pre-generated
+// all at once before starting the server. This means that their producedAt
+// times will all be the same. If a test depends on this not being the case,
+// perhaps calling startOCSPResponder twice (at different times) will be
+// necessary.
 //
 // serverPort is the port of the http OCSP responder
 // identity is the http hostname that will answer the OCSP requests
 // invalidIdentities is an array of identities that if used an
 //   will cause a test failure
 // nssDBlocaion is the location of the NSS database from where the OCSP
 //   responses will be generated (assumes appropiate keys are present)
 // expectedCertNames is an array of nicks of the certs to be responsed
 // expectedBasePaths is an optional array that is used to indicate
 //   what is the expected base path of the OCSP request.
 function startOCSPResponder(serverPort, identity, invalidIdentities,
                             nssDBLocation, expectedCertNames,
                             expectedBasePaths, expectedMethods,
                             expectedResponseTypes) {
+  let ocspResponseGenerationArgs = expectedCertNames.map(
+    function(expectedNick) {
+      let responseType = "good";
+      if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
+        responseType = expectedResponseTypes.shift();
+      }
+      return [responseType, expectedNick, "unused"];
+    }
+  );
+  let ocspResponses = generateOCSPResponses(ocspResponseGenerationArgs,
+                                            nssDBLocation);
   let httpServer = new HttpServer();
   httpServer.registerPrefixHandler("/",
     function handleServerCallback(aRequest, aResponse) {
       invalidIdentities.forEach(function(identity) {
         do_check_neq(aRequest.host, identity)
       });
       do_print("got request for: " + aRequest.path);
       let basePath = aRequest.path.slice(1).split("/")[0];
       if (expectedBasePaths.length >= 1) {
         do_check_eq(basePath, expectedBasePaths.shift());
       }
       do_check_true(expectedCertNames.length >= 1);
       if (expectedMethods && expectedMethods.length >= 1) {
         do_check_eq(aRequest.method, expectedMethods.shift());
       }
-      let responseType = "good";
-      if (expectedResponseTypes && expectedResponseTypes.length >= 1) {
-        responseType = expectedResponseTypes.shift();
-      }
-      do_check_true(expectedCertNames.length >= 1);
-      let expectedNick = expectedCertNames.shift();
-      do_print("Generating ocsp response(" + responseType + ") for '" +
-               expectedNick + "(" + basePath + ")'");
       aResponse.setStatusLine(aRequest.httpVersion, 200, "OK");
       aResponse.setHeader("Content-Type", "application/ocsp-response");
-      let args = [ [responseType, expectedNick, "unused" ] ];
-      let retArray = generateOCSPResponses(args, nssDBLocation);
-      let responseBody = retArray[0];
-      aResponse.bodyOutputStream.write(responseBody, responseBody.length);
+      aResponse.write(ocspResponses.shift());
     });
   httpServer.identity.setPrimary("http", identity, serverPort);
   invalidIdentities.forEach(function(identity) {
     httpServer.identity.add("http", identity, serverPort);
   });
   httpServer.start(serverPort);
   return {
     stop: function(callback) {
-      do_check_eq(expectedCertNames.length, 0);
-       if (expectedBasePaths) {
-         do_check_eq(expectedBasePaths.length, 0);
-       }
+      // make sure we consumed each expected response
+      do_check_eq(ocspResponses.length, 0);
+      if (expectedBasePaths) {
+        do_check_eq(expectedBasePaths.length, 0);
+      }
       if (expectedResponseTypes) {
         do_check_eq(expectedResponseTypes.length, 0);
       }
       httpServer.stop(callback);
     }
   };
 }
--- a/security/manager/ssl/tests/unit/test_ocsp_caching.js
+++ b/security/manager/ssl/tests/unit/test_ocsp_caching.js
@@ -1,15 +1,22 @@
 // -*- Mode: javascript; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-
 // 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/.
 "use strict";
 
 let gFetchCount = 0;
+let gGoodOCSPResponse = null;
+
+function generateGoodOCSPResponse() {
+  let args = [ ["good", "localhostAndExampleCom", "unused" ] ];
+  let responses = generateOCSPResponses(args, "tlsserver");
+  return responses[0];
+}
 
 function run_test() {
   do_get_profile();
   Services.prefs.setBoolPref("security.ssl.enable_ocsp_stapling", true);
   add_tls_server_setup("OCSPStaplingServer");
 
   let ocspResponder = new HttpServer();
   ocspResponder.registerPrefixHandler("/", function(request, response) {
@@ -22,26 +29,19 @@ function run_test() {
 
       response.setStatusLine(request.httpVersion, 500, "Internal Server Error");
       let body = "Refusing to return a response";
       response.bodyOutputStream.write(body, body.length);
       return;
     }
 
     do_print("returning 200 OK");
-
-    let nickname = "localhostAndExampleCom";
-    do_print("Generating ocsp response for '" + nickname + "'");
-    let args = [ ["good", nickname, "unused" ] ];
-    let ocspResponses = generateOCSPResponses(args, "tlsserver");
-    let goodResponse = ocspResponses[0];
-
     response.setStatusLine(request.httpVersion, 200, "OK");
     response.setHeader("Content-Type", "application/ocsp-response");
-    response.bodyOutputStream.write(goodResponse, goodResponse.length);
+    response.write(gGoodOCSPResponse);
   });
   ocspResponder.start(8080);
 
   add_tests_in_mode(true);
   add_tests_in_mode(false);
 
   add_test(function() { ocspResponder.stop(run_next_test); });
   run_next_test();
@@ -79,16 +79,20 @@ function add_tests_in_mode(useMozillaPKI
   // response will be seen as "not newer" and it won't replace the existing
   // entry.
   add_test(function() {
     let duration = 1200;
     do_print("Sleeping for " + duration + "ms");
     let timer = Cc["@mozilla.org/timer;1"].createInstance(Ci.nsITimer);
     timer.initWithCallback(run_next_test, duration, Ci.nsITimer.TYPE_ONE_SHOT);
   });
+  add_test(function() {
+    gGoodOCSPResponse = generateGoodOCSPResponse();
+    run_next_test();
+  });
   add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK,
                       clearSessionCache);
   add_test(function() { do_check_eq(gFetchCount, 2); run_next_test(); });
 
   // The Good response retrieved from the previous fetch must have replaced
   // the Unknown response in the cache, resulting in the catched Good response
   // being returned and no fetch.
   add_connection_test("ocsp-stapling-none.example.com", Cr.NS_OK,