From aa76d9482aeae10800feae312bd5656090f4faf5 Mon Sep 17 00:00:00 2001
From: Andy Armstrong <andya@edx.org>
Date: Fri, 12 Jun 2015 15:19:33 -0400
Subject: [PATCH] Update Bok Choy to use optimized static assets

TNL-2465
---
 cms/envs/bok_choy.py                          | 29 +++++++++---
 cms/envs/test_static_optimized.py             | 45 +++++++++++++++++++
 cms/static/build.js                           |  6 ++-
 .../verify_student/tests/test_views.py        |  2 +-
 lms/envs/test_static_optimized.py             | 16 +++++++
 pavelib/utils/test/suites/acceptance_suite.py |  2 +-
 pavelib/utils/test/suites/bokchoy_suite.py    | 11 ++---
 pavelib/utils/test/suites/suite.py            | 10 +++++
 8 files changed, 105 insertions(+), 16 deletions(-)
 create mode 100644 cms/envs/test_static_optimized.py
 create mode 100644 lms/envs/test_static_optimized.py

diff --git a/cms/envs/bok_choy.py b/cms/envs/bok_choy.py
index dcd120abf18..29f9accd973 100644
--- a/cms/envs/bok_choy.py
+++ b/cms/envs/bok_choy.py
@@ -1,5 +1,13 @@
 """
-Settings for bok choy tests
+Settings for Bok Choy tests that are used for running CMS and LMS.
+
+Bok Choy uses two different settings files:
+1. test_static_optimized is used when invoking collectstatic
+2. bok_choy is used when running CMS and LMS
+
+Note: it isn't possible to have a single settings file, because Django doesn't
+support both generating static assets to a directory and also serving static
+from the same directory.
 """
 
 import os
@@ -44,8 +52,20 @@ update_module_store_settings(
     default_store=os.environ.get('DEFAULT_STORE', 'draft'),
 )
 
-# Enable django-pipeline and staticfiles
-STATIC_ROOT = (TEST_ROOT / "staticfiles").abspath()
+############################ STATIC FILES #############################
+
+# Enable debug so that static assets are served by Django
+DEBUG = True
+
+# Serve static files at /static directly from the staticfiles directory under test root
+# Note: optimized files for testing are generated with settings from test_static_optimized
+STATIC_URL = "/static/"
+STATICFILES_FINDERS = (
+    'staticfiles.finders.FileSystemFinder',
+)
+STATICFILES_DIRS = (
+    (TEST_ROOT / "staticfiles").abspath(),
+)
 
 # Silence noisy logs
 import logging
@@ -80,9 +100,6 @@ FEATURES['ENABLE_VIDEO_BUMPER'] = True  # Enable video bumper in Studio settings
 ########################### Entrance Exams #################################
 FEATURES['ENTRANCE_EXAMS'] = True
 
-# Unfortunately, we need to use debug mode to serve staticfiles
-DEBUG = True
-
 # Point the URL used to test YouTube availability to our stub YouTube server
 YOUTUBE_PORT = 9080
 YOUTUBE['API'] = "127.0.0.1:{0}/get_youtube_api/".format(YOUTUBE_PORT)
diff --git a/cms/envs/test_static_optimized.py b/cms/envs/test_static_optimized.py
new file mode 100644
index 00000000000..c2b333b547c
--- /dev/null
+++ b/cms/envs/test_static_optimized.py
@@ -0,0 +1,45 @@
+"""
+Settings used when generating static assets for use in tests.
+
+For example, Bok Choy uses two different settings files:
+1. test_static_optimized is used when invoking collectstatic
+2. bok_choy is used when running CMS and LMS
+
+Note: it isn't possible to have a single settings file, because Django doesn't
+support both generating static assets to a directory and also serving static
+from the same directory.
+"""
+
+import os
+from path import path  # pylint: disable=no-name-in-module
+
+# Pylint gets confused by path.py instances, which report themselves as class
+# objects. As a result, pylint applies the wrong regex in validating names,
+# and throws spurious errors. Therefore, we disable invalid-name checking.
+# pylint: disable=invalid-name
+
+
+########################## Prod-like settings ###################################
+# These should be as close as possible to the settings we use in production.
+# As in prod, we read in environment and auth variables from JSON files.
+# Unlike in prod, we use the JSON files stored in this repo.
+# This is a convenience for ensuring (a) that we can consistently find the files
+# and (b) that the files are the same in Jenkins as in local dev.
+os.environ['SERVICE_VARIANT'] = 'bok_choy'
+os.environ['CONFIG_ROOT'] = path(__file__).abspath().dirname()  # pylint: disable=no-value-for-parameter
+
+from .aws import *  # pylint: disable=wildcard-import, unused-wildcard-import
+
+######################### Testing overrides ####################################
+
+# Redirects to the test_root folder within the repo
+TEST_ROOT = CONFIG_ROOT.dirname().dirname() / "test_root"  # pylint: disable=no-value-for-parameter
+LOG_DIR = (TEST_ROOT / "log").abspath()
+
+# Stores the static files under test root so that they don't overwrite existing static assets
+STATIC_ROOT = (TEST_ROOT / "staticfiles").abspath()
+
+# Disables uglify when tests are running (used by build.js).
+# 1. Uglify is by far the slowest part of the build process
+# 2. Having full source code makes debugging tests easier for developers
+os.environ['REQUIRE_BUILD_PROFILE_OPTIMIZE'] = 'none'
diff --git a/cms/static/build.js b/cms/static/build.js
index bb890bee5c9..340ce024567 100644
--- a/cms/static/build.js
+++ b/cms/static/build.js
@@ -19,6 +19,10 @@
         }));
     };
 
+
+    var jsOptimize = process.env.REQUIRE_BUILD_PROFILE_OPTIMIZE !== undefined ?
+        process.env.REQUIRE_BUILD_PROFILE_OPTIMIZE : 'uglify2';
+
     return {
         /**
          * List the modules that will be optimized. All their immediate and deep
@@ -143,7 +147,7 @@
          * mode to minify the code. Only available if REQUIRE_ENVIRONMENT is "rhino" (the default).
          * - "none": No minification will be done.
          */
-        optimize: 'uglify2',
+        optimize: jsOptimize,
         /**
          * Sets the logging level. It is a number:
          * TRACE: 0,
diff --git a/lms/djangoapps/verify_student/tests/test_views.py b/lms/djangoapps/verify_student/tests/test_views.py
index dc6620da0c8..c97593fe84c 100644
--- a/lms/djangoapps/verify_student/tests/test_views.py
+++ b/lms/djangoapps/verify_student/tests/test_views.py
@@ -1965,7 +1965,7 @@ class TestEmailMessageWithCustomICRVBlock(ModuleStoreTestCase):
             "We could not verify your identity for the {assessment} assessment "
             "in the {course_name} course. You have used "
             "{used_attempts} out of {allowed_attempts} attempts to "
-            "verify your identity.".format(
+            "verify your identity".format(
                 course_name=self.course.display_name_with_default,
                 assessment=self.assessment,
                 used_attempts=1,
diff --git a/lms/envs/test_static_optimized.py b/lms/envs/test_static_optimized.py
new file mode 100644
index 00000000000..61c99b65904
--- /dev/null
+++ b/lms/envs/test_static_optimized.py
@@ -0,0 +1,16 @@
+"""
+Settings used when generating static assets for use in tests.
+
+Bok Choy uses two different settings files:
+1. test_static_optimized is used when invoking collectstatic
+2. bok_choy is used when running CMS and LMS
+
+Note: it isn't possible to have a single settings file, because Django doesn't
+support both generating static assets to a directory and also serving static
+from the same directory.
+
+"""
+
+# TODO: update the Bok Choy tests to run with optimized static assets (as is done in Studio)
+
+from .bok_choy import *  # pylint: disable=wildcard-import, unused-wildcard-import
diff --git a/pavelib/utils/test/suites/acceptance_suite.py b/pavelib/utils/test/suites/acceptance_suite.py
index f9f8897b1b9..52bf4929092 100644
--- a/pavelib/utils/test/suites/acceptance_suite.py
+++ b/pavelib/utils/test/suites/acceptance_suite.py
@@ -91,7 +91,7 @@ class AcceptanceTestSuite(TestSuite):
 
     def __enter__(self):
         super(AcceptanceTestSuite, self).__enter__()
-        if not self.skip_clean:
+        if not (self.fasttest or self.skip_clean):
             test_utils.clean_test_files()
 
         if not self.fasttest:
diff --git a/pavelib/utils/test/suites/bokchoy_suite.py b/pavelib/utils/test/suites/bokchoy_suite.py
index 356d7f17118..1301368436f 100644
--- a/pavelib/utils/test/suites/bokchoy_suite.py
+++ b/pavelib/utils/test/suites/bokchoy_suite.py
@@ -57,7 +57,7 @@ class BokChoyTestSuite(TestSuite):
         self.report_dir.makedirs_p()
         test_utils.clean_reports_dir()
 
-        if not self.skip_clean:
+        if not (self.fasttest or self.skip_clean):
             test_utils.clean_test_files()
 
         msg = colorize('green', "Checking for mongo, memchache, and mysql...")
@@ -85,16 +85,13 @@ class BokChoyTestSuite(TestSuite):
 
     def prepare_bokchoy_run(self):
         """
-        Sets up and starts servers for bok-choy run. This includes any stubbed servers.
+        Sets up and starts servers for a Bok Choy run. If --fasttest is not
+        specified then static assets are collected
         """
         sh("{}/scripts/reset-test-db.sh".format(Env.REPO_ROOT))
 
         if not self.fasttest:
-            # Process assets and set up database for bok-choy tests
-            # Reset the database
-
-            # Collect static assets
-            sh("paver update_assets --settings=bok_choy")
+            self.generate_optimized_static_assets()
 
         # Clear any test data already in Mongo or MySQLand invalidate
         # the cache
diff --git a/pavelib/utils/test/suites/suite.py b/pavelib/utils/test/suites/suite.py
index 82647c96242..bfe83d07662 100644
--- a/pavelib/utils/test/suites/suite.py
+++ b/pavelib/utils/test/suites/suite.py
@@ -3,6 +3,8 @@ A class used for defining and running test suites
 """
 import sys
 import subprocess
+from paver.easy import sh
+
 from pavelib.utils.process import kill_process
 
 try:
@@ -57,6 +59,14 @@ class TestSuite(object):
         """
         return None
 
+    def generate_optimized_static_assets(self):
+        """
+        Collect static assets using test_static_optimized.py which generates
+        optimized files to a dedicated test static root.
+        """
+        print colorize('green', "Generating optimized static assets...")
+        sh("paver update_assets --settings=test_static_optimized")
+
     def run_test(self):
         """
         Runs a self.cmd in a subprocess and waits for it to finish.
-- 
GitLab