diff --git a/reviewboard/oauth/tests.py b/reviewboard/oauth/tests.py
index 51fda3216a121c60a28fde84703e6052ce13d7df..13b86bbce306bcd8dabb115b15e1c0a58aebee09 100644
--- a/reviewboard/oauth/tests.py
+++ b/reviewboard/oauth/tests.py
@@ -4,12 +4,14 @@ from django.contrib.auth.models import AnonymousUser, User
 from django.core.exceptions import ValidationError
 from django.forms.models import model_to_dict
 from django.urls import reverse
+from djblets.features.testing import override_feature_check
 from djblets.testing.decorators import add_fixtures
 
 from reviewboard.oauth.forms import (ApplicationChangeForm,
                                      ApplicationCreationForm,
                                      UserApplicationChangeForm,
                                      UserApplicationCreationForm)
+from reviewboard.oauth.features import oauth2_service_feature
 from reviewboard.oauth.models import Application
 from reviewboard.site.models import LocalSite
 from reviewboard.testing import TestCase
@@ -345,6 +347,26 @@ class ApplicationChangeFormTests(TestCase):
         self.assertEqual(form.non_field_errors(),
                          [ApplicationCreationForm.DISABLED_FOR_SECURITY_ERROR])
 
+    @add_fixtures(['test_site'])
+    def test_disable_reassign_to_admin(self):
+        """Testing an Application is disabled and re-assigned to a Local Site
+        admin when its owner is removed from a Local Site
+        """
+        with override_feature_check(oauth2_service_feature.feature_id, True):
+            local_site = LocalSite.objects.get(pk=1)
+            user = User.objects.get(username='doc')
+            admin = User.objects.get(username='admin')
+            application = self.create_oauth_application(user=user,
+                                                        local_site=local_site)
+
+            local_site.users.remove(user)
+
+            application = Application.objects.get(pk=application.pk)
+            self.assertTrue(application.is_disabled_for_security)
+            self.assertEqual(application.original_user_id, user.pk)
+            self.assertEqual(application.user_id, admin.pk)
+            self.assertFalse(application.enabled)
+
     def _test_redirect_uri_grant_combination(self, redirect_uris, grant_type,
                                              is_valid):
         doc = User.objects.get(username='doc')
diff --git a/reviewboard/site/tests.py b/reviewboard/site/tests/test_local_site_aware_model_form_mixin.py
similarity index 53%
rename from reviewboard/site/tests.py
rename to reviewboard/site/tests/test_local_site_aware_model_form_mixin.py
index 10d0b53ec7153d7774a10901efb7ea43a84d1e40..5c2fd029d9297682ce197d7d1f113ef6fec56ee0 100644
--- a/reviewboard/site/tests.py
+++ b/reviewboard/site/tests/test_local_site_aware_model_form_mixin.py
@@ -1,339 +1,14 @@
-import importlib
+"""Unit tests for reviewboard.site.mixins.LocalSiteAwareModelFormMixin."""
 
 from django import forms
-from django.contrib.auth.models import Permission, User
-from django.http import HttpRequest, HttpResponse, HttpResponseRedirect
-from django.template import Context, Template
-from django.views.generic.base import View
-from djblets.features.testing import override_feature_check
-from djblets.testing.decorators import add_fixtures
-
-from reviewboard.oauth.features import oauth2_service_feature
-from reviewboard.oauth.models import Application
+from django.contrib.auth.models import User
+
 from reviewboard.reviews.models import DefaultReviewer, Group
-from reviewboard.site.context_processors import AllPermsWrapper
-from reviewboard.site.middleware import LocalSiteMiddleware
-from reviewboard.site.mixins import (CheckLocalSiteAccessViewMixin,
-                                     LocalSiteAwareModelFormMixin)
+from reviewboard.site.mixins import LocalSiteAwareModelFormMixin
 from reviewboard.site.models import LocalSite
-from reviewboard.site.urlresolvers import local_site_reverse
 from reviewboard.testing.testcase import TestCase
 
 
-class BasicTests(TestCase):
-    """Tests basic LocalSite functionality"""
-    fixtures = ['test_users', 'test_site']
-
-    def test_access(self):
-        """Test LocalSite.is_accessible_by"""
-        doc = User.objects.get(username="doc")
-        dopey = User.objects.get(username="dopey")
-        site = LocalSite.objects.get(name="local-site-1")
-
-        self.assertTrue(site.is_accessible_by(doc))
-        self.assertFalse(site.is_accessible_by(dopey))
-
-    def test_access_with_public(self):
-        """Test LocalSite.is_accessible_by with public LocalSites"""
-        doc = User.objects.get(username="doc")
-        dopey = User.objects.get(username="dopey")
-        site = LocalSite.objects.get(name="local-site-1")
-        site.public = True
-
-        self.assertTrue(site.is_accessible_by(doc))
-        self.assertTrue(site.is_accessible_by(dopey))
-
-    def test_local_site_reverse_with_no_local_site(self):
-        """Testing local_site_reverse with no local site"""
-        request = HttpRequest()
-
-        self.assertEqual(local_site_reverse('dashboard'),
-                         '/dashboard/')
-        self.assertEqual(local_site_reverse('dashboard', request=request),
-                         '/dashboard/')
-        self.assertEqual(local_site_reverse('user', args=['sample-user']),
-                         '/users/sample-user/')
-        self.assertEqual(
-            local_site_reverse('user', kwargs={'username': 'sample-user'}),
-            '/users/sample-user/')
-
-    def test_local_site_reverse_with_local_site(self):
-        """Testing local_site_reverse with a local site"""
-        request = HttpRequest()
-        request.GET['local_site_name'] = 'test'
-
-        self.assertEqual(local_site_reverse('dashboard', request=request),
-                         '/dashboard/')
-        self.assertEqual(local_site_reverse('user', args=['sample-user'],
-                                            request=request),
-                         '/users/sample-user/')
-        self.assertEqual(
-            local_site_reverse('user', kwargs={'username': 'sample-user'},
-                               request=request),
-            '/users/sample-user/')
-
-
-class LocalSiteMiddlewareTests(TestCase):
-    """Unit tests for reviewboard.site.middleware.LocalSiteMiddleware."""
-
-    def setUp(self):
-        super(LocalSiteMiddlewareTests, self).setUp()
-
-        self.middleware = LocalSiteMiddleware(lambda: HttpResponse(''))
-
-    def test_request_local_site_empty(self):
-        """Testing LocalSiteMiddleware's request.local_site with no LocalSite
-        """
-        request = HttpRequest()
-        self.middleware.process_view(request=request, view_func=None,
-                                     view_args=None, view_kwargs={})
-
-        self.assertTrue(hasattr(request, '_local_site_name'))
-        self.assertTrue(hasattr(request, 'local_site'))
-        self.assertIsNone(request._local_site_name)
-        self.assertIsNone(request.local_site)
-
-    def test_request_local_site_not_empty(self):
-        """Testing LocalSiteMiddleware's request.local_site with a LocalSite"""
-        local_site = LocalSite.objects.create(name='test-site')
-
-        request = HttpRequest()
-        self.middleware.process_view(
-            request=request,
-            view_func=None,
-            view_args=None,
-            view_kwargs={
-                'local_site_name': local_site.name,
-            })
-
-        self.assertTrue(hasattr(request, '_local_site_name'))
-        self.assertTrue(hasattr(request, 'local_site'))
-        self.assertEqual(request._local_site_name, 'test-site')
-        self.assertEqual(request.local_site, local_site)
-
-
-class PermissionWrapperTests(TestCase):
-    """Testing the LocalSite-aware permissions wrapper."""
-    def setUp(self):
-        super(PermissionWrapperTests, self).setUp()
-
-        self.user = User.objects.get(username='doc')
-        self.assertFalse(self.user.is_superuser)
-
-    @add_fixtures(['test_users', 'test_site'])
-    def test_lookup_global_permission(self):
-        """Testing AllPermsWrapper with global permission lookup"""
-        self.user.user_permissions.add(
-            Permission.objects.get(codename='delete_reviewrequest'))
-
-        perms = AllPermsWrapper(self.user, self.local_site_name)
-
-        self.assertIn('reviews.delete_reviewrequest', perms)
-        self.assertNotIn('reviews.fake_permission', perms)
-
-    @add_fixtures(['test_users', 'test_site'])
-    def test_lookup_site_permission(self):
-        """Testing AllPermsWrapper with site permission lookup"""
-        local_site = LocalSite.objects.get(name=self.local_site_name)
-
-        local_site_profile = self.user.get_site_profile(local_site)
-        local_site_profile.permissions['reviews.can_change_status'] = True
-        local_site_profile.save(update_fields=('permissions',))
-
-        perms = AllPermsWrapper(self.user, self.local_site_name)
-
-        self.assertIn('reviews.can_change_status', perms)
-        self.assertNotIn('reviews.fake_permission', perms)
-
-
-class AdminPermissionTests(TestCase):
-    fixtures = ['test_users', 'test_site']
-
-    def setUp(self):
-        super(AdminPermissionTests, self).setUp()
-
-        self.user = User.objects.get(username='doc')
-        self.assertFalse(self.user.is_superuser)
-
-        self.local_site = LocalSite.objects.get(name=self.local_site_name)
-        self.local_site.admins.add(self.user)
-
-    def test_assigned_permissions(self):
-        """Testing LocalSite assigned admin permissions"""
-        self.assertTrue(self.user.has_perm(
-            'hostingsvcs.change_hostingserviceaccount', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'hostingsvcs.create_hostingserviceaccount', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.can_change_status', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.can_edit_reviewrequest', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.can_submit_as_another_user', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.change_default_reviewer', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.add_group', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.change_group', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.delete_file', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'reviews.delete_screenshot', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'scmtools.add_repository', self.local_site))
-        self.assertTrue(self.user.has_perm(
-            'scmtools.change_repository', self.local_site))
-
-    def test_invalid_permissions(self):
-        """Testing LocalSite invalid admin permissions"""
-        self.assertFalse(self.user.has_perm(
-            'reviews.delete_reviewrequest', self.local_site))
-        self.assertFalse(self.user.has_perm(
-            'dummy.permission', self.local_site))
-
-
-class TemplateTagTests(TestCase):
-    def test_local_site_url_with_no_local_site(self):
-        """Testing localsite's {% url %} with no local site"""
-        context = Context({})
-
-        t = Template('{% url "dashboard" %}')
-        self.assertEqual(t.render(context), '/dashboard/')
-
-        t = Template('{% url "user" "sample-user" %}')
-        self.assertEqual(t.render(context), '/users/sample-user/')
-
-    def test_local_site_url_with_local_site(self):
-        """Testing localsite's {% url %} with local site"""
-
-        # Make sure that {% url %} is registered as a built-in tag.
-        importlib.import_module('reviewboard.site.templatetags')
-
-        context = Context({
-            'local_site_name': 'test',
-        })
-
-        t = Template('{% url "dashboard" %}')
-        self.assertEqual(t.render(context), '/s/test/dashboard/')
-
-        t = Template('{% url "user" "sample-user" %}')
-        self.assertEqual(t.render(context), '/s/test/users/sample-user/')
-
-
-class CheckLocalSiteAccessViewMixinTests(TestCase):
-    """Unit tests for CheckLocalSiteAccessViewMixin."""
-
-    fixtures = ['test_users', 'test_site']
-
-    def test_dispatch_with_local_site_and_allowed(self):
-        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
-        access allowed
-        """
-        class MyView(CheckLocalSiteAccessViewMixin, View):
-            def get(view, *args, **kwargs):
-                self.assertIsNotNone(view.local_site)
-                self.assertEqual(view.local_site.name, 'local-site-1')
-
-                return HttpResponse('success')
-
-        local_site = self.get_local_site(self.local_site_name)
-        request = self.create_http_request(user=local_site.users.all()[0],
-                                           local_site=local_site)
-
-        view = MyView.as_view()
-        response = view(request, local_site_name=local_site.name)
-
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.content, b'success')
-
-    def test_dispatch_with_local_site_and_not_allowed(self):
-        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
-        access not allowed
-        """
-        class MyView(CheckLocalSiteAccessViewMixin, View):
-            def get(view, *args, **kwargs):
-                self.assertIsNotNone(view.local_site)
-                self.assertEqual(view.local_site.name, 'local-site-1')
-
-                return HttpResponse('success')
-
-        view = MyView.as_view()
-
-        local_site = self.get_local_site(self.local_site_name)
-        request = self.create_http_request(
-            user=User.objects.create_user(username='test123',
-                                          email='test123@example.com'),
-            local_site=local_site,
-            view=view)
-
-        response = view(request, local_site_name=local_site.name)
-        self.assertEqual(response.status_code, 403)
-
-    def test_dispatch_with_local_site_and_anonymous(self):
-        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
-        anonymous user
-        """
-        class MyView(CheckLocalSiteAccessViewMixin, View):
-            def get(view, *args, **kwargs):
-                self.assertIsNotNone(view.local_site)
-                self.assertEqual(view.local_site.name, 'local-site-1')
-
-                return HttpResponse('success')
-
-        view = MyView.as_view()
-
-        local_site = self.get_local_site(self.local_site_name)
-        request = self.create_http_request(local_site=local_site,
-                                           view=view)
-
-        response = view(request, local_site_name=local_site.name)
-        self.assertIsInstance(response, HttpResponseRedirect)
-
-    def test_dispatch_with_no_local_site(self):
-        """Testing CheckLocalSiteAccessViewMixin.dispatch with no LocalSite"""
-        class MyView(CheckLocalSiteAccessViewMixin, View):
-            def get(view, *args, **kwargs):
-                self.assertIsNone(view.local_site)
-
-                return HttpResponse('success')
-
-        view = MyView.as_view()
-
-        request = self.create_http_request(
-            user=User.objects.get(username='doc'),
-            view=view)
-
-        response = view(request)
-        self.assertEqual(response.status_code, 200)
-        self.assertEqual(response.content, b'success')
-
-
-class OAuth2ApplicationTests(TestCase):
-    """Testing Applicications assigned to a Local Site."""
-
-    fixtures = ['test_users', 'test_site']
-
-    def test_disable_reassign_to_admin(self):
-        """Testing an Application is disabled and re-assigned to a Local Site
-        admin when its owner is removed from a Local Site
-        """
-        with override_feature_check(oauth2_service_feature.feature_id, True):
-            local_site = LocalSite.objects.get(pk=1)
-            user = User.objects.get(username='doc')
-            admin = User.objects.get(username='admin')
-            application = self.create_oauth_application(user=user,
-                                                        local_site=local_site)
-
-            local_site.users.remove(user)
-
-            application = Application.objects.get(pk=application.pk)
-            self.assertTrue(application.is_disabled_for_security)
-            self.assertEqual(application.original_user_id, user.pk)
-            self.assertEqual(application.user_id, admin.pk)
-            self.assertFalse(application.enabled)
-
-
 class LocalSiteAwareModelFormMixinTests(TestCase):
     """Unit tests for LocalSiteAwareModelFormMixin."""
 
diff --git a/reviewboard/site/tests/__init__.py b/reviewboard/site/tests/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/reviewboard/site/tests/test_check_local_site_access_view_mixin.py b/reviewboard/site/tests/test_check_local_site_access_view_mixin.py
new file mode 100644
index 0000000000000000000000000000000000000000..1a5f50ebb918df5a3d4d9b49524d232372db3afa
--- /dev/null
+++ b/reviewboard/site/tests/test_check_local_site_access_view_mixin.py
@@ -0,0 +1,96 @@
+"""Unit tests for reviewboard.site.mixins.CheckLocalSiteAccessViewMixin."""
+
+from django.contrib.auth.models import User
+from django.http import HttpResponse, HttpResponseRedirect
+from django.views.generic.base import View
+
+from reviewboard.site.mixins import CheckLocalSiteAccessViewMixin
+from reviewboard.testing.testcase import TestCase
+
+
+class CheckLocalSiteAccessViewMixinTests(TestCase):
+    """Unit tests for CheckLocalSiteAccessViewMixin."""
+
+    fixtures = ['test_users', 'test_site']
+
+    def test_dispatch_with_local_site_and_allowed(self):
+        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
+        access allowed
+        """
+        class MyView(CheckLocalSiteAccessViewMixin, View):
+            def get(view, *args, **kwargs):
+                self.assertIsNotNone(view.local_site)
+                self.assertEqual(view.local_site.name, 'local-site-1')
+
+                return HttpResponse('success')
+
+        local_site = self.get_local_site(self.local_site_name)
+        request = self.create_http_request(user=local_site.users.all()[0],
+                                           local_site=local_site)
+
+        view = MyView.as_view()
+        response = view(request, local_site_name=local_site.name)
+
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content, b'success')
+
+    def test_dispatch_with_local_site_and_not_allowed(self):
+        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
+        access not allowed
+        """
+        class MyView(CheckLocalSiteAccessViewMixin, View):
+            def get(view, *args, **kwargs):
+                self.assertIsNotNone(view.local_site)
+                self.assertEqual(view.local_site.name, 'local-site-1')
+
+                return HttpResponse('success')
+
+        view = MyView.as_view()
+
+        local_site = self.get_local_site(self.local_site_name)
+        request = self.create_http_request(
+            user=User.objects.create_user(username='test123',
+                                          email='test123@example.com'),
+            local_site=local_site,
+            view=view)
+
+        response = view(request, local_site_name=local_site.name)
+        self.assertEqual(response.status_code, 403)
+
+    def test_dispatch_with_local_site_and_anonymous(self):
+        """Testing CheckLocalSiteAccessViewMixin.dispatch with LocalSite and
+        anonymous user
+        """
+        class MyView(CheckLocalSiteAccessViewMixin, View):
+            def get(view, *args, **kwargs):
+                self.assertIsNotNone(view.local_site)
+                self.assertEqual(view.local_site.name, 'local-site-1')
+
+                return HttpResponse('success')
+
+        view = MyView.as_view()
+
+        local_site = self.get_local_site(self.local_site_name)
+        request = self.create_http_request(local_site=local_site,
+                                           view=view)
+
+        response = view(request, local_site_name=local_site.name)
+        self.assertIsInstance(response, HttpResponseRedirect)
+
+    def test_dispatch_with_no_local_site(self):
+        """Testing CheckLocalSiteAccessViewMixin.dispatch with no LocalSite"""
+        class MyView(CheckLocalSiteAccessViewMixin, View):
+            def get(view, *args, **kwargs):
+                self.assertIsNone(view.local_site)
+
+                return HttpResponse('success')
+
+        view = MyView.as_view()
+
+        request = self.create_http_request(
+            user=User.objects.get(username='doc'),
+            view=view)
+
+        response = view(request)
+        self.assertEqual(response.status_code, 200)
+        self.assertEqual(response.content, b'success')
diff --git a/reviewboard/site/tests/test_context_processors.py b/reviewboard/site/tests/test_context_processors.py
new file mode 100644
index 0000000000000000000000000000000000000000..b5f11d3898de834d52bab91f970ee100ae4204bb
--- /dev/null
+++ b/reviewboard/site/tests/test_context_processors.py
@@ -0,0 +1,42 @@
+"""Unit tests for reviewboard.site.context_processors."""
+
+from django.contrib.auth.models import Permission
+from djblets.testing.decorators import add_fixtures
+
+from reviewboard.site.context_processors import AllPermsWrapper
+from reviewboard.site.models import LocalSite
+from reviewboard.testing.testcase import TestCase
+
+
+class AllPermsWrapperTests(TestCase):
+    """Unit tests for AllPermsWrapper."""
+
+    def setUp(self):
+        super().setUp()
+
+        self.user = self.create_user()
+
+    @add_fixtures(['test_users', 'test_site'])
+    def test_lookup_global_permission(self):
+        """Testing AllPermsWrapper with global permission lookup"""
+        self.user.user_permissions.add(
+            Permission.objects.get(codename='delete_reviewrequest'))
+
+        perms = AllPermsWrapper(self.user, self.local_site_name)
+
+        self.assertIn('reviews.delete_reviewrequest', perms)
+        self.assertNotIn('reviews.fake_permission', perms)
+
+    @add_fixtures(['test_users', 'test_site'])
+    def test_lookup_site_permission(self):
+        """Testing AllPermsWrapper with site permission lookup"""
+        local_site = LocalSite.objects.get(name=self.local_site_name)
+
+        local_site_profile = self.user.get_site_profile(local_site)
+        local_site_profile.permissions['reviews.can_change_status'] = True
+        local_site_profile.save(update_fields=('permissions',))
+
+        perms = AllPermsWrapper(self.user, self.local_site_name)
+
+        self.assertIn('reviews.can_change_status', perms)
+        self.assertNotIn('reviews.fake_permission', perms)
diff --git a/reviewboard/site/tests/test_local_site.py b/reviewboard/site/tests/test_local_site.py
new file mode 100644
index 0000000000000000000000000000000000000000..0b3e7a1e72331a52e943f859c713b0f29db9ddfd
--- /dev/null
+++ b/reviewboard/site/tests/test_local_site.py
@@ -0,0 +1,80 @@
+"""Unit tests for reviewboard.site.models.LocalSite."""
+
+from django.contrib.auth.models import User
+
+from reviewboard.site.models import LocalSite
+from reviewboard.testing.testcase import TestCase
+
+
+class LocalSiteTests(TestCase):
+    """Unit tests for LocalSite."""
+
+    fixtures = ['test_users', 'test_site']
+
+    def test_access(self):
+        """Test LocalSite.is_accessible_by"""
+        doc = User.objects.get(username="doc")
+        dopey = User.objects.get(username="dopey")
+        site = LocalSite.objects.get(name="local-site-1")
+
+        self.assertTrue(site.is_accessible_by(doc))
+        self.assertFalse(site.is_accessible_by(dopey))
+
+    def test_access_with_public(self):
+        """Test LocalSite.is_accessible_by with public LocalSites"""
+        doc = User.objects.get(username="doc")
+        dopey = User.objects.get(username="dopey")
+        site = LocalSite.objects.get(name="local-site-1")
+        site.public = True
+
+        self.assertTrue(site.is_accessible_by(doc))
+        self.assertTrue(site.is_accessible_by(dopey))
+
+
+class PermissionTests(TestCase):
+    """Unit tests for Django-provided permissions for LocalSite."""
+
+    fixtures = ['test_users', 'test_site']
+
+    def setUp(self):
+        super().setUp()
+
+        self.user = User.objects.get(username='doc')
+        self.assertFalse(self.user.is_superuser)
+
+        self.local_site = LocalSite.objects.get(name=self.local_site_name)
+        self.local_site.admins.add(self.user)
+
+    def test_assigned_permissions(self):
+        """Testing LocalSite assigned admin permissions"""
+        self.assertTrue(self.user.has_perm(
+            'hostingsvcs.change_hostingserviceaccount', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'hostingsvcs.create_hostingserviceaccount', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.can_change_status', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.can_edit_reviewrequest', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.can_submit_as_another_user', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.change_default_reviewer', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.add_group', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.change_group', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.delete_file', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'reviews.delete_screenshot', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'scmtools.add_repository', self.local_site))
+        self.assertTrue(self.user.has_perm(
+            'scmtools.change_repository', self.local_site))
+
+    def test_invalid_permissions(self):
+        """Testing LocalSite invalid admin permissions"""
+        self.assertFalse(self.user.has_perm(
+            'reviews.delete_reviewrequest', self.local_site))
+        self.assertFalse(self.user.has_perm(
+            'dummy.permission', self.local_site))
diff --git a/reviewboard/site/tests/test_local_site_middleware.py b/reviewboard/site/tests/test_local_site_middleware.py
new file mode 100644
index 0000000000000000000000000000000000000000..51ea9aa638e16e943e91d58cfc0193c2e3a5fe54
--- /dev/null
+++ b/reviewboard/site/tests/test_local_site_middleware.py
@@ -0,0 +1,44 @@
+from django.http import HttpRequest, HttpResponse
+
+from reviewboard.site.middleware import LocalSiteMiddleware
+from reviewboard.site.models import LocalSite
+from reviewboard.testing.testcase import TestCase
+
+
+class LocalSiteMiddlewareTests(TestCase):
+    """Unit tests for reviewboard.site.middleware.LocalSiteMiddleware."""
+
+    def setUp(self):
+        super().setUp()
+
+        self.middleware = LocalSiteMiddleware(lambda: HttpResponse(''))
+
+    def test_request_local_site_empty(self):
+        """Testing LocalSiteMiddleware's request.local_site with no LocalSite
+        """
+        request = HttpRequest()
+        self.middleware.process_view(request=request, view_func=None,
+                                     view_args=None, view_kwargs={})
+
+        self.assertTrue(hasattr(request, '_local_site_name'))
+        self.assertTrue(hasattr(request, 'local_site'))
+        self.assertIsNone(request._local_site_name)
+        self.assertIsNone(request.local_site)
+
+    def test_request_local_site_not_empty(self):
+        """Testing LocalSiteMiddleware's request.local_site with a LocalSite"""
+        local_site = LocalSite.objects.create(name='test-site')
+
+        request = HttpRequest()
+        self.middleware.process_view(
+            request=request,
+            view_func=None,
+            view_args=None,
+            view_kwargs={
+                'local_site_name': local_site.name,
+            })
+
+        self.assertTrue(hasattr(request, '_local_site_name'))
+        self.assertTrue(hasattr(request, 'local_site'))
+        self.assertEqual(request._local_site_name, 'test-site')
+        self.assertEqual(request.local_site, local_site)
diff --git a/reviewboard/site/tests/test_template_tags.py b/reviewboard/site/tests/test_template_tags.py
new file mode 100644
index 0000000000000000000000000000000000000000..425d5c2f5943eb6d05facc3c8edd93fce3b5ddf1
--- /dev/null
+++ b/reviewboard/site/tests/test_template_tags.py
@@ -0,0 +1,31 @@
+"""Unit tests for reviewboard.site.templatetags.local_site."""
+
+from django.template import Context, Template
+
+from reviewboard.testing.testcase import TestCase
+
+
+class TemplateTagTests(TestCase):
+    """Unit tests for reviewboard.site.templatetags.local_site."""
+
+    def test_local_site_url_with_no_local_site(self):
+        """Testing localsite's {% url %} with no local site"""
+        context = Context({})
+
+        t = Template('{% url "dashboard" %}')
+        self.assertEqual(t.render(context), '/dashboard/')
+
+        t = Template('{% url "user" "sample-user" %}')
+        self.assertEqual(t.render(context), '/users/sample-user/')
+
+    def test_local_site_url_with_local_site(self):
+        """Testing localsite's {% url %} with local site"""
+        context = Context({
+            'local_site_name': 'test',
+        })
+
+        t = Template('{% url "dashboard" %}')
+        self.assertEqual(t.render(context), '/s/test/dashboard/')
+
+        t = Template('{% url "user" "sample-user" %}')
+        self.assertEqual(t.render(context), '/s/test/users/sample-user/')
diff --git a/reviewboard/site/tests/test_urlresolvers.py b/reviewboard/site/tests/test_urlresolvers.py
new file mode 100644
index 0000000000000000000000000000000000000000..2aa7f294b3b3e628230b2a894f0df6581bc705b3
--- /dev/null
+++ b/reviewboard/site/tests/test_urlresolvers.py
@@ -0,0 +1,39 @@
+"""Unit tests for reviewboard.site.urlresolvers."""
+
+from django.http import HttpRequest
+
+from reviewboard.site.urlresolvers import local_site_reverse
+from reviewboard.testing.testcase import TestCase
+
+
+class LocalSiteReverseTests(TestCase):
+    """Unit tests for local_site_reverse."""
+
+    def test_with_no_local_site(self):
+        """Testing local_site_reverse with no local site"""
+        request = HttpRequest()
+
+        self.assertEqual(local_site_reverse('dashboard'),
+                         '/dashboard/')
+        self.assertEqual(local_site_reverse('dashboard', request=request),
+                         '/dashboard/')
+        self.assertEqual(local_site_reverse('user', args=['sample-user']),
+                         '/users/sample-user/')
+        self.assertEqual(
+            local_site_reverse('user', kwargs={'username': 'sample-user'}),
+            '/users/sample-user/')
+
+    def test_with_local_site(self):
+        """Testing local_site_reverse with a local site"""
+        request = HttpRequest()
+        request.GET['local_site_name'] = 'test'
+
+        self.assertEqual(local_site_reverse('dashboard', request=request),
+                         '/dashboard/')
+        self.assertEqual(local_site_reverse('user', args=['sample-user'],
+                                            request=request),
+                         '/users/sample-user/')
+        self.assertEqual(
+            local_site_reverse('user', kwargs={'username': 'sample-user'},
+                               request=request),
+            '/users/sample-user/')
