Example #1
0
class UploadedFileManagerTest(unittest.TestCase):
    def setUp(self):
        self.mgr = UploadedFileManager()
        self.filemgr_events = []
        self.mgr.on_files_added.connect(self._on_files_added)

    def _on_files_added(self, file_list, **kwargs):
        self.filemgr_events.append(file_list)

    def test_add_file(self):
        self.assertIsNone(self.mgr.get_files("non-report", "non-widget"))

        event1 = UploadedFileList("session", "widget", [file1])
        event2 = UploadedFileList("session", "widget", [file2])

        self.mgr.add_files("session", "widget", [file1])
        self.assertEqual([file1], self.mgr.get_files("session", "widget"))
        self.assertEqual([event1], self.filemgr_events)

        # Add another file with the same ID
        self.mgr.add_files("session", "widget", [file2])
        self.assertEqual([file2], self.mgr.get_files("session", "widget"))
        self.assertEqual([event1, event2], self.filemgr_events)

    def test_remove_file(self):
        # This should not error.
        self.mgr.remove_files("non-report", "non-widget")

        self.mgr.add_files("session", "widget", [file1])
        self.assertEqual([file1], self.mgr.get_files("session", "widget"))

        self.mgr.remove_files("session", "widget")
        self.assertIsNone(self.mgr.get_files("session", "widget"))

    def test_remove_all_files(self):
        # This should not error.
        self.mgr.remove_session_files("non-report")

        # Add two files with different session IDs, but the same widget ID.
        self.mgr.add_files("session1", "widget", [file1])
        self.mgr.add_files("session2", "widget", [file1])

        event1 = UploadedFileList("session1", "widget", [file1])
        event2 = UploadedFileList("session2", "widget", [file1])

        self.mgr.remove_session_files("session1")
        self.assertIsNone(self.mgr.get_files("session1", "widget"))
        self.assertEqual([file1], self.mgr.get_files("session2", "widget"))
        self.assertEqual([event1, event2], self.filemgr_events)
class UploadFileRequestHandlerTest(tornado.testing.AsyncHTTPTestCase):
    """Tests the /upload_file endpoint."""
    def get_app(self):
        self.file_mgr = UploadedFileManager()
        self._get_session_info = lambda x: True
        return tornado.web.Application([
            (
                UPLOAD_FILE_ROUTE,
                UploadFileRequestHandler,
                dict(
                    file_mgr=self.file_mgr,
                    get_session_info=self._get_session_info,
                ),
            ),
        ])

    def _upload_files(self, params):
        # We use requests.Request to construct our multipart/form-data request
        # here, because they are absurdly fiddly to compose, and Tornado
        # doesn't include a utility for building them. We then use self.fetch()
        # to actually send the request to the test server.
        req = requests.Request(method="POST",
                               url=self.get_url("/upload_file"),
                               files=params).prepare()

        return self.fetch("/upload_file",
                          method=req.method,
                          headers=req.headers,
                          body=req.body)

    def test_upload_one_file(self):
        """Uploading a file should populate our file_mgr."""
        file = MockFile("filename", b"123")
        params = {
            file.name: file.data,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
            "totalFiles": (None, "1"),
        }
        response = self._upload_files(params)
        self.assertEqual(200, response.code)
        self.assertEqual(
            [(file.name, file.data)],
            [(rec.name, rec.data)
             for rec in self.file_mgr.get_files("fooReport", "barWidget")],
        )

    def test_upload_multiple_files(self):
        file_1 = MockFile("file1", b"123")
        file_2 = MockFile("file2", b"456")
        file_3 = MockFile("file3", b"789")

        params = {
            file_1.name: file_1.data,
            file_2.name: file_2.data,
            file_3.name: file_3.data,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
            "totalFiles": (None, "1"),
        }
        response = self._upload_files(params)
        self.assertEqual(200, response.code)
        self.assertEqual(
            sorted([file_1, file_2, file_3]),
            sorted([
                (rec.name, rec.data)
                for rec in self.file_mgr.get_files("fooReport", "barWidget")
            ]),
        )

    def test_upload_missing_params(self):
        """Missing params in the body should fail with 400 status."""
        params = {
            "image.png": ("image.png", b"1234"),
            "sessionId": (None, "fooReport"),
            # "widgetId": (None, 'barWidget'),
            "totalFiles": (None, "1"),
        }

        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIn("Missing 'widgetId'", response.reason)

    def test_upload_missing_file(self):
        """Missing file should fail with 400 status."""
        params = {
            # "image.png": ("image.png", b"1234"),
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
            "totalFiles": (None, "1"),
        }
        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIn("Expected at least 1 file, but got 0", response.reason)

    def test_delete_file(self):
        """File should be able to be deleted successfully"""
        file1 = UploadedFileRec("1234", "name", "type", b"1234")
        file2 = UploadedFileRec("4567", "name", "type", b"1234")

        self.file_mgr.add_files("session1", "widget1", [file1])
        self.file_mgr.add_files("session2", "widget2", [file2])

        response = self.fetch(f"/upload_file/session1/widget1/1234",
                              method="DELETE")
        self.assertEqual(200, response.code)
        self.assertFalse(len(self.file_mgr.get_files("session1", "widget1")))
        self.assertTrue(len(self.file_mgr.get_files("session2", "widget2")))

    def test_delete_file_across_sessions(self):
        """Deleting file param mismatch should fail with 404 status."""
        file1 = UploadedFileRec("1234", "name", "type", b"1234")
        file2 = UploadedFileRec("4567", "name", "type", b"1234")

        self.file_mgr.add_files("session1", "widget1", [file1])
        self.file_mgr.add_files("session2", "widget2", [file2])

        response = self.fetch(f"/upload_file/session2/widget1/1234",
                              method="DELETE")
        self.assertEqual(404, response.code)
        self.assertTrue(len(self.file_mgr.get_files("session1", "widget1")))
        self.assertTrue(len(self.file_mgr.get_files("session2", "widget2")))

    @parameterized.expand([
        (None, "widget_id", "123"),
        ("session_id", None, "123"),
        ("session_id", "widget_id", None),
    ])
    def test_delete_missing_param(self, session_id, widget_id, file_id):
        """Missing param should fail with 404 status."""
        response = self.fetch(
            f"/upload_file/{session_id}/{widget_id}/{file_id}",
            method="DELETE")

        self.assertEqual(404, response.code)
class UploadFileRequestHandlerInvalidSessionTest(
        tornado.testing.AsyncHTTPTestCase):
    """Tests the /upload_file endpoint."""
    def get_app(self):
        self.file_mgr = UploadedFileManager()
        self._get_session_info = lambda x: None
        return tornado.web.Application([
            (
                UPLOAD_FILE_ROUTE,
                UploadFileRequestHandler,
                dict(
                    file_mgr=self.file_mgr,
                    get_session_info=self._get_session_info,
                ),
            ),
        ])

    def _upload_files(self, params):
        # We use requests.Request to construct our multipart/form-data request
        # here, because they are absurdly fiddly to compose, and Tornado
        # doesn't include a utility for building them. We then use self.fetch()
        # to actually send the request to the test server.
        req = requests.Request(method="POST",
                               url=self.get_url("/upload_file"),
                               files=params).prepare()

        return self.fetch("/upload_file",
                          method=req.method,
                          headers=req.headers,
                          body=req.body)

    def test_upload_one_file(self):
        """Uploading a file should populate our file_mgr."""
        file = MockFile("filename", b"123")
        params = {
            file.name: file.data,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
            "totalFiles": (None, "1"),
        }
        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIsNone(self.file_mgr.get_files("fooReport", "barWidget"))

    def test_upload_multiple_files(self):
        file_1 = MockFile("file1", b"123")
        file_2 = MockFile("file2", b"456")
        file_3 = MockFile("file3", b"789")

        params = {
            file_1.name: file_1.data,
            file_2.name: file_2.data,
            file_3.name: file_3.data,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
            "totalFiles": (None, "1"),
        }
        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIsNone(self.file_mgr.get_files("fooReport", "barWidget"))

    def test_delete_file(self):
        """File should be able to be deleted successfully"""
        file1 = UploadedFileRec("1234", "name", "type", b"1234")
        file2 = UploadedFileRec("4567", "name", "type", b"1234")

        self.file_mgr.add_files("session1", "widget1", [file1])
        self.file_mgr.add_files("session2", "widget2", [file2])

        response = self.fetch(f"/upload_file/session1/widget1/1234",
                              method="DELETE")
        self.assertEqual(404, response.code)
class UploadedFileManagerTest(unittest.TestCase):
    def setUp(self):
        self.mgr = UploadedFileManager()
        self.filemgr_events = []
        self.mgr.on_files_updated.connect(self._on_files_updated)

    def _on_files_updated(self, file_list, **kwargs):
        self.filemgr_events.append(file_list)

    def test_added_file_id(self):
        """An added file should have a unique ID."""
        f1 = self.mgr.add_file("session", "widget", FILE_1)
        f2 = self.mgr.add_file("session", "widget", FILE_1)
        self.assertNotEqual(FILE_1.id, f1.id)
        self.assertNotEqual(f1.id, f2.id)

    def test_added_file_properties(self):
        """An added file should maintain all its source properties
        except its ID."""
        added = self.mgr.add_file("session", "widget", FILE_1)
        self.assertNotEqual(added.id, FILE_1.id)
        self.assertEqual(added.name, FILE_1.name)
        self.assertEqual(added.type, FILE_1.type)
        self.assertEqual(added.data, FILE_1.data)

    def test_retrieve_added_file(self):
        """After adding a file to the mgr, we should be able to get it back."""
        self.assertEqual([], self.mgr.get_all_files("non-report",
                                                    "non-widget"))

        file_1 = self.mgr.add_file("session", "widget", FILE_1)
        self.assertEqual([file_1], self.mgr.get_all_files("session", "widget"))
        self.assertEqual([file_1],
                         self.mgr.get_files("session", "widget", [file_1.id]))
        self.assertEqual(len(self.filemgr_events), 1)

        # Add another file
        file_2 = self.mgr.add_file("session", "widget", FILE_2)
        self.assertEqual([file_1, file_2],
                         self.mgr.get_all_files("session", "widget"))
        self.assertEqual([file_1],
                         self.mgr.get_files("session", "widget", [file_1.id]))
        self.assertEqual([file_2],
                         self.mgr.get_files("session", "widget", [file_2.id]))
        self.assertEqual(len(self.filemgr_events), 2)

    def test_remove_file(self):
        # This should not error.
        self.mgr.remove_files("non-report", "non-widget")

        f1 = self.mgr.add_file("session", "widget", FILE_1)
        self.mgr.remove_file("session", "widget", f1.id)
        self.assertEqual([], self.mgr.get_all_files("session", "widget"))

        # Remove the file again. It doesn't exist, but this isn't an error.
        self.mgr.remove_file("session", "widget", f1.id)
        self.assertEqual([], self.mgr.get_all_files("session", "widget"))

        f1 = self.mgr.add_file("session", "widget", FILE_1)
        f2 = self.mgr.add_file("session", "widget", FILE_2)
        self.mgr.remove_file("session", "widget", f1.id)
        self.assertEqual([f2], self.mgr.get_all_files("session", "widget"))

    def test_remove_widget_files(self):
        # This should not error.
        self.mgr.remove_session_files("non-report")

        # Add two files with different session IDs, but the same widget ID.
        f1 = self.mgr.add_file("session1", "widget", FILE_1)
        f2 = self.mgr.add_file("session2", "widget", FILE_1)

        self.mgr.remove_files("session1", "widget")
        self.assertEqual([], self.mgr.get_all_files("session1", "widget"))
        self.assertEqual([f2], self.mgr.get_all_files("session2", "widget"))

    def test_remove_session_files(self):
        # This should not error.
        self.mgr.remove_session_files("non-report")

        # Add two files with different session IDs, but the same widget ID.
        f1 = self.mgr.add_file("session1", "widget1", FILE_1)
        f2 = self.mgr.add_file("session1", "widget2", FILE_1)
        f3 = self.mgr.add_file("session2", "widget", FILE_1)

        self.mgr.remove_session_files("session1")
        self.assertEqual([], self.mgr.get_all_files("session1", "widget1"))
        self.assertEqual([], self.mgr.get_all_files("session1", "widget2"))
        self.assertEqual([f3], self.mgr.get_all_files("session2", "widget"))

    def test_remove_orphaned_files(self):
        """Test the remove_orphaned_files behavior"""
        f1 = self.mgr.add_file("session1", "widget1", FILE_1)
        f2 = self.mgr.add_file("session1", "widget1", FILE_1)
        f3 = self.mgr.add_file("session1", "widget1", FILE_1)
        self.assertEqual([f1, f2, f3],
                         self.mgr.get_all_files("session1", "widget1"))

        # Nothing should be removed here (all files are active).
        self.mgr.remove_orphaned_files(
            "session1",
            "widget1",
            newest_file_id=f3.id,
            active_file_ids=[f1.id, f2.id, f3.id],
        )
        self.assertEqual([f1, f2, f3],
                         self.mgr.get_all_files("session1", "widget1"))

        # Nothing should be removed here (no files are active, but they're all
        # "newer" than newest_file_id).
        self.mgr.remove_orphaned_files("session1",
                                       "widget1",
                                       newest_file_id=f1.id - 1,
                                       active_file_ids=[])
        self.assertEqual([f1, f2, f3],
                         self.mgr.get_all_files("session1", "widget1"))

        # f2 should be removed here (it's not in the active file list)
        self.mgr.remove_orphaned_files("session1",
                                       "widget1",
                                       newest_file_id=f3.id,
                                       active_file_ids=[f1.id, f3.id])
        self.assertEqual([f1, f3],
                         self.mgr.get_all_files("session1", "widget1"))

        # remove_orphaned_files on an untracked session/widget should not error
        self.mgr.remove_orphaned_files("no_session",
                                       "no_widget",
                                       newest_file_id=0,
                                       active_file_ids=[])
Example #5
0
class UploadFileRequestHandlerTest(tornado.testing.AsyncHTTPTestCase):
    """Tests the /upload_file endpoint."""
    def get_app(self):
        self.file_mgr = UploadedFileManager()
        return tornado.web.Application([("/upload_file",
                                         UploadFileRequestHandler,
                                         dict(file_mgr=self.file_mgr))])

    def _upload_files(self, params):
        # We use requests.Request to construct our multipart/form-data request
        # here, because they are absurdly fiddly to compose, and Tornado
        # doesn't include a utility for building them. We then use self.fetch()
        # to actually send the request to the test server.
        req = requests.Request(method="POST",
                               url=self.get_url("/upload_file"),
                               files=params).prepare()

        return self.fetch("/upload_file",
                          method=req.method,
                          headers=req.headers,
                          body=req.body)

    def test_upload_one_file(self):
        """Uploading a file should populate our file_mgr."""
        file = UploadedFile("image.png", b"123")
        params = {
            file.name: file,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
        }
        response = self._upload_files(params)
        self.assertEqual(200, response.code)
        self.assertEqual([file],
                         self.file_mgr.get_files("fooReport", "barWidget"))

    def test_upload_multiple_files(self):
        file1 = UploadedFile("image1.png", b"123")
        file2 = UploadedFile("image2.png", b"456")
        file3 = UploadedFile("image3.png", b"789")

        params = {
            file1.name: file1,
            file2.name: file2,
            file3.name: file3,
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
        }
        response = self._upload_files(params)
        self.assertEqual(200, response.code)
        self.assertEqual(
            sorted([file1, file2, file3], key=_get_filename),
            sorted(self.file_mgr.get_files("fooReport", "barWidget"),
                   key=_get_filename),
        )

    def test_missing_params(self):
        """Missing params in the body should fail with 400 status."""
        params = {
            "image.png": ("image.png", b"1234"),
            "sessionId": (None, "fooReport"),
            # "widgetId": (None, 'barWidget'),
        }

        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIn("Missing 'widgetId'", response.reason)

    def test_missing_file(self):
        """Missing file should fail with 400 status."""
        params = {
            # "image.png": ("image.png", b"1234"),
            "sessionId": (None, "fooReport"),
            "widgetId": (None, "barWidget"),
        }
        response = self._upload_files(params)
        self.assertEqual(400, response.code)
        self.assertIn("Expected at least 1 file, but got 0", response.reason)
Example #6
0
class UploadedFileManagerTest(unittest.TestCase):
    def setUp(self):
        self.mgr = UploadedFileManager()
        self.filemgr_events = []
        self.mgr.on_files_updated.connect(self._on_files_updated)

    def _on_files_updated(self, file_list, **kwargs):
        self.filemgr_events.append(file_list)

    def test_add_file(self):
        self.assertIsNone(self.mgr.get_files("non-report", "non-widget"))

        self.mgr.update_file_count("session", "widget", 1)
        self.mgr.add_files("session", "widget", [file1])
        self.assertEqual([file1], self.mgr.get_files("session", "widget"))
        self.assertEqual(len(self.filemgr_events), 1)

        # Add another file with the same ID
        self.mgr.update_file_count("session", "widget", 2)
        self.mgr.add_files("session", "widget", [file2])
        self.assertEqual([file1, file2],
                         self.mgr.get_files("session", "widget"))
        self.assertEqual(len(self.filemgr_events), 2)

    def test_remove_file(self):
        # This should not error.
        self.mgr.remove_files("non-report", "non-widget")

        self.mgr.add_files("session", "widget", [file1])
        self.mgr.remove_file("session", "widget", file1.id)
        self.assertEqual([], self.mgr.get_files("session", "widget"))

        self.mgr.remove_file("session", "widget", file1.id)
        self.assertEqual([], self.mgr.get_files("session", "widget"))

        self.mgr.add_files("session", "widget", [file1])
        self.mgr.add_files("session", "widget", [file2])
        self.mgr.remove_file("session", "widget", file1.id)
        self.assertEqual([file2], self.mgr.get_files("session", "widget"))

    def test_remove_widget_files(self):
        # This should not error.
        self.mgr.remove_session_files("non-report")

        # Add two files with different session IDs, but the same widget ID.
        self.mgr.add_files("session1", "widget", [file1])
        self.mgr.add_files("session2", "widget", [file1])

        self.mgr.remove_files("session1", "widget")
        self.assertIsNone(self.mgr.get_files("session1", "widget"))
        self.assertEqual([file1], self.mgr.get_files("session2", "widget"))

    def test_remove_session_files(self):
        # This should not error.
        self.mgr.remove_session_files("non-report")

        # Add two files with different session IDs, but the same widget ID.
        self.mgr.add_files("session1", "widget1", [file1])
        self.mgr.add_files("session1", "widget2", [file1])
        self.mgr.add_files("session2", "widget", [file1])

        self.mgr.remove_session_files("session1")
        self.assertIsNone(self.mgr.get_files("session1", "widget1"))
        self.assertIsNone(self.mgr.get_files("session1", "widget2"))
        self.assertEqual([file1], self.mgr.get_files("session2", "widget"))

    def test_replace_widget_files(self):
        self.mgr.add_files("session1", "widget", [file1])
        self.mgr.replace_files("session1", "widget", [file2])

        self.assertEqual(len(self.mgr.get_files("session1", "widget")), 1)
        self.assertEqual([file2], self.mgr.get_files("session1", "widget"))