Repository: oppia/oppia

Issue:
Performance test dependency library Xvfb doesn't get installed in most operating systems 
We use XvfbWrapper library for performance testing which depends on Xvfb library. Currently, we install Xvfb library only on Vagrant. It means that by running on mac os x or other non-vagrant platforms:

`bash scripts/run_performance_tests.sh`

We will get: EnvironmentError: Can not find Xvfb. Please install it and try again.



Discussion:
\cc @BenHenning @gvishal 

Will assign a bug severity once I triage it. 

The tests work on Travis. Needs to have more investigation.

Vishal, can you make sure this works on Mac OS X, some flavors of Linux (e.g. Ubuntu), and Vagrant? If you can't test on one of these platforms, please use oppia-dev for users who have that OS.

FYI, I just ran the same command on Ubuntu:

```
 bash scripts/run_performance_tests.sh
```

and got the following error:

```
 EnvironmentError: Can not find Xvfb. Please install it and try again.
```


Resolving patch:
diff --git a/scripts/pre_commit_linter.py b/scripts/pre_commit_linter.py
--- a/scripts/pre_commit_linter.py
+++ b/scripts/pre_commit_linter.py
@@ -144,7 +144,6 @@
     os.path.join(_PARENT_DIR, 'oppia_tools', 'numpy-1.6.1'),
     os.path.join(_PARENT_DIR, 'oppia_tools', 'browsermob-proxy-0.7.1'),
     os.path.join(_PARENT_DIR, 'oppia_tools', 'selenium-2.53.2'),
-    os.path.join(_PARENT_DIR, 'oppia_tools', 'xvfbwrapper-0.2.8'),
     os.path.join('third_party', 'gae-pipeline-1.9.17.0'),
     os.path.join('third_party', 'bleach-1.2.2'),
     os.path.join('third_party', 'gae-mapreduce-1.9.17.0'),


Test patch:
diff --git a/core/tests/gae_suite.py b/core/tests/gae_suite.py
--- a/core/tests/gae_suite.py
+++ b/core/tests/gae_suite.py
@@ -46,7 +46,6 @@
         'lib', 'webob_0_9'),
     os.path.join(OPPIA_TOOLS_DIR, 'browsermob-proxy-0.7.1'),
     os.path.join(OPPIA_TOOLS_DIR, 'selenium-2.53.2'),
-    os.path.join(OPPIA_TOOLS_DIR, 'xvfbwrapper-0.2.8'),
     CURR_DIR,
     os.path.join(THIRD_PARTY_DIR, 'bleach-1.2.2'),
     os.path.join(THIRD_PARTY_DIR, 'gae-cloud-storage-1.9.15.0'),
diff --git a/core/tests/performance_framework/perf_services.py b/core/tests/performance_framework/perf_services.py
--- a/core/tests/performance_framework/perf_services.py
+++ b/core/tests/performance_framework/perf_services.py
@@ -22,9 +22,6 @@
 from browsermobproxy import Server
 from selenium import webdriver
 
-# Used for headless testing i.e, making browser windows invisible to the user.
-from xvfbwrapper import Xvfb
-
 from core.tests.performance_framework import perf_domain
 
 CHROME_DRIVER_PATH = os.path.join(
@@ -73,25 +70,23 @@ def load_url(self, page_url):
         resources. Used to obtain a uniform and warm-cache state for the tests,
         similar to a typical production server state.
         """
-        with Xvfb() as _:
-            driver = self._setup_driver(proxy=None, use_proxy=False)
+        driver = self._setup_driver(proxy=None, use_proxy=False)
 
-            driver.get(page_url)
+        driver.get(page_url)
 
         self._stop_driver(driver)
 
     def get_page_metrics_for_url(self, page_url):
         """Returns a PageSessionMetrics domain object for a given page URL.
         """
-        with Xvfb() as _:
-            server, proxy = self._setup_proxy_server()
-            driver = self._setup_driver(proxy=proxy, use_proxy=True)
+        server, proxy = self._setup_proxy_server()
+        driver = self._setup_driver(proxy=proxy, use_proxy=True)
 
-            proxy.new_har(page_url, options={'captureHeaders': True})
+        proxy.new_har(page_url, options={'captureHeaders': True})
 
-            driver.get(page_url)
+        driver.get(page_url)
 
-            self._wait_until_page_load_is_finished()
+        self._wait_until_page_load_is_finished()
 
         har_dict = proxy.har
 
@@ -108,19 +103,18 @@ def get_page_metrics_from_cached_session(self, page_url):
         Note: This method is stand-alone and does not require
         `get_page_session_metrics_for_url` to be called before it.
         """
-        with Xvfb() as _:
-            server, proxy = self._setup_proxy_server()
-            driver = self._setup_driver(proxy=proxy, use_proxy=True)
+        server, proxy = self._setup_proxy_server()
+        driver = self._setup_driver(proxy=proxy, use_proxy=True)
 
-            # Fetch the page once. This leads to caching of various resources.
-            driver.get(page_url)
-            self._wait_until_page_load_is_finished()
+        # Fetch the page once. This leads to caching of various resources.
+        driver.get(page_url)
+        self._wait_until_page_load_is_finished()
 
-            # Start recording har data for the next page fetch.
-            proxy.new_har(page_url, options={'captureHeaders': True})
-            driver.get(page_url)
+        # Start recording har data for the next page fetch.
+        proxy.new_har(page_url, options={'captureHeaders': True})
+        driver.get(page_url)
 
-            self._wait_until_page_load_is_finished()
+        self._wait_until_page_load_is_finished()
 
         har_dict = proxy.har
 
@@ -134,14 +128,13 @@ def get_page_timings_for_url(self, page_url):
         """Returns a PageSessionMetrics domain object initialized using
         page load timings for a page URL.
         """
-        with Xvfb() as _:
-            driver = self._setup_driver(proxy=None, use_proxy=False)
+        driver = self._setup_driver(proxy=None, use_proxy=False)
 
-            driver.get(page_url)
-            self._wait_until_page_load_is_finished()
+        driver.get(page_url)
+        self._wait_until_page_load_is_finished()
 
-            page_session_timings = (
-                driver.execute_script("return window.performance"))
+        page_session_timings = (
+            driver.execute_script("return window.performance"))
 
         self._stop_driver(driver)
 
@@ -153,18 +146,17 @@ def get_page_timings_from_cached_session(self, page_url):
         load timings for a page URL while simulating a cached session i.e, a
         return user.
         """
-        with Xvfb() as _:
-            driver = self._setup_driver(proxy=None, use_proxy=False)
+        driver = self._setup_driver(proxy=None, use_proxy=False)
 
-            # Fetch the page once. This leads to caching of various resources.
-            driver.get(page_url)
-            self._wait_until_page_load_is_finished()
+        # Fetch the page once. This leads to caching of various resources.
+        driver.get(page_url)
+        self._wait_until_page_load_is_finished()
 
-            driver.get(page_url)
-            self._wait_until_page_load_is_finished()
+        driver.get(page_url)
+        self._wait_until_page_load_is_finished()
 
-            page_session_timings = (
-                driver.execute_script("return window.performance"))
+        page_session_timings = (
+            driver.execute_script("return window.performance"))
 
         self._stop_driver(driver)
 
diff --git a/scripts/run_performance_tests.sh b/scripts/run_performance_tests.sh
--- a/scripts/run_performance_tests.sh
+++ b/scripts/run_performance_tests.sh
@@ -76,7 +76,17 @@ chmod 744 $TOOLS_DIR/browsermob-proxy-2.1.1/bin/browsermob-proxy
 # Wait for the servers to come up.
 while ! nc -vz localhost 9501; do sleep 1; done
 
-$PYTHON_CMD scripts/backend_tests.py --test_path='core/tests/performance_tests' $@ 
+# Install xvfb if not on travis, Used in frontend, e2e tests and performance tests.
+if [ "$TRAVIS" = true ]; then
+  export XVFB_PREFIX=""
+else
+  # This installs xvfb for systems with apt-get installer like Ubuntu, and will fail for other systems.
+  # TODO(gvishal): Install/provide xvfb for other systems.
+  sudo apt-get install xvfb
+  export XVFB_PREFIX="/usr/bin/xvfb-run"
+fi
+
+$XVFB_PREFIX $PYTHON_CMD scripts/backend_tests.py --test_path='core/tests/performance_tests' $@ 
 
 chmod 644 $TOOLS_DIR/browsermob-proxy-2.1.1/bin/browsermob-proxy
 rm bmp.log server.log