From 00947abe7a4a6508ac1377c14f8903a610f7671c Mon Sep 17 00:00:00 2001
From: Kenneth Reitz <me@kennethreitz.org>
Date: Wed, 14 Mar 2018 13:06:56 -0400
Subject: [PATCH] collectstatic metrics (#660)

---
 bin/steps/collectstatic                       |  22 ++-
 test/fixtures/collectstatic/.gitignore        |   5 +
 test/fixtures/collectstatic/Pipfile           |  16 +++
 test/fixtures/collectstatic/Pipfile.lock      | 118 +++++++++++++++++
 test/fixtures/collectstatic/Procfile          |   1 +
 test/fixtures/collectstatic/Procfile.windows  |   1 +
 test/fixtures/collectstatic/README.md         |  44 ++++++
 test/fixtures/collectstatic/app.json          |  22 +++
 .../collectstatic/gettingstarted/__init__.py  |   0
 .../collectstatic/gettingstarted/settings.py  | 125 ++++++++++++++++++
 .../gettingstarted/static/humans.txt          |   0
 .../collectstatic/gettingstarted/urls.py      |  17 +++
 .../collectstatic/gettingstarted/wsgi.py      |  15 +++
 test/fixtures/collectstatic/hello/__init__.py |   0
 test/fixtures/collectstatic/hello/admin.py    |   3 +
 .../hello/migrations/0001_initial.py          |  23 ++++
 .../hello/migrations/__init__.py              |   0
 test/fixtures/collectstatic/hello/models.py   |   5 +
 .../collectstatic/hello/static/lang-logo.png  | Bin 0 -> 2217 bytes
 .../collectstatic/hello/templates/base.html   |  83 ++++++++++++
 .../collectstatic/hello/templates/db.html     |  21 +++
 .../collectstatic/hello/templates/index.html  |  58 ++++++++
 test/fixtures/collectstatic/hello/tests.py    |  18 +++
 test/fixtures/collectstatic/hello/views.py    |  20 +++
 test/fixtures/collectstatic/manage.py         |  10 ++
 test/run                                      |   5 +
 26 files changed, 631 insertions(+), 1 deletion(-)
 create mode 100644 test/fixtures/collectstatic/.gitignore
 create mode 100644 test/fixtures/collectstatic/Pipfile
 create mode 100644 test/fixtures/collectstatic/Pipfile.lock
 create mode 100644 test/fixtures/collectstatic/Procfile
 create mode 100644 test/fixtures/collectstatic/Procfile.windows
 create mode 100644 test/fixtures/collectstatic/README.md
 create mode 100644 test/fixtures/collectstatic/app.json
 create mode 100644 test/fixtures/collectstatic/gettingstarted/__init__.py
 create mode 100644 test/fixtures/collectstatic/gettingstarted/settings.py
 create mode 100644 test/fixtures/collectstatic/gettingstarted/static/humans.txt
 create mode 100644 test/fixtures/collectstatic/gettingstarted/urls.py
 create mode 100644 test/fixtures/collectstatic/gettingstarted/wsgi.py
 create mode 100644 test/fixtures/collectstatic/hello/__init__.py
 create mode 100644 test/fixtures/collectstatic/hello/admin.py
 create mode 100644 test/fixtures/collectstatic/hello/migrations/0001_initial.py
 create mode 100644 test/fixtures/collectstatic/hello/migrations/__init__.py
 create mode 100644 test/fixtures/collectstatic/hello/models.py
 create mode 100644 test/fixtures/collectstatic/hello/static/lang-logo.png
 create mode 100644 test/fixtures/collectstatic/hello/templates/base.html
 create mode 100644 test/fixtures/collectstatic/hello/templates/db.html
 create mode 100644 test/fixtures/collectstatic/hello/templates/index.html
 create mode 100644 test/fixtures/collectstatic/hello/tests.py
 create mode 100644 test/fixtures/collectstatic/hello/views.py
 create mode 100755 test/fixtures/collectstatic/manage.py

diff --git a/bin/steps/collectstatic b/bin/steps/collectstatic
index b779b7e4..73f03cf0 100755
--- a/bin/steps/collectstatic
+++ b/bin/steps/collectstatic
@@ -32,7 +32,11 @@ if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALL
     # Run collectstatic, cleanup some of the noisy output.
     PYTHONPATH=${PYTHONPATH:-.}
     export PYTHONPATH
-    python "$MANAGE_FILE" collectstatic --noinput --traceback 2>&1 | sed '/^Post-processed/d;/^Copying/d;/^$/d' | indent
+
+    # Create a temporary file for collecting the collectstaic logs.
+    COLLECTSTATIC_LOG=$(mktemp)
+
+    python "$MANAGE_FILE" collectstatic --noinput --traceback 2>&1 | tee "$COLLECTSTATIC_LOG" | sed '/^Post-processed/d;/^Copying/d;/^$/d' | indent
     COLLECTSTATIC_STATUS="${PIPESTATUS[0]}"
 
     set -e
@@ -42,6 +46,22 @@ if [ ! "$DISABLE_COLLECTSTATIC" ] && [ -f "$MANAGE_FILE" ] && [ "$DJANGO_INSTALL
 
         mcount "failure.collectstatic"
 
+        if grep -q 'SyntaxError' "$COLLECTSTATIC_LOG"; then
+            mcount "failure.collectstatic.syntax-error"
+        fi
+
+        if grep -q 'ImproperlyConfigured' "$COLLECTSTATIC_LOG"; then
+            mcount "failure.collectstatic.improper-configuration"
+        fi
+
+        if grep -q 'The CSS file' "$COLLECTSTATIC_LOG"; then
+            mcount "failure.collectstatic.fancy-references"
+        fi
+
+        if grep -q 'OSError' "$COLLECTSTATIC_LOG"; then
+            mcount "failure.collectstatic.missing-file"
+        fi
+
         echo
         echo " !     Error while running '$ python $MANAGE_FILE collectstatic --noinput'."
         echo "       See traceback above for details."
diff --git a/test/fixtures/collectstatic/.gitignore b/test/fixtures/collectstatic/.gitignore
new file mode 100644
index 00000000..f95d164a
--- /dev/null
+++ b/test/fixtures/collectstatic/.gitignore
@@ -0,0 +1,5 @@
+venv
+*.pyc
+staticfiles
+.env
+db.sqlite3
diff --git a/test/fixtures/collectstatic/Pipfile b/test/fixtures/collectstatic/Pipfile
new file mode 100644
index 00000000..70ca30fd
--- /dev/null
+++ b/test/fixtures/collectstatic/Pipfile
@@ -0,0 +1,16 @@
+[[source]]
+
+url = "https://pypi.python.org/simple"
+verify_ssl = true
+
+
+[packages]
+
+django = "*"
+gunicorn = "*"
+django-heroku = "*"
+
+
+[requires]
+
+python_version = "3.6"
diff --git a/test/fixtures/collectstatic/Pipfile.lock b/test/fixtures/collectstatic/Pipfile.lock
new file mode 100644
index 00000000..397a1c9d
--- /dev/null
+++ b/test/fixtures/collectstatic/Pipfile.lock
@@ -0,0 +1,118 @@
+{
+    "_meta": {
+        "hash": {
+            "sha256": "7843aa61794626156c5dbfa26d6be61df24889c396f04a8dead353d23e2899d6"
+        },
+        "host-environment-markers": {
+            "implementation_name": "cpython",
+            "implementation_version": "3.6.3",
+            "os_name": "posix",
+            "platform_machine": "x86_64",
+            "platform_python_implementation": "CPython",
+            "platform_release": "17.3.0",
+            "platform_system": "Darwin",
+            "platform_version": "Darwin Kernel Version 17.3.0: Thu Nov  9 18:09:22 PST 2017; root:xnu-4570.31.3~1/RELEASE_X86_64",
+            "python_full_version": "3.6.3",
+            "python_version": "3.6",
+            "sys_platform": "darwin"
+        },
+        "pipfile-spec": 6,
+        "requires": {
+            "python_version": "3.6"
+        },
+        "sources": [
+            {
+                "url": "https://pypi.python.org/simple",
+                "verify_ssl": true
+            }
+        ]
+    },
+    "default": {
+        "dj-database-url": {
+            "hashes": [
+                "sha256:e16d94c382ea0564c48038fa7fe8d9c890ef1ab1a8ec4cb48e732c124b9482fd",
+                "sha256:a6832d8445ee9d788c5baa48aef8130bf61fdc442f7d9a548424d25cd85c9f08"
+            ],
+            "version": "==0.4.2"
+        },
+        "django": {
+            "hashes": [
+                "sha256:af18618ce3291be5092893d8522fe3919661bf3a1fb60e3858ae74865a4f07c2",
+                "sha256:9614851d4a7ff8cbd32b73c6076441f377c45a5bbff7e771798fb02c43c31f47"
+            ],
+            "version": "==2.0"
+        },
+        "django-heroku": {
+            "hashes": [
+                "sha256:193bacbe644a607642f6b60acd0a382d6abf4a1f7578f8d3eb10659457efe904",
+                "sha256:af6c723872553b7427121a865eb9fce70d566b9ad26d7defcdcd03a8acea56c8"
+            ],
+            "version": "==0.1.0"
+        },
+        "gunicorn": {
+            "hashes": [
+                "sha256:75af03c99389535f218cc596c7de74df4763803f7b63eb09d77e92b3956b36c6",
+                "sha256:eee1169f0ca667be05db3351a0960765620dad53f53434262ff8901b68a1b622"
+            ],
+            "version": "==19.7.1"
+        },
+        "psycopg2": {
+            "hashes": [
+                "sha256:594aa9a095de16614f703d759e10c018bdffeafce2921b8e80a0e8a0ebbc12e5",
+                "sha256:1cf5d84290c771eeecb734abe2c6c3120e9837eb12f99474141a862b9061ac51",
+                "sha256:0344b181e1aea37a58c218ccb0f0f771295de9aa25a625ed076e6996c6530f9e",
+                "sha256:25250867a4cd1510fb755ef9cb38da3065def999d8e92c44e49a39b9b76bc893",
+                "sha256:317612d5d0ca4a9f7e42afb2add69b10be360784d21ce4ecfbca19f1f5eadf43",
+                "sha256:9d6266348b15b4a48623bf4d3e50445d8e581da413644f365805b321703d0fac",
+                "sha256:ddca39cc55877653b5fcf59976d073e3d58c7c406ef54ae8e61ddf8782867182",
+                "sha256:988d2ec7560d42ef0ac34b3b97aad14c4f068792f00e1524fa1d3749fe4e4b64",
+                "sha256:7a9c6c62e6e05df5406e9b5235c31c376a22620ef26715a663cee57083b3c2ea",
+                "sha256:7a75565181e75ba0b9fb174b58172bf6ea9b4331631cfe7bafff03f3641f5d73",
+                "sha256:94e4128ba1ea56f02522fffac65520091a9de3f5c00da31539e085e13db4771b",
+                "sha256:92179bd68c2efe72924a99b6745a9172471931fc296f9bfdf9645b75eebd6344",
+                "sha256:b9358e203168fef7bfe9f430afaed3a2a624717a1d19c7afa7dfcbd76e3cd95c",
+                "sha256:009e0bc09a57dbef4b601cb8b46a2abad51f5274c8be4bba276ff2884cd4cc53",
+                "sha256:d3ac07240e2304181ffdb13c099840b5eb555efc7be9344503c0c03aa681de79",
+                "sha256:40fa5630cd7d237cd93c4d4b64b9e5ed9273d1cfce55241c7f9066f5db70629d",
+                "sha256:6c2f1a76a9ebd9ecf7825b9e20860139ca502c2bf1beabf6accf6c9e66a7e0c3",
+                "sha256:37f54452c7787dbdc0a634ca9773362b91709917f0b365ed14b831f03cbd34ba",
+                "sha256:8f5942a4daf1ffac42109dc4a72f786af4baa4fa702ede1d7c57b4b696c2e7d6",
+                "sha256:bf708455cd1e9fa96c05126e89a0c59b200d086c7df7bbafc7d9be769e4149a3",
+                "sha256:82c40ea3ac1555e0462803380609fbe8b26f52620f3d4f8eb480cfd8ceed8a14",
+                "sha256:207ba4f9125a0a4200691e82d5eee7ea1485708eabe99a07fc7f08696fae62f4",
+                "sha256:0cd4c848f0e9d805d531e44973c8f48962e20eb7fc0edac3db4f9dbf9ed5ab82",
+                "sha256:57baf63aeb2965ca4b52613ce78e968b6d2bde700c97f6a7e8c6c236b51ab83e",
+                "sha256:2954557393cfc9a5c11a5199c7a78cd9c0c793a047552d27b1636da50d013916",
+                "sha256:7c31dade89634807196a6b20ced831fbd5bec8a21c4e458ea950c9102c3aa96f",
+                "sha256:1286dd16d0e46d59fa54582725986704a7a3f3d9aca6c5902a7eceb10c60cb7e",
+                "sha256:697ff63bc5451e0b0db48ad205151123d25683b3754198be7ab5fcb44334e519",
+                "sha256:fc993c9331d91766d54757bbc70231e29d5ceb2d1ac08b1570feaa0c38ab9582",
+                "sha256:9d64fed2681552ed642e9c0cc831a9e95ab91de72b47d0cb68b5bf506ba88647",
+                "sha256:5c3213be557d0468f9df8fe2487eaf2990d9799202c5ff5cb8d394d09fad9b2a"
+            ],
+            "version": "==2.7.3.2"
+        },
+        "pytz": {
+            "hashes": [
+                "sha256:80af0f3008046b9975242012a985f04c5df1f01eed4ec1633d56cc47a75a6a48",
+                "sha256:feb2365914948b8620347784b6b6da356f31c9d03560259070b2f30cff3d469d",
+                "sha256:59707844a9825589878236ff2f4e0dc9958511b7ffaae94dc615da07d4a68d33",
+                "sha256:d0ef5ef55ed3d37854320d4926b04a4cb42a2e88f71da9ddfdacfde8e364f027",
+                "sha256:c41c62827ce9cafacd6f2f7018e4f83a6f1986e87bfd000b8cfbd4ab5da95f1a",
+                "sha256:8cc90340159b5d7ced6f2ba77694d946fc975b09f1a51d93f3ce3bb399396f94",
+                "sha256:dd2e4ca6ce3785c8dd342d1853dd9052b19290d5bf66060846e5dc6b8d6667f7",
+                "sha256:699d18a2a56f19ee5698ab1123bbcc1d269d061996aeb1eda6d89248d3542b82",
+                "sha256:fae4cffc040921b8a2d60c6cf0b5d662c1190fe54d718271db4eb17d44a185b7"
+            ],
+            "version": "==2017.3"
+        },
+        "whitenoise": {
+            "hashes": [
+                "sha256:15f43b2e701821b95c9016cf469d29e2a546cb1c7dead584ba82c36f843995cf",
+                "sha256:9d81515f2b5b27051910996e1e860b1332e354d9e7bcf30c98f21dcb6713e0dd"
+            ],
+            "version": "==3.3.1"
+        }
+    },
+    "develop": {}
+}
diff --git a/test/fixtures/collectstatic/Procfile b/test/fixtures/collectstatic/Procfile
new file mode 100644
index 00000000..b6f89307
--- /dev/null
+++ b/test/fixtures/collectstatic/Procfile
@@ -0,0 +1 @@
+web: gunicorn gettingstarted.wsgi
diff --git a/test/fixtures/collectstatic/Procfile.windows b/test/fixtures/collectstatic/Procfile.windows
new file mode 100644
index 00000000..69789e55
--- /dev/null
+++ b/test/fixtures/collectstatic/Procfile.windows
@@ -0,0 +1 @@
+web: python manage.py runserver 0.0.0.0:5000
diff --git a/test/fixtures/collectstatic/README.md b/test/fixtures/collectstatic/README.md
new file mode 100644
index 00000000..23ff5a07
--- /dev/null
+++ b/test/fixtures/collectstatic/README.md
@@ -0,0 +1,44 @@
+# Python: Getting Started
+
+A barebones Django app, which can easily be deployed to Heroku.
+
+This application supports the [Getting Started with Python on Heroku](https://devcenter.heroku.com/articles/getting-started-with-python) article - check it out.
+
+## Running Locally
+
+Make sure you have Python [installed properly](http://install.python-guide.org). Also, install the [Heroku CLI](https://devcenter.heroku.com/articles/heroku-cli) and [Postgres](https://devcenter.heroku.com/articles/heroku-postgresql#local-setup).
+
+```sh
+$ git clone git@github.com:heroku/python-getting-started.git
+$ cd python-getting-started
+
+$ pipenv install
+
+$ createdb python_getting_started
+
+$ python manage.py migrate
+$ python manage.py collectstatic
+
+$ heroku local
+```
+
+Your app should now be running on [localhost:5000](http://localhost:5000/).
+
+## Deploying to Heroku
+
+```sh
+$ heroku create
+$ git push heroku master
+
+$ heroku run python manage.py migrate
+$ heroku open
+```
+or
+
+[![Deploy](https://www.herokucdn.com/deploy/button.svg)](https://heroku.com/deploy)
+
+## Documentation
+
+For more information about using Python on Heroku, see these Dev Center articles:
+
+- [Python on Heroku](https://devcenter.heroku.com/categories/python)
diff --git a/test/fixtures/collectstatic/app.json b/test/fixtures/collectstatic/app.json
new file mode 100644
index 00000000..8721c499
--- /dev/null
+++ b/test/fixtures/collectstatic/app.json
@@ -0,0 +1,22 @@
+{
+  "name": "Start on Heroku: Python",
+  "description": "A barebones Python app, which can easily be deployed to Heroku.",
+  "image": "heroku/python",
+  "repository": "https://github.com/heroku/python-getting-started",
+  "keywords": ["python", "django" ],
+  "addons": [ "heroku-postgresql" ],
+  "env": {
+    "SECRET_KEY": {
+      "description": "The secret key for the Django application.",
+      "generator": "secret"
+    }
+  },
+  "environments": {
+    "test": {
+      "scripts": {
+        "test-setup": "python manage.py collectstatic --noinput",
+        "test": "python manage.py test"
+      }
+    }
+  }
+}
diff --git a/test/fixtures/collectstatic/gettingstarted/__init__.py b/test/fixtures/collectstatic/gettingstarted/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/test/fixtures/collectstatic/gettingstarted/settings.py b/test/fixtures/collectstatic/gettingstarted/settings.py
new file mode 100644
index 00000000..b23e28bc
--- /dev/null
+++ b/test/fixtures/collectstatic/gettingstarted/settings.py
@@ -0,0 +1,125 @@
+"""
+Django settings for gettingstarted project.
+
+Generated by 'django-admin startproject' using Django 2.0.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/2.0/topics/settings/
+
+For the full list of settings and their values, see
+https://docs.djangoproject.com/en/2.0/ref/settings/
+"""
+
+import os
+import django_heroku
+
+
+# Build paths inside the project like this: os.path.join(BASE_DIR, ...)
+BASE_DIR = os.path.dirname(os.path.dirname(os.path.abspath(__file__)))
+
+
+# Quick-start development settings - unsuitable for production
+# See https://docs.djangoproject.com/en/2.0/howto/deployment/checklist/
+
+# SECURITY WARNING: keep the secret key used in production secret!
+SECRET_KEY = 'CHANGE_ME!!!! (P.S. the SECRET_KEY environment variable will be used, if set, instead).'
+
+# SECURITY WARNING: don't run with debug turned on in production!
+DEBUG = True
+
+ALLOWED_HOSTS = []
+
+
+# Application definition
+
+INSTALLED_APPS = [
+    'django.contrib.admin',
+    'django.contrib.auth',
+    'django.contrib.contenttypes',
+    'django.contrib.sessions',
+    'django.contrib.messages',
+    'django.contrib.staticfiles',
+    'hello'
+]
+
+MIDDLEWARE = [
+    'django.middleware.security.SecurityMiddleware',
+    'django.contrib.sessions.middleware.SessionMiddleware',
+    'django.middleware.common.CommonMiddleware',
+    'django.middleware.csrf.CsrfViewMiddleware',
+    'django.contrib.auth.middleware.AuthenticationMiddleware',
+    'django.contrib.messages.middleware.MessageMiddleware',
+    'django.middleware.clickjacking.XFrameOptionsMiddleware',
+]
+
+ROOT_URLCONF = 'gettingstarted.urls'
+
+TEMPLATES = [
+    {
+        'BACKEND': 'django.template.backends.django.DjangoTemplates',
+        'DIRS': [],
+        'APP_DIRS': True,
+        'OPTIONS': {
+            'context_processors': [
+                'django.template.context_processors.debug',
+                'django.template.context_processors.request',
+                'django.contrib.auth.context_processors.auth',
+                'django.contrib.messages.context_processors.messages',
+            ],
+        },
+    },
+]
+
+WSGI_APPLICATION = 'gettingstarted.wsgi.application'
+
+
+# Database
+# https://docs.djangoproject.com/en/2.0/ref/settings/#databases
+
+DATABASES = {
+    'default': {
+        'ENGINE': 'django.db.backends.sqlite3',
+        'NAME': os.path.join(BASE_DIR, 'db.sqlite3'),
+    }
+}
+
+
+# Password validation
+# https://docs.djangoproject.com/en/2.0/ref/settings/#auth-password-validators
+
+AUTH_PASSWORD_VALIDATORS = [
+    {
+        'NAME': 'django.contrib.auth.password_validation.UserAttributeSimilarityValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.MinimumLengthValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.CommonPasswordValidator',
+    },
+    {
+        'NAME': 'django.contrib.auth.password_validation.NumericPasswordValidator',
+    },
+]
+
+
+# Internationalization
+# https://docs.djangoproject.com/en/2.0/topics/i18n/
+
+LANGUAGE_CODE = 'en-us'
+
+TIME_ZONE = 'UTC'
+
+USE_I18N = True
+
+USE_L10N = True
+
+USE_TZ = True
+
+
+# Static files (CSS, JavaScript, Images)
+# https://docs.djangoproject.com/en/2.0/howto/static-files/
+
+STATIC_URL = '/static/'
+
+django_heroku.settings(locals())
\ No newline at end of file
diff --git a/test/fixtures/collectstatic/gettingstarted/static/humans.txt b/test/fixtures/collectstatic/gettingstarted/static/humans.txt
new file mode 100644
index 00000000..e69de29b
diff --git a/test/fixtures/collectstatic/gettingstarted/urls.py b/test/fixtures/collectstatic/gettingstarted/urls.py
new file mode 100644
index 00000000..36492ed3
--- /dev/null
+++ b/test/fixtures/collectstatic/gettingstarted/urls.py
@@ -0,0 +1,17 @@
+from django.conf.urls import include, url
+from django.urls import path
+
+from django.contrib import admin
+admin.autodiscover()
+
+import hello.views
+
+# Examples:
+# url(r'^$', 'gettingstarted.views.home', name='home'),
+# url(r'^blog/', include('blog.urls')),
+
+urlpatterns = [
+    url(r'^$', hello.views.index, name='index'),
+    url(r'^db', hello.views.db, name='db'),
+    path('admin/', admin.site.urls),
+]
diff --git a/test/fixtures/collectstatic/gettingstarted/wsgi.py b/test/fixtures/collectstatic/gettingstarted/wsgi.py
new file mode 100644
index 00000000..feb0af46
--- /dev/null
+++ b/test/fixtures/collectstatic/gettingstarted/wsgi.py
@@ -0,0 +1,15 @@
+"""
+WSGI config for gettingstarted project.
+
+It exposes the WSGI callable as a module-level variable named ``application``.
+
+For more information on this file, see
+https://docs.djangoproject.com/en/1.6/howto/deployment/wsgi/
+"""
+
+import os
+os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings")
+
+from django.core.wsgi import get_wsgi_application
+
+application = get_wsgi_application()
diff --git a/test/fixtures/collectstatic/hello/__init__.py b/test/fixtures/collectstatic/hello/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/test/fixtures/collectstatic/hello/admin.py b/test/fixtures/collectstatic/hello/admin.py
new file mode 100644
index 00000000..8c38f3f3
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/admin.py
@@ -0,0 +1,3 @@
+from django.contrib import admin
+
+# Register your models here.
diff --git a/test/fixtures/collectstatic/hello/migrations/0001_initial.py b/test/fixtures/collectstatic/hello/migrations/0001_initial.py
new file mode 100644
index 00000000..99c4a82a
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/migrations/0001_initial.py
@@ -0,0 +1,23 @@
+# -*- coding: utf-8 -*-
+# Generated by Django 1.9.1 on 2016-01-27 21:54
+from __future__ import unicode_literals
+
+from django.db import migrations, models
+
+
+class Migration(migrations.Migration):
+
+    initial = True
+
+    dependencies = [
+    ]
+
+    operations = [
+        migrations.CreateModel(
+            name='Greeting',
+            fields=[
+                ('id', models.AutoField(auto_created=True, primary_key=True, serialize=False, verbose_name='ID')),
+                ('when', models.DateTimeField(auto_now_add=True, verbose_name=b'date created')),
+            ],
+        ),
+    ]
diff --git a/test/fixtures/collectstatic/hello/migrations/__init__.py b/test/fixtures/collectstatic/hello/migrations/__init__.py
new file mode 100644
index 00000000..e69de29b
diff --git a/test/fixtures/collectstatic/hello/models.py b/test/fixtures/collectstatic/hello/models.py
new file mode 100644
index 00000000..89d76fd1
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/models.py
@@ -0,0 +1,5 @@
+from django.db import models
+
+# Create your models here.
+class Greeting(models.Model):
+    when = models.DateTimeField('date created', auto_now_add=True)
diff --git a/test/fixtures/collectstatic/hello/static/lang-logo.png b/test/fixtures/collectstatic/hello/static/lang-logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..f04aff1e38eeaeadba93390eb5cd356388b8a9f7
GIT binary patch
literal 2217
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
aZ$a%}dZnx*#!~kSf(m2>Gtbhu?D`$|L6nF9

literal 0
HcmV?d00001

diff --git a/test/fixtures/collectstatic/hello/templates/base.html b/test/fixtures/collectstatic/hello/templates/base.html
new file mode 100644
index 00000000..97ec0738
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/templates/base.html
@@ -0,0 +1,83 @@
+<!DOCTYPE html>
+<html>
+<head>
+<title>Python Getting Started on Heroku</title>
+  <link rel="stylesheet" type="text/css" href="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/css/bootstrap.min.css" />
+  <script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.3/jquery.min.js"></script>
+  <script type="text/javascript" src="//maxcdn.bootstrapcdn.com/bootstrap/3.3.4/js/bootstrap.min.js"></script>
+  <style type="text/css">
+    .jumbotron {
+        background: #532f8c;
+        color: white;
+        padding-bottom: 80px
+    }
+    .jumbotron .btn-primary {
+        background: #845ac7;
+        border-color: #845ac7
+    }
+    .jumbotron .btn-primary:hover {
+        background: #7646c1
+    }
+    .jumbotron p {
+        color: #d9ccee;
+        max-width: 75%;
+        margin: 1em auto 2em
+    }
+    .navbar+.jumbotron {
+        margin-top: -20px
+    }
+    .jumbotron .lang-logo {
+        display: block;
+        background: #b01302;
+        border-radius: 50%;
+        overflow: hidden;
+        width: 100px;
+        height: 100px;
+        margin: auto;
+        border: 2px solid white
+    }
+    .jumbotron .lang-logo img {
+        max-width: 100%
+    }
+
+
+  </style>
+</head>
+<body>
+<nav class="navbar navbar-default navbar-static-top navbar-inverse">
+  <div class="container">
+    <ul class="nav navbar-nav">
+      <li class="active">
+        <a href="/"><span class="glyphicon glyphicon-home"></span> Home</a>
+      </li>
+      <li>
+        <a href="https://devcenter.heroku.com/articles/how-heroku-works"><span class="glyphicon glyphicon-user"></span> How Heroku Works</a>
+      </li>
+      <li class="dropdown">
+        <a href="#" class="dropdown-toggle" data-toggle="dropdown" role="button" aria-expanded="false"><span class="glyphicon glyphicon-info-sign"></span> Getting Started Guides <span class="caret"></span></a>
+          <ul class="dropdown-menu" role="menu">
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-ruby">Getting Started with Ruby on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-nodejs">Getting Started with Node on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-php">Getting Started with PHP on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started with Python on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-java">Getting Started with Java on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-clojure">Getting Started with Clojure on Heroku</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-scala">Getting Started with Scala on Heroku</a></li>
+            <li class="divider"></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-heroku-and-connect-without-local-dev">Getting Started on Heroku with Heroku Connect</a></li>
+            <li><a href="https://devcenter.heroku.com/articles/getting-started-with-jruby">Getting Started with Ruby on Heroku (Microsoft Windows)</a></li>
+          </ul>
+      </li>
+    </ul>
+    <ul class="nav navbar-nav navbar-right">
+      <li class="navbar-right">
+        <a href="https://devcenter.heroku.com"><span class="glyphicon glyphicon-book"></span> Heroku Dev Center</a>
+      </li>
+    </ul>
+  </div>
+</nav>
+
+{% block content %}{% endblock %}
+
+</body>
+</html>
diff --git a/test/fixtures/collectstatic/hello/templates/db.html b/test/fixtures/collectstatic/hello/templates/db.html
new file mode 100644
index 00000000..e0e03d4c
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/templates/db.html
@@ -0,0 +1,21 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block content %}
+  <div class="container">
+
+
+<h2>Page View Report</h2>
+
+
+<ul>
+
+{% for greeting in greetings %}
+    <li>{{ greeting.when }}</li>
+{% endfor %}
+
+</ul>
+
+</div>
+
+{% endblock %}
\ No newline at end of file
diff --git a/test/fixtures/collectstatic/hello/templates/index.html b/test/fixtures/collectstatic/hello/templates/index.html
new file mode 100644
index 00000000..8af29028
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/templates/index.html
@@ -0,0 +1,58 @@
+{% extends "base.html" %}
+{% load staticfiles %}
+
+{% block content %}
+
+<div class="jumbotron text-center">
+  <div class="container">
+    <a href="/" class="lang-logo">
+      <img src="{% static 'lang-logo.png'%}">
+    </a>
+    <h1>Getting Started with Python on Heroku</h1>
+    <p>This is a sample Python application deployed to Heroku. It's a reasonably simple app - but a good foundation for understanding how to get the most out of the Heroku platform.</p>
+    <a type="button" class="btn btn-lg btn-default" href="https://devcenter.heroku.com/articles/getting-started-with-python"><span class="glyphicon glyphicon-flash"></span> Getting Started with Python</a>
+    <a type="button" class="btn btn-lg btn-primary" href="https://github.com/heroku/python-getting-started"><span class="glyphicon glyphicon-download"></span> Source on GitHub</a>
+  </div>
+</div>
+<div class="container">
+  <div class="alert alert-info text-center" role="alert">
+    To deploy your own copy, and learn the fundamentals of the Heroku platform, head over to the <a href="https://devcenter.heroku.com/articles/getting-started-with-python" class="alert-link">Getting Started with Python on Heroku</a> tutorial.
+  </div>
+  <hr>
+  <div class="row">
+    <div class="col-md-6">
+      <h3><span class="glyphicon glyphicon-info-sign"></span> How this sample app works</h3>
+      <ul>
+        <li>This app was deployed to Heroku, either using Git or by using <a href="https://github.com/heroku/python-getting-started">Heroku Button</a> on the repository.</li>
+
+        <li>When Heroku received the source code, it fetched all the dependencies in the <a href="https://github.com/heroku/python-getting-started/blob/master/Pipfile">Pipfile</a>, creating a deployable slug.</li>
+        <li>The platform then spins up a dyno, a lightweight container that provides an isolated environment in which the slug can be mounted and executed.</li>
+        <li>You can scale your app, manage it, and deploy over <a href="https://addons.heroku.com/">150 add-on services</a>, from the Dashboard or CLI.</li>
+      </ul>
+    </div>
+    <div class="col-md-6">
+      <h3><span class="glyphicon glyphicon-link"></span> Next Steps</h3>
+      <ul>
+        <li>If you are following the <a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started</a> guide, then please head back to the tutorial and follow the next steps!</li>
+        <li>If you deployed this app by deploying the Heroku Button, then in a command line shell, run:</li>
+        <ul>
+          <li><code>git clone https://github.com/heroku/python-getting-started.git</code> - this will create a local copy of the source code for the app</li>
+          <li><code>cd python-getting-started</code> - change directory into the local source code repository</li>
+          <li><code>heroku git:remote -a &lt;your-app-name></code> - associate the Heroku app with the repository</li>
+          <li>You'll now be set up to run the app locally, or <a href="https://devcenter.heroku.com/articles/getting-started-with-python#push-local-changes">deploy changes</a> to Heroku</li>
+        </ul>
+      </ul>
+      <h3><span class="glyphicon glyphicon-link"></span> Helpful Links</h3>
+      <ul>
+        <li><a href="https://www.heroku.com/home">Heroku</a></li>
+        <li><a href="https://devcenter.heroku.com/">Heroku Dev Center</a></li>
+        <li><a href="https://devcenter.heroku.com/articles/getting-started-with-python">Getting Started with Python on Heroku</a></li>
+        <li><a href="https://devcenter.heroku.com/articles/django-app-configuration">Configuring Django Apps for Heroku</a></li>
+      </ul>
+    </div>
+  </div> <!-- row -->
+   <div class="alert alert-info text-center" role="alert">
+    Please do work through the Getting Started guide, even if you do know how to build such an application.  The guide covers the basics of working with Heroku, and will familiarize you with all the concepts you need in order to build and deploy your own apps.
+  </div>
+</div>
+{% endblock %}
diff --git a/test/fixtures/collectstatic/hello/tests.py b/test/fixtures/collectstatic/hello/tests.py
new file mode 100644
index 00000000..1d69113f
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/tests.py
@@ -0,0 +1,18 @@
+from django.contrib.auth.models import AnonymousUser, User
+from django.test import TestCase, RequestFactory
+
+from .views import index
+
+class SimpleTest(TestCase):
+    def setUp(self):
+        # Every test needs access to the request factory.
+        self.factory = RequestFactory()
+
+    def test_details(self):
+        # Create an instance of a GET request.
+        request = self.factory.get('/')
+        request.user = AnonymousUser()
+
+        # Test my_view() as if it were deployed at /customer/details
+        response = index(request)
+        self.assertEqual(response.status_code, 200)
\ No newline at end of file
diff --git a/test/fixtures/collectstatic/hello/views.py b/test/fixtures/collectstatic/hello/views.py
new file mode 100644
index 00000000..8558d845
--- /dev/null
+++ b/test/fixtures/collectstatic/hello/views.py
@@ -0,0 +1,20 @@
+from django.shortcuts import render
+from django.http import HttpResponse
+
+from .models import Greeting
+
+# Create your views here.
+def index(request):
+    # return HttpResponse('Hello from Python!')
+    return render(request, 'index.html')
+
+
+def db(request):
+
+    greeting = Greeting()
+    greeting.save()
+
+    greetings = Greeting.objects.all()
+
+    return render(request, 'db.html', {'greetings': greetings})
+
diff --git a/test/fixtures/collectstatic/manage.py b/test/fixtures/collectstatic/manage.py
new file mode 100755
index 00000000..eb3ab8af
--- /dev/null
+++ b/test/fixtures/collectstatic/manage.py
@@ -0,0 +1,10 @@
+#!/usr/bin/env python
+import os
+import sys
+
+if __name__ == "__main__":
+    os.environ.setdefault("DJANGO_SETTINGS_MODULE", "gettingstarted.settings")
+
+    from django.core.management import execute_from_command_line
+
+    execute_from_command_line(sys.argv)
diff --git a/test/run b/test/run
index 62e902f4..82baf795 100755
--- a/test/run
+++ b/test/run
@@ -27,6 +27,11 @@ testNoRequirements() {
   assertCapturedError
 }
 
+testCollectstatic() {
+  compile "collectstatic"
+  assertCaptured "collectstatic"
+}
+
 testGEOS() {
   BUILD_WITH_GEO_LIBRARIES=1 compile "geos"
   assertCaptured "geos"
-- 
GitLab