class SesssonStoreTest(TestCase):
    def setUp(self):
        # create session and key
        self.session = SessionStore()
        self.session.create()
        self.session_key = self.session.session_key

    def test_flush(self):
        # check that folder and key exists
        self.assertTrue(os.path.exists(os.path.join(settings.UPLOADED_IMAGES_ROOT, self.session_key)))
        Session.objects.get(session_key=self.session_key)

        # flush the session
        self.session.flush()

        # check that session doesnt exist and folder is deleted
        with self.assertRaises(Session.DoesNotExist):
            Session.objects.get(session_key=self.session_key)
        self.assertFalse(os.path.exists(os.path.join(settings.UPLOADED_IMAGES_ROOT, self.session_key)))

    def test_create(self):
        self.assertTrue(self.session.exists(self.session_key))
        root = os.path.join(settings.UPLOADED_IMAGES_ROOT, self.session_key)
        self.assertTrue(os.path.exists(root))
        self.assertTrue(os.path.exists(os.path.join(root, "undo")))
        self.assertTrue(os.path.exists(os.path.join(root, "redo")))

    def tearDown(self):
        if self.session.exists(self.session_key):
            self.session.flush()
    def test_remove_session(self):
        # set ip in request headers
        self.r.META.update({
            'HTTP_X_FORWARDED_FOR': '127.0.0.1',
        })

        # session ips to populate database with
        ips = ["127.0.0.1", "127.0.0.1", "0"]

        # in try, finally block to remove all sessions in case an error occurs
        try:
            # create other sessions
            sessions = []
            for ip in ips:
                s = SessionStore()
                s["ip"] = ip
                s.create()
                sessions.append(s)

            # send through view
            response = views.remove_session(self.r)
            # check for success
            self.assertTrue(
                json.loads(response.getvalue())["status"] == "success")
            # get all remaining ips
            all_ips = [
                s.get_decoded()["ip"] for s in Session.objects.get_queryset()
            ]
            # check that 1 ip has been removed
            self.assertTrue(len(all_ips) == len(ips) - 1)
            # there should be 1 '127.0.0.1' and 1 '0' ip left
            self.assertTrue("127.0.0.1" in all_ips)
            self.assertTrue("0" in all_ips)

        finally:
            # clear other sessions
            for s in sessions:
                s.flush()
    def test_upload_page_with_session(self):
        try:
            self.r.session.create()
            # set request headers so the ip should be 127.0.0.1
            self.r.META.update({
                'HTTP_X_FORWARDED_FOR': '127.0.0.1',
            })

            response = views.image_upload_page(self.r)

            response_parse = BeautifulSoup(response.getvalue(), "html.parser")
            upload_page_parser = BeautifulSoup(
                render(self.r, "image_editor_app/upload.html").getvalue(),
                "html.parser")

            self.assertTrue(response_parse.get_text,
                            upload_page_parser.get_text)

            sessions = []

            # create sessions
            for _ in range(3):
                s = SessionStore()
                s["ip"] = "127.0.0.1"
                s.create()
                sessions.append(s)

            response = views.image_upload_page(self.r)
            self.assertTrue(
                response._headers["location"][-1] == reverse("uploadpage") +
                "?error=iplimit")
        finally:
            try:
                for s in sessions:
                    s.flush()
            except NameError:
                pass
class TestSessionClean(TestCase):
    def setUp(self):
        self.s = SessionStore()

    def test_clear_inactive(self):
        # set expiry to 1 second
        self.s.set_expiry(1)
        # create session
        self.s.create()
        # wait 3 seconds
        time.sleep(3)
        # call the cleaner with False testing argument as, with testing=True, function returns instantly
        session_cleaner.session_clean(False)
        # check expired session is cleared
        self.assertTrue([s for s in Session.objects.get_queryset()] == [])

    def test_max_time(self):
        # set start to 0, should be expired
        self.s["start"] = 0
        # set to high value, shouldn't be cleared from activity expiration
        self.s.set_expiry(1000)
        self.s.create()

        # call the cleaner with False testing argument as, with testing=True, function returns instantly
        session_cleaner.session_clean(False)

        # check session deleted
        self.assertTrue([s for s in Session.objects.get_queryset()] == [])

    def test_no_session_key(self):
        # make a folder in uploaded images directory
        path = os.path.join(settings.UPLOADED_IMAGES_ROOT, "test_should_be_deleted")
        os.mkdir(path)

        # call the cleaner with False testing argument as, with testing=True, function returns instantly
        session_cleaner.session_clean(False)

        # check folder is deleted
        self.assertFalse(os.path.exists(path))

    def test_no_folder(self):
        # create session
        self.s["start"] = time.time()
        self.s.set_expiry(1000)
        self.s.create()

        # remove folder
        shutil.rmtree(os.path.join(settings.UPLOADED_IMAGES_ROOT, self.s.session_key))

        # call the cleaner with False testing argument as, with testing=True, function returns instantly
        session_cleaner.session_clean(False)

        # check session is cleared
        self.assertTrue([s for s in Session.objects.get_queryset()] == [])

    def test_valid(self):
        # no expiry, with folder, nothing should be removed
        self.s["start"] = time.time()
        self.s.set_expiry(1000)
        self.s.create()

        # call the cleaner with False testing argument as, with testing=True, function returns instantly
        session_cleaner.session_clean(False)

        # check sessions in database is a list with the session key
        self.assertTrue([s.session_key for s in Session.objects.get_queryset()] == [self.s.session_key])

    def tearDown(self):
        if self.s.exists(self.s.session_key):
            self.s.flush()