def test_unavailable_run_script_during_add_tasks(self):
        """
        - add tasks

        Expected: selenium log was saved and endpoint was deleted
        """
        from vmpool.artifact_collector import ArtifactCollector
        with patch(
            'core.db.Database', DatabaseMock()
        ):
            from core.db.models import Session, Endpoint, Provider
            session = Session("origin_1")
            session.id = self.session_id
            log_path = os.sep.join([self.artifact_dir, 'selenium_server.log'])

            provider = Provider(name='noname', url='nourl')
            endpoint = Endpoint(Mock(), '', provider)
            endpoint.ip = '127.0.0.1'
            endpoint.name = 'test_endpoint'
            endpoint.ports = {'selenium': '4455', 'agent': '9000', 'vnc': '5900'}

            session.endpoint = endpoint
            self.app.sessions.get_session = Mock(return_value=session)

            art_collector = ArtifactCollector(database=Mock())
            in_queue = art_collector.save_artifact(session, 'selenium_server.log', '/var/log/selenium_server.log')

        self.assertTrue(in_queue)
        self.assertTrue(wait_for(
            lambda: len(art_collector.get_queue()) == 0))
        with open(log_path, 'r') as f:
            text = f.read()
            self.assertIn('Connection refused', text)

        art_collector.stop()
Exemple #2
0
    def setUp(self):
        self.ctx = self.app.test_request_context()
        self.ctx.push()

        with patch('flask.current_app.database',
                   DatabaseMock()), patch('flask.current_app.sessions',
                                          Mock()):
            from core.db.models import Session, Provider, Endpoint
            self.session = Session('origin_1')
            self.session.name = "session1"

            provider = Provider(name='noname', url='nourl')
            vm = Endpoint(Mock(), '', provider)
            vm.name = 'vm1'
            vm.ip = self.host
            vm.ports = {
                'selenium': self.webdriver_server.port,
                'agent': self.vmmaster_agent.port,
                'vnc': self.vnc_server.port
            }
            self.session.endpoint = vm

            self.session.run()

            from vmmaster.webdriver import commands
            self.commands = commands
Exemple #3
0
    def test_when_during_proxy_starting_already_started_from_other_thread(
            self):
        from core.db.models import Session, Endpoint, Provider
        provider = Provider(name='noname', url='nourl')
        endpoint = Endpoint(Mock(), '', provider)
        endpoint.ip = '127.0.0.1'
        endpoint.name = 'test_endpoint'
        endpoint.ports = {'4455': 4455, '9000': 9000, '5900': 5900}
        session = Session("some_platform")
        session.id = 1
        session.name = "session1"
        session.status = "running"
        type(session).vnc_proxy_port = PropertyMock(
            side_effect=[None, 55555, 55555])
        session.vnc_proxy_pid = 55555
        session.created = session.modified = datetime.now()
        session.endpoint = endpoint
        session.stop_vnc_proxy = Mock()

        with patch('flask.current_app.sessions.get_session',
                   Mock(return_value=session)):
            response = self.vmmaster_client.get(
                '/api/session/{}/vnc_info'.format(session.id))
            session._close()

        body = json.loads(response.data)
        self.assertEqual(200, response.status_code)
        self.assertDictEqual({'vnc_proxy_port': 55555}, body['result'])
        self.assertEqual(200, body['metacode'])
        self.assertTrue(session.stop_vnc_proxy.called)
    def test_500_code_run_script_during_add_tasks(self):
        """
        - add tasks

        Expected: selenium log was saved and endpoint was deleted
        """
        from vmpool.artifact_collector import ArtifactCollector
        with patch(
            'core.db.Database', DatabaseMock()
        ):
            from core.db.models import Session, Endpoint, Provider
            session = Session("origin_1")
            session.id = self.session_id

            provider = Provider(name='noname', url='nourl')
            endpoint = Endpoint(Mock(), '', provider)
            endpoint.ip = '127.0.0.1'
            endpoint.name = 'test_endpoint'
            endpoint.ports = {'selenium': '4455', 'agent': '9000', 'vnc': '5900'}

            session.endpoint = endpoint
            art_collector = ArtifactCollector(database=Mock())
            in_queue = art_collector.save_artifact(session, 'selenium_server.log', '/var/log/selenium_server.log')

        self.assertTrue(in_queue)
        self.assertTrue(wait_for(
            lambda: len(art_collector.get_queue()) == 0))

        art_collector.stop()
Exemple #5
0
    def __init__(self):
        self.session = Session()
        self.ruz_api = RuzApi()
        self.nvr_api = Nvr_Api()
        self.calendar_api = GCalendar()

        self.ruz = self.session.query(OnlineRoom).filter_by(name="РУЗ").first()
        self.jitsi = self.session.query(OnlineRoom).filter_by(
            name="Jitsi").first()
Exemple #6
0
    def test_get_vnc_proxy_port_if_session_is_waiting(self):
        from core.db.models import Session, Endpoint, Provider
        provider = Provider(name='noname', url='nourl')
        endpoint = Endpoint(Mock(), '', provider)
        endpoint.ip = '127.0.0.1'
        endpoint.name = 'test_endpoint'
        endpoint.ports = {'4455': 4455, '9000': 9000, '5900': 5900}
        session = Session("some_platform")
        session.name = "session1"
        session.id = 1
        session.status = "waiting"
        session.vnc_proxy_port = None
        session.vnc_proxy_pid = None
        session.created = session.modified = datetime.now()
        session.endpoint = endpoint

        with patch('flask.current_app.sessions.get_session',
                   Mock(return_value=session)):
            response = self.vmmaster_client.get(
                '/api/session/{}/vnc_info'.format(session.id))

        body = json.loads(response.data)
        self.assertEqual(200, response.status_code)
        self.assertDictEqual({}, body['result'])
        self.assertEqual(500, body['metacode'])
Exemple #7
0
    def test_api_stop_session(self):
        from core.db.models import Session
        session = Session("some_platform")
        session.failed = Mock()

        with patch('flask.current_app.sessions.get_session',
                   Mock(return_value=session)):
            response = self.vmmaster_client.get("/api/session/{}/stop".format(
                session.id))
        body = json.loads(response.data)
        self.assertEqual(200, body['metacode'])

        session.failed.assert_any_call(
            reason=constants.SESSION_CLOSE_REASON_API_CALL)
Exemple #8
0
    def test_endpoints_cleanup(self):
        """
        - endpoint1 linked with session
        - endpoint2 not linked with session
        - both endpoints mark as 'deleted'
        expected: endpoint1 deleted, endpoint2 not deleted
        """
        class FakeOrigin(str):
            short_name = 'fake_short_name'

        from core.db.models import Session, Endpoint, Provider
        provider = Provider('name', 'url')
        endpoint1 = Endpoint(origin=FakeOrigin('fake'),
                             prefix='prefix',
                             provider=provider)
        endpoint2 = Endpoint(origin=FakeOrigin('fake'),
                             prefix='prefix',
                             provider=provider)
        endpoint1.deleted, endpoint2.deleted = True, True
        endpoint1.save(), endpoint2.save()

        session = Session(platform='some_platform',
                          name='__test_keep_forever_sessions_1')
        session.refresh()
        session.endpoint = endpoint1
        session.save()

        endpoints_to_delete = [
            e.id for e in self.cleanup.endpoints_to_delete()
        ]
        self.assertNotIn(endpoint1.id, endpoints_to_delete)
        self.assertIn(endpoint2.id, endpoints_to_delete)
Exemple #9
0
    def test_api_sessions(self):
        from core.db.models import Session
        session = Session(self.platform, "session1",
                          self.desired_caps["desiredCapabilities"])
        session.created = session.modified = datetime.now()

        with patch('flask.current_app.sessions.active',
                   Mock(return_value=[session])):
            response = self.vmmaster_client.get('/api/sessions')
        body = json.loads(response.data)
        self.assertEqual(200, response.status_code)

        sessions = body['result']['sessions']
        self.assertEqual(1, len(sessions))
        self.assertEqual(self.platform, session.platform)
        self.assertEqual(200, body['metacode'])

        session.failed()
Exemple #10
0
    def setUp(self):
        setup_config('data/config_openstack.py')
        self.host = "localhost"
        self.port = config.PORT
        self.address = (self.host, self.port)
        self.vmmaster = vmmaster_server_mock(self.port)
        self.assertTrue(server_is_up(self.address))
        self.free_port = get_free_port()

        self.ctx = self.vmmaster.app.app_context()
        self.ctx.push()

        from core.db.models import Session, Provider, Endpoint
        self.session = Session('some_platform')

        provider = Provider(name='noname', url='nourl')
        endpoint = Endpoint(Mock(), '', provider)
        endpoint.ip = 'localhost'
        self.session.endpoint = endpoint
Exemple #11
0
    def test_sessions_overflow(self):
        user = Mock(id=1, max_stored_sessions=0)
        from core.db.models import Session
        session = Session('some_platform')
        session.status = 'unknown'
        session.closed = True
        session.name = '__test_outdated_sessions'
        session.save()

        session_ids_to_delete = [
            p.id for p in self.cleanup.sessions_overflow(user)
        ]

        self.assertIn(session.id, session_ids_to_delete)
        self.cleanup.delete_session_data([session])
Exemple #12
0
    def test_file_deletion(self):
        from core.db.models import Session
        session = Session('some_platform')
        session.status = 'unknown'
        session.name = '__test_file_deletion'
        session.save()

        session_dir = os.path.join(config.SCREENSHOTS_DIR, str(session.id))
        system_utils.run_command(["mkdir", config.SCREENSHOTS_DIR],
                                 silent=True)
        system_utils.run_command(["mkdir", session_dir], silent=True)
        system_utils.run_command(
            ["touch", os.path.join(session_dir, "file_for_deletion")],
            silent=True)
        self.cleanup.delete_session_data([session])
        self.assertEqual(os.path.isdir(session_dir), 0)
        system_utils.run_command(["rm", "-rf", config.SCREENSHOTS_DIR],
                                 silent=True)
Exemple #13
0
def get_session():
    profiler.register_get_session_call()

    dc = commands.get_desired_capabilities(request)
    matched_platform, provider_id = current_app.get_matched_platforms(dc)
    if not matched_platform:
        raise SessionException("Cannot match platform for DesiredCapabilities: {}".format(dc))

    session = Session(platform=matched_platform, dc=dc, provider_id=provider_id)
    request.session = session
    log.info("New session {}({}) on provider {} with dc: {}".format(session.id, session.name, provider_id, dc))
    yield session

    start_time = time.time()
    while not session.endpoint_id:
        time.sleep(constants.GET_SESSION_SLEEP_TIME)
        if time.time() - start_time >= config.GET_VM_TIMEOUT:
            raise CreationException("Timeout getting endpoint for {}".format(session))
        session.refresh()
        yield session

    session.run()
    yield session
Exemple #14
0
class TestHttpProxy(BaseTestCase):
    def setUp(self):
        setup_config('data/config_openstack.py')
        self.host = "localhost"
        self.port = config.PORT
        self.address = (self.host, self.port)
        self.vmmaster = vmmaster_server_mock(self.port)
        self.assertTrue(server_is_up(self.address))
        self.free_port = get_free_port()

        self.ctx = self.vmmaster.app.app_context()
        self.ctx.push()

        from core.db.models import Session, Provider, Endpoint
        self.session = Session('some_platform')

        provider = Provider(name='noname', url='nourl')
        endpoint = Endpoint(Mock(), '', provider)
        endpoint.ip = 'localhost'
        self.session.endpoint = endpoint

    def tearDown(self):
        self.session._close()
        self.ctx.pop()
        self.vmmaster.app.sessions.kill_all()
        self.vmmaster.app.cleanup()
        self.vmmaster.stop_services()
        self.assertTrue(server_is_down(self.address))

    def test_proxy_successful(self):
        server = ServerMock(self.host, self.free_port)
        server.start()
        with patch(
            'core.sessions.Sessions.get_session', Mock(
                return_value=self.session)
        ):
            response = requests.get(
                "http://%s:%s/proxy/session/%s/port/%s/" %
                (self.host, self.port, self.session.id, self.free_port)
            )
        server.stop()
        self.assertEqual("ok", response.content)

    def test_proxy_responses_when_trying_to_connect_failed(self):
        with patch(
            'core.sessions.Sessions.get_session', Mock(
                return_value=self.session)
        ):
            response = requests.get(
                "http://%s:%s/proxy/session/%s/port/%s/" %
                (self.host, self.port, self.session.id, self.free_port)
            )
        self.assertEqual(
            "Request forwarding failed:\n"
            "Connection was refused by other side: 111: Connection refused.",
            response.content)

    def test_proxy_to_session_that_was_closed(self):
        self.session.succeed()
        with patch(
            'flask.current_app.database.get_session',
            Mock(return_value=self.session)
        ):
            response = requests.get(
                "http://%s:%s/proxy/session/%s/port/%s/" %
                (self.host, self.port, self.session.id, self.free_port)
            )
        self.assertIn(
            "Session {}(Success) already closed earlier".format(self.session.id),
            response.content
        )

    def test_proxy_with_wrong_path(self):
        response = requests.get(
            "http://%s:%s/proxy/asdf/%s/" %
            (self.host, self.port, self.free_port)
        )
        self.assertEqual(
            "Couldn't parse request uri, "
            "make sure you request uri has "
            "/proxy/session/<session_id>/port/<port_number>/<destination>",
            response.content)
Exemple #15
0
class CommonCommandsTestCase(BaseTestCase):
    webdriver_server = None
    vmmaster_agent = None
    vnc_server = None
    host = 'localhost'

    @classmethod
    def setUpClass(cls):
        setup_config("data/config_openstack.py")
        body = {
            "sessionId": None,
            "desiredCapabilities": {
                "platform": "some_platform",
                "browserName": "firefox",
                "version": "",
                "javascriptEnabled": True
            }
        }
        session_request_body = json.dumps(body)
        session_request_headers = {
            'content-length': '%s' % len(session_request_body),
            'accept-encoding': 'identity',
            'Connection': 'close',
            'accept': 'application/json',
            'user-agent': 'Python-urllib/2.7',
            'host': '127.0.0.1:9000',
            'content-type': 'application/json;charset=UTF-8',
        }
        cls.request = Mock()
        cls.request.method = "POST"
        cls.request.path = "/wd/hub/session"
        cls.request.headers = dict()
        cls.request.headers.update(session_request_headers)
        cls.request.data = session_request_body

        cls.webdriver_server = ServerMock(cls.host, get_free_port())
        cls.webdriver_server.start()
        cls.vmmaster_agent = ServerMock(cls.host, get_free_port())
        cls.vmmaster_agent.start()
        cls.vnc_server = ServerMock(cls.host, get_free_port())
        cls.vnc_server.start()

        cls.app = Flask(__name__)
        cls.app.database = None
        cls.app.sessions = None
        cls.app.database_task_queue = Mock()
        cls.app.pool = Mock()

    def setUp(self):
        self.ctx = self.app.test_request_context()
        self.ctx.push()

        with patch('flask.current_app.database',
                   DatabaseMock()), patch('flask.current_app.sessions',
                                          Mock()):
            from core.db.models import Session, Provider, Endpoint
            self.session = Session('origin_1')
            self.session.name = "session1"

            provider = Provider(name='noname', url='nourl')
            vm = Endpoint(Mock(), '', provider)
            vm.name = 'vm1'
            vm.ip = self.host
            vm.ports = {
                'selenium': self.webdriver_server.port,
                'agent': self.vmmaster_agent.port,
                'vnc': self.vnc_server.port
            }
            self.session.endpoint = vm

            self.session.run()

            from vmmaster.webdriver import commands
            self.commands = commands

    def tearDown(self):
        with patch('flask.current_app.sessions',
                   Mock()), patch('flask.current_app.database', Mock()):
            self.session._close()
        self.ctx.pop()

    @classmethod
    def tearDownClass(cls):
        cls.webdriver_server.stop()
        cls.vmmaster_agent.stop()
        cls.vnc_server.stop()
        del cls.app
Exemple #16
0
    def test_get_vnc_port_if_running_proxy(self):
        from core.db.models import Session, Endpoint, Provider
        provider = Provider(name='noname', url='nourl')
        endpoint = Endpoint(Mock(), '', provider)
        endpoint.ip = '127.0.0.1'
        endpoint.name = 'test_endpoint'
        endpoint.ports = {'4455': 4455, '9000': 9000, '5900': 5900}
        session = Session("some_platform")
        session.id = 1
        session.name = "session1"
        session.status = "running"
        session.vnc_proxy_port = 55555
        session.vnc_proxy_pid = 55555
        session.created = session.modified = datetime.now()
        session.endpoint = endpoint
        session.stop_vnc_proxy = Mock()

        with patch('flask.current_app.sessions.get_session',
                   Mock(return_value=session)), patch(
                       'core.utils.kill_process', Mock(return_value=True)):
            response = self.vmmaster_client.get('/api/session/%s/vnc_info' %
                                                session.id)
            session._close()

        body = json.loads(response.data)
        self.assertEqual(200, response.status_code)
        self.assertDictEqual({'vnc_proxy_port': 55555}, body['result'])
        self.assertEqual(200, body['metacode'])
        self.assertTrue(session.stop_vnc_proxy.called)
Exemple #17
0
    def test_session_keep_forever(self):
        user = Mock(id=1, max_stored_sessions=0)

        from core.db.models import Session
        session1 = Session(platform='some_platform',
                           name='__test_keep_forever_sessions_1')
        session1.closed = True
        session1.keep_forever = True
        session1.save()

        session2 = Session(platform='some_platform',
                           name='__test_keep_forever_sessions_2')
        session2.closed = True
        session2.keep_forever = False
        session2.save()

        session_ids_to_delete = [
            p.id for p in self.cleanup.sessions_overflow(user)
        ]

        self.assertNotIn(session1.id, session_ids_to_delete)
        self.assertIn(session2.id, session_ids_to_delete)

        self.cleanup.delete_session_data([session1, session2])
Exemple #18
0
class CalendarManager:
    def __init__(self):
        self.session = Session()
        self.ruz_api = RuzApi()
        self.nvr_api = Nvr_Api()
        self.calendar_api = GCalendar()

        self.ruz = self.session.query(OnlineRoom).filter_by(name="РУЗ").first()
        self.jitsi = self.session.query(OnlineRoom).filter_by(
            name="Jitsi").first()

    def __del__(self):
        self.session.close()

    async def get_rooms(self):
        offline_rooms = [room.name for room in self.session.query(Room).all()]

        rooms = await self.ruz_api.get_auditoriumoid()

        tasks = [
            self.synchronize_lessons_in_room(room["auditoriumOid"],
                                             offline_rooms, room["number"])
            for room in rooms
        ]

        await asyncio.gather(*tasks)

        logger.info(
            f"Created events for {datetime.today().date() + timedelta(days=1)} - {datetime.today().date() + timedelta(days=self.ruz_api.period)}"
        )

    async def synchronize_lessons_in_room(self, room_id: str,
                                          offline_rooms: list, room_name: str):
        lessons = await self.get_lessons_from_room(room_id)

        if lessons:
            logger.info(f"""
                Successfully got lessons for room {room_name}
                Synchronizing lessons in calendar and Erudite
                """)
            # Deletes lessons from Erudite if it doesn't exist in Ruz
            await self.nvr_api.check_delete_Erudite_lessons(lessons, room_id)
            time.sleep(0.2)

            for i in range(0, len(lessons), 10):
                chunk = lessons[i:i + 10]

                tasks = [
                    self.synchronize_lesson(room_id, lesson, offline_rooms)
                    for lesson in chunk
                ]
                await asyncio.gather(*tasks)

    async def get_lessons_from_room(self, room_id: str) -> list:
        """ Get lessons in room from ruz """

        try:
            lessons = await self.ruz_api.get_lessons(room_id)
        except Exception as err:
            lessons = None
            logger.error(err)

        return lessons

    async def synchronize_lesson(
        self,
        room_id: str,
        lesson: dict,
        offline_rooms: list,
    ):
        check_data = await self.nvr_api.check_lesson(lesson)
        status = check_data[0]

        # Lesson not found in Erudite, so we add it
        if status == "Not found":
            await self.add_lesson(lesson, offline_rooms)

        # Lesson found in Erudite, but the data of this lesson has to be updated
        elif status == "Update":
            lesson_id = check_data[1]
            event_id = check_data[2]
            await self.update_lesson(lesson, offline_rooms, lesson_id,
                                     event_id)
            time.sleep(0.6)

    async def add_lesson(self, lesson: dict, offline_rooms: list):
        """ Adds lesson to Erudite and Google Calendar """

        if lesson["ruz_url"] is None or "meet.miem.hse.ru" not in lesson[
                "ruz_url"]:
            logger.info("Adding ruz lesson")
            data = await self.test_post_lesson(lesson)
            code = data[0]
            erudite_lesson = data[1]
            event = None
            if code == 201 or code == 409:
                try:
                    event = await self.post_lesson(lesson,
                                                   erudite_lesson["id"],
                                                   self.ruz.calendar)
                    time.sleep(0.6)
                except:
                    logger.warning(f"Erudite returned - {erudite_lesson}")

            if lesson["ruz_auditorium"] in offline_rooms and event:
                room = self.session.query(Room).filter_by(
                    name=lesson["ruz_auditorium"]).first()
                self.create_record(room, event)

        elif lesson["ruz_url"] is not None and "meet.miem.hse.ru" in lesson[
                "ruz_url"]:
            logger.info("Adding jitsi lesson")
            data = await self.test_post_lesson(lesson)
            code = data[0]
            erudite_lesson = data[1]
            if code == 201 or code == 409:
                try:
                    event = await self.post_lesson(lesson,
                                                   erudite_lesson["id"],
                                                   self.jitsi.calendar)
                except:
                    logger.warning(f"Erudite returned - {erudite_lesson}")

    async def update_lesson(self, lesson: dict, offline_rooms: list,
                            lesson_id: str, event_id: str):
        """ Updates lesson in Erudite and Google Calendar """

        if lesson["ruz_url"] is None or "meet.miem.hse.ru" not in lesson[
                "ruz_url"]:
            logger.info("Updating ruz lesson")
            try:
                event = await self.calendar_api.update_event(
                    self.ruz.calendar, event_id, lesson)
                lesson["gcalendar_event_id"] = event["id"]
                lesson["gcalendar_calendar_id"] = self.ruz.calendar
            except:
                logger.warning(
                    "Lesson could not be updated succesfully in calendar")
            await self.nvr_api.update_lesson(lesson_id, lesson)

            # if lesson["ruz_auditorium"] in offline_rooms:
            #     room = self.session.query(Room).filter_by(name=lesson["ruz_auditorium"]).first()
            #     self.create_record(room, event)

        elif lesson["ruz_url"] is not None and "meet.miem.hse.ru" in lesson[
                "ruz_url"]:
            logger.info("Updating jitsi lesson")
            try:
                event = await self.calendar_api.update_event(
                    self.jitsi.calendar, event_id, lesson)
                lesson["gcalendar_event_id"] = event["id"]
                lesson["gcalendar_calendar_id"] = self.jitsi.calendar
            except:
                logger.warning(
                    "Lesson could not be updated succesfully in calendar")
            await self.nvr_api.update_lesson(lesson_id, lesson)

    async def test_post_lesson(self, lesson: dict):
        """ Post a lesson with empty event_id """

        lesson = dict(lesson)  # make copy

        lesson["gcalendar_event_id"] = ""
        lesson["gcalendar_calendar_id"] = ""

        data = await self.nvr_api.add_lesson(lesson)

        return data

    async def post_lesson(self, lesson: dict, lesson_id: str,
                          calendar_id: str):
        """ Posts event to Google calendar and updates lesson in Erudite """

        event = await self.calendar_api.create_event(self.ruz.calendar, lesson)
        lesson["gcalendar_event_id"] = event["id"]
        lesson["gcalendar_calendar_id"] = calendar_id
        await self.nvr_api.update_lesson(lesson_id, lesson)

        return event

    def create_record(self, room: Room, event: dict):
        start_date = event["start"]["dateTime"].split("T")[0]
        end_date = event["end"]["dateTime"].split("T")[0]

        if start_date != end_date:
            return

        creator = self.session.query(User).filter_by(
            email=event["creator"]["email"]).first()
        if not creator:
            return

        new_record = Record()
        new_record.room = room
        new_record.update_from_calendar(**event)
        self.session.add(new_record)
        self.session.commit()

        user_record = UserRecord(user_id=creator.id, record_id=new_record.id)
        self.session.add(user_record)
        self.session.commit()

    async def delete_online_events(self):
        while True:
            events = await self.calendar_api.get_events(self.jitsi.calendar)
            if len(events) == 0:
                break
            for event in events:
                await self.calendar_api.delete_event(self.jitsi.calendar,
                                                     event["id"])

        while True:
            events = await self.calendar_api.get_events(self.ruz.calendar)
            if len(events) == 0:
                break
            for event in events:
                await self.calendar_api.delete_event(self.ruz.calendar,
                                                     event["id"])