from __future__ import unicode_literals
from __future__ import absolute_import, division, print_function

"""
Tests for site module
"""

__author__      = "Graham Klyne (GK@ACM.ORG)"
__copyright__   = "Copyright 2014, G. Klyne"
__license__     = "MIT (http://opensource.org/licenses/MIT)"

import os
import unittest
import json

import logging
log = logging.getLogger(__name__)

from django.conf                    import settings
from django.db                      import models
from django.http                    import QueryDict
from django.core.urlresolvers       import resolve, reverse
from django.contrib.auth.models     import User
from django.test                    import TestCase # cf. https://docs.djangoproject.com/en/dev/topics/testing/tools/#assertions
from django.test.client             import Client

from bs4                            import BeautifulSoup

from annalist                       import layout
from annalist.identifiers           import RDF, RDFS, ANNAL
from annalist.models.site           import Site
from annalist.models.site           import Collection
from annalist.models.annalistuser   import AnnalistUser

from annalist.views.site            import SiteView, SiteActionView

from .AnnalistTestCase import AnnalistTestCase
from .tests import (
    TestHost, TestHostUri, TestBasePath, TestBaseUri, TestBaseDir
    )
from .init_tests import (
    init_annalist_test_site, 
    init_annalist_test_coll,
    resetSitedata
    )
from .entity_testutils import (
    site_view_url, collection_view_url, collection_edit_url, 
    collection_value_keys, collection_create_values, collection_values,
    collection_new_form_data, collection_remove_form_data,
    site_title,
    create_user_permissions, create_test_user
    )
from .entity_testuserdata import (
    annalistuser_create_values, annalistuser_values, annalistuser_read_values
    )
from .entity_testtypedata import (
    recordtype_url, recordtype_edit_url
    )

# Keys in side metadata entity
site_data_keys = (
    { '@id', '@type', '@context'
    , 'annal:type_id', 'annal:id', 'annal:type'
    , 'annal:url', 'annal:meta_comment'
    , 'rdfs:label', 'rdfs:comment'
    , 'collections', 'title'
    , 'annal:software_version'
    })

# Initial collection data used for form display
init_collections = (
    { 'coll1': collection_values("coll1", hosturi=TestHostUri)
    , 'coll2': collection_values("coll2", hosturi=TestHostUri)
    , 'coll3': collection_values("coll3", hosturi=TestHostUri)
    })

init_collection_keys = ["_annalist_site","coll1","coll2","coll3"]


class SiteTest(AnnalistTestCase):
    """
    Tests for Site object interface
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite    = Site(TestBaseUri, TestBaseDir)
        self.coll1       = collection_values(coll_id="coll1")
        self.collnewmeta = collection_create_values(coll_id="new")
        self.collnew     = collection_values(coll_id="new")
        return

    def tearDown(self):
        resetSitedata(scope="collections")
        return

    @classmethod
    def setUpClass(cls):
        super(SiteTest, cls).setUpClass()
        return

    @classmethod
    def tearDownClass(cls):
        super(SiteTest, cls).tearDownClass()
        resetSitedata(scope="all")
        return

    def test_SiteTest(self):
        self.assertEqual(Site.__name__, "Site", "Check Site class name")
        return

    def test_site_init(self):
        s = Site(TestBaseUri, TestBaseDir)
        self.assertEqual(s._entitytype,     ANNAL.CURIE.Site)
        self.assertEqual(s._entityfile,     layout.SITE_META_FILE)
        self.assertEqual(s._entityid,       layout.SITEDATA_ID)
        self.assertEqual(s._entityurl,      TestBaseUri + "/")
        self.assertEqual(s._entitydir,      TestBaseDir + "/")
        self.assertEqual(s._values,         None)
        return

    def test_site_data(self):
        sd = self.testsite.site_data()
        self.assertEquals(set(sd),                  site_data_keys)
        self.assertEquals(sd["title"],              site_title())
        self.assertEquals(sd["rdfs:label"],         site_title())
        self.assertEquals(list(sd["collections"]),  init_collection_keys)
        self.assertDictionaryMatch(sd["collections"]["coll1"], self.coll1)
        return

    # User permissions

    def test_get_user_permissions(self):
        s = self.testsite
        c = s.site_data_collection()
        # Create local permissions
        usr = AnnalistUser.create(
            c, "user1", annalistuser_create_values(user_id="user1")
            )
        # Test access to permissions defined in site
        ugp = s.get_user_permissions("user1", "mailto:testuser@example.org")
        self.assertEqual(ugp[ANNAL.CURIE.id],                 "user1")
        self.assertEqual(ugp[ANNAL.CURIE.type_id],            "_user")
        self.assertEqual(ugp[RDFS.CURIE.label],               "Test User")
        self.assertEqual(ugp[RDFS.CURIE.comment],             "User user1: permissions for Test User in collection testcoll")
        self.assertEqual(ugp[ANNAL.CURIE.user_uri],           "mailto:testuser@example.org")
        self.assertEqual(ugp[ANNAL.CURIE.user_permission],    ["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"])
        return

    def test_get_local_user_not_defined(self):
        s = self.testsite
        ugp = s.get_user_permissions("user1", "mailto:testuser@example.org")
        self.assertIsNone(ugp)
        return

    def test_get_user_uri_mismatch(self):
        s = self.testsite
        c = s.site_data_collection()
        # Create local permissions
        usr = AnnalistUser.create(c, "user1", annalistuser_create_values(user_id="user1"))
        # Test access to permissions defined locally in collection
        ugp = s.get_user_permissions("user1", "mailto:anotheruser@example.org")
        self.assertIsNone(ugp)
        return

    def test_get_default_user_permissions(self):
        s = self.testsite
        # Test access to default permissions defined in site
        ugp = s.get_user_permissions("_default_user_perms", "annal:User/_default_user_perms")
        self.assertEqual(ugp[ANNAL.CURIE.id],                 "_default_user_perms")
        self.assertEqual(ugp[ANNAL.CURIE.type_id],            "_user")
        self.assertEqual(ugp[RDFS.CURIE.label],               "Default permissions")
        self.assertEqual(ugp[ANNAL.CURIE.user_uri],           "annal:User/_default_user_perms")
        self.assertEqual(ugp[ANNAL.CURIE.user_permission],    ["VIEW"])
        return

    # Collections

    def test_collections_dict(self):
        colls = self.testsite.collections_dict()
        self.assertEquals(list(colls), init_collection_keys)
        self.assertDictionaryMatch(colls["coll1"], self.coll1)
        return

    def test_add_collection(self):
        colls = self.testsite.collections_dict()
        self.assertEquals(list(colls), init_collection_keys)
        self.testsite.add_collection("new", self.collnewmeta)
        colls = self.testsite.collections_dict()
        self.assertEquals(set(colls), set(init_collection_keys+["new"]))
        self.assertDictionaryMatch(colls["coll1"], self.coll1)
        self.assertDictionaryMatch(colls["new"],   self.collnew)
        return

    def test_remove_collection(self):
        colls = self.testsite.collections_dict()
        self.assertEquals(list(colls), init_collection_keys)
        self.testsite.remove_collection("coll2")
        collsb = self.testsite.collections_dict()
        self.assertEquals(set(collsb), set(init_collection_keys) - {"coll2"})
        self.assertDictionaryMatch(colls["coll1"], self.coll1)
        return

#   -----------------------------------------------------------------------------
#
#   SiteView tests
#
#   -----------------------------------------------------------------------------

class SiteViewTest(AnnalistTestCase):
    """
    Tests for Site views
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite    = Site(TestBaseUri, TestBaseDir)
        self.uri         = reverse("AnnalistSiteView")
        self.homeuri     = reverse("AnnalistHomeView")
        self.profileuri  = reverse("AnnalistProfileView")
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="testuser", password="testpassword")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def setUpClass(cls):
        super(SiteViewTest, cls).setUpClass()
        return

    @classmethod
    def tearDownClass(cls):
        super(SiteViewTest, cls).tearDownClass()
        resetSitedata(scope="all")
        return

    def test_SiteViewTest(self):
        self.assertEqual(SiteView.__name__, "SiteView", "Check SiteView class name")
        return

    def test_get(self):
        # @@TODO: use reference to self.client, per 
        # https://docs.djangoproject.com/en/dev/topics/testing/tools/#default-test-client
        r = self.client.get(self.uri)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, site_title("<title>%s</title>"))
        return

    def test_get_error(self):
        r = self.client.get(self.uri+"?error_head=Error&error_message=Error%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, """<h3>Error</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Error presented</p>""", html=True)
        return

    def test_get_info(self):
        r = self.client.get(self.uri+"?info_head=Information&info_message=Information%20presented")
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertContains(r, """<h3>Information</h3>""", html=True)
        self.assertContains(r, """<p class="messages">Information presented</p>""", html=True)
        return

    def test_get_home(self):
        r = self.client.get(self.homeuri)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "Found")
        self.assertEqual(r["location"], self.uri)
        return

    def test_get_no_login(self):
        self.client.logout()
        r = self.client.get(self.uri)
        self.assertFalse(r.context["auth_create"])
        self.assertFalse(r.context["auth_update"])
        self.assertFalse(r.context["auth_delete"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string,  "Login")
        self.assertEqual(menuitems[0].a['href'],         self.profileuri)
        # Check displayed collections
        trows = s.form.find_all("div", class_="tbody")
        self.assertEqual(len(trows), len(init_collection_keys))
        self.assertEqual(trows[0].div.div('div')[1].a.string,  "_annalist_site")
        self.assertEqual(trows[0].div.div('div')[1].a['href'], collection_view_url("_annalist_site"))
        self.assertEqual(trows[1].div.div('div')[1].a.string,  "coll1")
        self.assertEqual(trows[1].div.div('div')[1].a['href'], collection_view_url("coll1"))
        self.assertEqual(trows[2].div.div('div')[1].a.string,  "coll2")
        self.assertEqual(trows[2].div.div('div')[1].a['href'], collection_view_url("coll2"))
        self.assertEqual(trows[3].div.div('div')[1].a.string,  "coll3")
        self.assertEqual(trows[3].div.div('div')[1].a['href'], collection_view_url("coll3"))
        return

    def test_get_with_login(self):
        r = self.client.get(self.uri)
        # Preferred way to test main view logic
        self.assertTrue(r.context["auth_create"])
        self.assertTrue(r.context["auth_update"])
        self.assertTrue(r.context["auth_delete"])
        self.assertTrue(r.context["auth_create_coll"])
        self.assertTrue(r.context["auth_delete_coll"])
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            # First two here added in models.site.site_data()
            self.assertEqual(colls[id]["id"],         id)
            self.assertEqual(colls[id]["url"],        init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        # Check returned HTML (checks template logic)
        # (Don't need to keep doing this as logic can be tested through context as above)
        # (See: http://stackoverflow.com/questions/2257958/)
        s = BeautifulSoup(r.content, "html.parser")
        # title and top menu
        self.assertEqual(s.html.title.string, site_title())
        homelink = s.find(class_="title-area").find(class_="name").h1.a
        self.assertEqual(homelink.string,   "Home")
        self.assertEqual(homelink['href'],  self.uri)
        menuitems = s.find(class_="top-bar-section").find(class_="right").find_all("li")
        self.assertEqualIgnoreWS(menuitems[0].a.string, "User testuser")
        self.assertEqual(menuitems[0].a['href'],        TestBasePath+"/profile/")
        self.assertEqualIgnoreWS(menuitems[1].a.string, "Logout")
        self.assertEqual(menuitems[1].a['href'],        TestBasePath+"/logout/")
        # Displayed colllections and check-buttons
        # trows = s.form.find_all("div", class_="tbody")
        trows = s.select("form > div > div > div")
        self.assertEqual(len(trows), len(init_collection_keys)+4)
        site_data = (
            [ (1, "checkbox", "select", "_annalist_site")
            , (2, "checkbox", "select", "coll1")
            , (3, "checkbox", "select", "coll2")
            , (4, "checkbox", "select", "coll3")
            ])
        for i, itype, iname, ivalue in site_data:
            # tcols = trows[i].find_all("div", class_="view-value")
            tcols = trows[i].select("div > div > div")
            self.assertEqual(tcols[0].input['type'],   itype)
            self.assertEqual(tcols[0].input['name'],   iname)
            self.assertEqual(tcols[0].input['value'],  ivalue)
            self.assertEqual(tcols[1].a.string,        ivalue)
            self.assertEqual(tcols[1].a['href'],       collection_view_url(ivalue))
        # buttons to view/edit/remove selected
        btn_view = trows[5].select("div > input")[0]
        self.assertEqual(btn_view["type"],  "submit")
        self.assertEqual(btn_view["name"],  "view")
        btn_edit = trows[5].select("div > input")[1]
        self.assertEqual(btn_edit["type"],  "submit")
        self.assertEqual(btn_edit["name"],  "edit")
        btn_remove = trows[5].select("div > input")[2]
        self.assertEqual(btn_remove["type"],  "submit")
        self.assertEqual(btn_remove["name"],  "remove")
        # Input fields for new collection
        add_fields = trows[6].select("div > div > div")
        field_id    = add_fields[1].input
        field_label = add_fields[2].input
        self.assertEqual(field_id["type"],    "text")
        self.assertEqual(field_id["name"],    "new_id")
        self.assertEqual(field_label["type"], "text")
        self.assertEqual(field_label["name"], "new_label")
        # Button for new collection
        btn_new = trows[7].select("div > input")[0]
        self.assertEqual(btn_new["type"],     "submit")
        self.assertEqual(btn_new["name"],     "new")
        return

    def test_get_site_context_resource(self):
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": layout.SITE_CONTEXT_FILE})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "application/ld+json")
        return

    def test_get_site_image_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["testimage"] = (
            { "resource_name": "test-image.jpg" 
            , "resource_type": "image/jpeg"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "test-image.jpg"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "image/jpeg")
        return

    def test_get_site_markdown_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["testdatafile"] = (
            { "resource_name": "testdatafile.md" 
            , "resource_type": "text/markdown"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "testdatafile.md"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     200)
        self.assertEqual(r.reason_phrase,   "OK")
        self.assertEqual(r["content-type"], "text/markdown")
        return

    def test_get_site_nonexistent_resource(self):
        self.testsite._ensure_values_loaded()
        self.testsite["nosuchfile"] = (
            { "resource_name": "nosuch.file" 
            , "resource_type": "text/plain"
            })
        self.testsite._save()
        u = reverse("AnnalistSiteResourceAccess", kwargs={"resource_ref": "nosuch.file"})
        r = self.client.get(u)
        self.assertEqual(r.status_code,     404)
        self.assertEqual(r.reason_phrase,   "Not found")
        return

    def test_post_add(self):
        form_data = collection_new_form_data("testnew")
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   302)
        self.assertEqual(r.reason_phrase, "Found")
        self.assertEqual(r.content,       b"")
        self.assertEqual(r['location'],
            TestBasePath+"/site/"
            "?info_head=Action%20completed"+
            "&info_message=Created%20new%20collection:%20'testnew'")
        # Check site now has new colllection
        r = self.client.get(self.uri)
        new_collections = init_collections.copy()
        new_collections["testnew"] = collection_values("testnew", hosturi=TestHostUri)
        colls = r.context['collections']
        for id in new_collections:
            p = "[%s]"%id
            # First two here added in model.site.site_data for view template
            self.assertEqualPrefix(colls[id]["id"],         id,                                p)
            self.assertEqualPrefix(colls[id]["url"],        new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["annal:id"],   id,                                p)
            self.assertEqualPrefix(colls[id]["annal:url"],  new_collections[id]["annal:url"],  p)
            self.assertEqualPrefix(colls[id]["rdfs:label"], new_collections[id]["rdfs:label"], p)
        # Check new collection has admin permissions for creator
        new_coll = Collection(self.testsite, "testnew")
        testuser_perms = new_coll.get_user_permissions("testuser", "mailto:testuser@%s"%TestHost)
        expect_perms   = ["VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG", "ADMIN"]
        expect_descr   = "User testuser: permissions for Test User in collection testnew"
        self.assertEqual(testuser_perms[ANNAL.CURIE.id],                "testuser")
        self.assertEqual(testuser_perms[RDFS.CURIE.label],              "Test User")
        self.assertEqual(testuser_perms[RDFS.CURIE.comment],            expect_descr)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_uri],          "mailto:testuser@%s"%TestHost)
        self.assertEqual(testuser_perms[ANNAL.CURIE.user_permission],   expect_perms)
        return

    def test_post_remove(self):
        form_data = collection_remove_form_data(["coll1", "coll3"])
        r = self.client.post(self.uri, form_data)
        self.assertEqual(r.status_code,   200)
        self.assertEqual(r.reason_phrase, "OK")
        self.assertTemplateUsed(r, "annalist_confirm.html")
        # Returns confirmation form: check
        self.assertContains(r, '''<form method="POST" action="'''+TestBasePath+'''/confirm/">''', status_code=200)
        self.assertContains(r, '''<input type="submit" name="confirm" value="Confirm"/>''', html=True)
        self.assertContains(r, '''<input type="submit" name="cancel" value="Cancel"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="confirmed_action" value="'''+reverse("AnnalistSiteActionView")+'''"/>''', html=True)
        self.assertContains(r, '''<input type="hidden" name="cancel_action"   value="'''+reverse("AnnalistSiteView")+'''"/>''', html=True)
        self.assertHtmlContentElement(r.content,
            tagname="input", tagattrs={"name": "action_params"},
            expect_attrs=
                { "type": "hidden"
                , "value":
                    { "remove":    ["Remove selected"]
                    , "new_id":    [""]
                    , "new_label": [""]
                    , "select":    ["coll1", "coll3"]
                    }
                }
            )
        return

#   -----------------------------------------------------------------------------
#
#   SiteActionView tests
#
#   -----------------------------------------------------------------------------

class SiteActionViewTests(AnnalistTestCase):
    """
    Tests for Site action views (completion of confirmed actions
    requested from the site view)
    """

    def setUp(self):
        init_annalist_test_site()
        self.testsite = Site(TestBaseUri, TestBaseDir)
        # self.user = User.objects.create_user('testuser', 'user@test.example.com', 'testpassword')
        # self.user.save()
        # self.client = Client(HTTP_HOST=TestHost)
        # Login and permissions
        create_test_user(None, "testuser", "testpassword")
        self.client = Client(HTTP_HOST=TestHost)
        loggedin = self.client.login(username="testuser", password="testpassword")
        self.assertTrue(loggedin)
        create_user_permissions(
            self.testsite.site_data_collection(), "testuser",
            user_permissions=
              [ "VIEW", "CREATE", "UPDATE", "DELETE", "CONFIG"
              , "CREATE_COLLECTION", "DELETE_COLLECTION"
              ]
            )
        return

    def tearDown(self):
        return

    @classmethod
    def setUpClass(cls):
        super(SiteActionViewTests, cls).setUpClass()
        # Remove any collections left behind from previous tests
        resetSitedata(scope="collections")
        return

    def _conf_data(self, action="confirm"):
        action_values = (
            { 'confirm': "Confirm"
            , 'cancel':  "Cancel"
            })
        return (
            { action:             action_values[action]
            , "confirmed_action": reverse("AnnalistSiteActionView")
            , "action_params":    """{"new_label": [""], "new_id": [""], "select": ["coll1", "coll3"], "remove": ["Remove selected"]}"""
            , "cancel_action":    reverse("AnnalistSiteView")
            })

    def test_SiteActionViewTest(self):
        self.assertEqual(SiteActionView.__name__, "SiteActionView", "Check SiteActionView class name")
        return

    def test_post_confirmed_remove(self):
        # Submit positive confirmation
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="confirm"))
        self.assertEqual(r.status_code,    302)
        self.assertEqual(r.reason_phrase,  "Found")
        self.assertEqual(r.content,        b"")
        v  = reverse("AnnalistSiteView")
        e1 = "info_head="
        e2 = "info_message="
        e3 = "coll1"
        e4 = "coll3"
        self.assertIn(v,  r['location'])
        self.assertIn(e1, r['location'])
        self.assertIn(e2, r['location'])
        self.assertIn(e3, r['location'])
        self.assertIn(e4, r['location'])
        # Confirm collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        #@@ (diagnostic only)
        if len(colls) != len(init_collection_keys)-2:
            log.warning("@@ Collection count mismatch: %s != %d"%(len(colls), len(init_collection_keys)-2))
            log.warning("@@ Collections seen %r"%(list(colls),))
        #@@
        self.assertEqual(len(colls), len(init_collection_keys)-2)
        id = "coll2"
        self.assertEqual(colls[id]["annal:id"],   id)
        self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
        self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return
 
    def test_post_cancelled_remove(self):
        u = reverse("AnnalistConfirmView")
        r = self.client.post(u, self._conf_data(action="cancel"))
        self.assertEqual(r.status_code,    302)
        self.assertEqual(r.reason_phrase,  "Found")
        self.assertEqual(r.content,        b"")
        self.assertEqual(r['location'],    TestBasePath+"/site/")
        # Confirm no collections deleted
        r = self.client.get(TestBasePath+"/site/")
        colls = r.context['collections']
        self.assertEqual(len(colls), len(init_collection_keys))
        for id in init_collections:
            self.assertEqual(colls[id]["annal:id"],   id)
            self.assertEqual(colls[id]["annal:url"],  init_collections[id]["annal:url"])
            self.assertEqual(colls[id]["rdfs:label"], init_collections[id]["rdfs:label"])
        return

# End.
