Example #1
0
 def test_display_name(self, formatdate):
     formatdate.return_value = "11111"
     meeting = Meeting("n", "c", "n")
     meeting.start_time = datetime(2021, 3, 7, 13, 14,
                                   0)  # in UTC by default
     assert meeting.display_name() == "c/n@11111"
     formatdate.assert_called_once_with(meeting.start_time)
Example #2
0
 def test_track_nick(self):
     meeting = Meeting("nick", "channel", "network")
     meeting.track_nick("xxx")
     assert meeting.nicks["xxx"] == 1
     meeting.track_nick("yyy", messages=0)
     assert meeting.nicks["yyy"] == 0
     meeting.track_nick("nick")
     assert meeting.nicks["nick"] == 1
     meeting.track_nick("nick", messages=4)
     assert meeting.nicks["nick"] == 5
Example #3
0
 def test_track_message_non_action(self):
     message = Message("id", MagicMock(), "nick", "channel", "network",
                       "Hello, world")
     meeting = Meeting("n", "c", "n")
     tracked = meeting.track_message(message)
     assert meeting.nicks["nick"] == 1
     assert tracked in meeting.messages
     assert tracked.sender == "nick"
     assert tracked.payload == "Hello, world"
     assert tracked.action is False
Example #4
0
 def test_track_event_no_attributes(self):
     meeting = Meeting("n", "c", "n")
     timestamp = MagicMock()
     message = MagicMock(timestamp=timestamp)
     tracked = meeting.track_event(event_type=EventType.VOTE,
                                   message=message)
     assert tracked in meeting.events
     assert tracked.id is not None
     assert tracked.event_type == EventType.VOTE
     assert tracked.message is message
     assert tracked.timestamp is timestamp
     assert tracked.operand is None
Example #5
0
 def test_track_message_action(self):
     # Trying to replicate "^AACTION waves goodbye^A" as in the Wikipedia article
     # See "DCC CHAT" under: https://en.wikipedia.org/wiki/Client-to-client_protocol
     message = Message("id", MagicMock(), "nick", "channel", "network",
                       "\x01ACTION waves goodbye\x01")
     meeting = Meeting("n", "c", "n")
     tracked = meeting.track_message(message)
     assert meeting.nicks["nick"] == 1
     assert tracked in meeting.messages
     assert tracked.id is not None
     assert tracked.sender == "nick"
     assert tracked.payload == "waves goodbye"
     assert tracked.action is True
Example #6
0
    def test_track_attendee(self):
        meeting = Meeting("n", "c", "n")

        meeting.track_attendee("one", None)
        assert meeting.nicks["one"] == 0
        assert meeting.aliases["one"] is None

        meeting.track_attendee("two", "three")
        assert meeting.nicks["two"] == 0
        assert meeting.aliases["two"] == "three"

        meeting.track_attendee("one", "four")
        assert meeting.nicks["one"] == 0
        assert meeting.aliases["one"] == "four"

        meeting.track_attendee("five", "five")
        assert meeting.nicks["five"] == 0
        assert meeting.aliases[
            "five"] is None  # an equivalent alias is not tracked
Example #7
0
 def test_constructor(self):
     before = datetime.now(utc)
     meeting = Meeting("nick", "channel", "network")
     assert meeting.id is not None
     assert meeting.name == "channel"
     assert meeting.founder == "nick"
     assert meeting.channel == "channel"
     assert meeting.network == "network"
     assert meeting.chair == "nick"
     assert meeting.chairs == ["nick"]
     assert meeting.nicks == {"nick": 0}
     assert meeting.start_time >= before
     assert meeting.end_time is None
     assert meeting.original_topic is None
     assert meeting.current_topic is None
     assert meeting.messages == []
     assert meeting.events == []
     assert meeting.aliases == {}
     assert meeting.key() == "channel/network"
     assert meeting.active is False
Example #8
0
 def test_derive_locations_with_attempted_path_traversal_relative(self):
     config = Config(
         conf_file=None,
         log_dir="/data/meetings/hcoop",
         url_prefix="https://whatever",
         timezone="UTC",
         pattern="%Y/../../%m%d.%H%M",
     )
     meeting = Meeting(id="i",
                       name="n",
                       founder="f",
                       channel="c",
                       network="n",
                       start_time=datetime(2021, 3, 7, 13, 14, 0))
     with pytest.raises(ValueError):
         derive_locations(config, meeting)
Example #9
0
 def test_derive_locations_with_attempted_path_traversal_absolute(self):
     config = Config(conf_file=None,
                     log_dir="/data/meetings/hcoop",
                     url_prefix="https://whatever",
                     timezone="UTC",
                     pattern="/%Y%m%d.%H%M")
     meeting = Meeting(id="i",
                       name="n",
                       founder="f",
                       channel="c",
                       network="n",
                       start_time=datetime(2021, 3, 7, 13, 14, 0))
     locations = derive_locations(config, meeting)
     assert locations.log.path == "/data/meetings/hcoop/20210307.1314.log.html"
     assert locations.log.url == "https://whatever/20210307.1314.log.html"
     assert locations.minutes.path == "/data/meetings/hcoop/20210307.1314.html"
     assert locations.minutes.url == "https://whatever/20210307.1314.html"
Example #10
0
 def test_pop_event(self):
     meeting = Meeting("n", "c", "n")
     timestamp = MagicMock()
     message = MagicMock(timestamp=timestamp)
     start = meeting.track_event(event_type=EventType.START_MEETING,
                                 message=message)
     assert start in meeting.events
     vote = meeting.track_event(event_type=EventType.VOTE, message=message)
     assert vote in meeting.events
     assert meeting.pop_event() is vote
     assert start in meeting.events
     assert meeting.pop_event() is None
Example #11
0
 def test_derive_locations_with_subsitution_variables(self):
     config = Config(
         conf_file=None,
         log_dir="/data/meetings/hcoop",
         url_prefix="https://whatever",
         timezone="UTC",
         pattern="{id}-{name}-{founder}-{channel}-{network}",
     )
     meeting = Meeting(id="i",
                       name="n",
                       founder="f",
                       channel="c",
                       network="n",
                       start_time=datetime(2021, 3, 7, 13, 14, 0))
     locations = derive_locations(config, meeting)
     assert locations.log.path == "/data/meetings/hcoop/i-n-f-c-n.log.html"
     assert locations.log.url == "https://whatever/i-n-f-c-n.log.html"
     assert locations.minutes.path == "/data/meetings/hcoop/i-n-f-c-n.html"
     assert locations.minutes.url == "https://whatever/i-n-f-c-n.html"
Example #12
0
 def test_derive_locations_with_constant_pattern(self):
     config = Config(
         conf_file=None,
         log_dir="/data/meetings/hcoop",
         url_prefix="https://whatever",
         timezone="UTC",
         pattern="constant",
     )
     meeting = Meeting(id="i",
                       name="n",
                       founder="f",
                       channel="c",
                       network="n",
                       start_time=datetime(2021, 3, 7, 13, 14, 0))
     locations = derive_locations(config, meeting)
     assert locations.log.path == "/data/meetings/hcoop/constant.log.html"
     assert locations.log.url == "https://whatever/constant.log.html"
     assert locations.minutes.path == "/data/meetings/hcoop/constant.html"
     assert locations.minutes.url == "https://whatever/constant.html"
Example #13
0
 def test_derive_locations_with_normalization(self):
     config = Config(
         conf_file=None,
         log_dir="/data/meetings/hcoop",
         url_prefix="https://whatever",
         timezone="UTC",
         pattern="{name}",
     )
     meeting = Meeting(
         id="i",
         name=
         r"!@#$%^&*()+=][}{}~`?<>,{network}\\",  # more than 1 consecutive bad char is normalized to single _
         founder="f",
         channel="c",
         network="n",
         start_time=datetime(2021, 3, 7, 13, 14, 0),
     )
     locations = derive_locations(config, meeting)
     assert locations.log.path == "/data/meetings/hcoop/_network_.log.html"
     assert locations.log.url == "https://whatever/_network_.log.html"
     assert locations.minutes.path == "/data/meetings/hcoop/_network_.html"
     assert locations.minutes.url == "https://whatever/_network_.html"
Example #14
0
def _meeting() -> Meeting:
    """Generate a semi-realistic meeting that can be used for unit tests"""

    # Initialize the meeting
    meeting = Meeting(founder="pronovic", channel="#hcoop", network="network")

    # this gets us some data in the attendees section without having to add tons of messages
    meeting.track_nick("unknown_lamer", 13)
    meeting.track_nick("layline", 32)
    meeting.track_nick("bhkl", 3)

    # Start the meeting
    meeting.active = True
    meeting.start_time = _time(0)
    tracked = meeting.track_message(
        message=_message(0, "pronovic", "#startmeeting", 0))
    meeting.track_event(event_type=EventType.START_MEETING, message=tracked)

    # these messages and events will be associated with the prologue, because no topic has been set yet
    tracked = meeting.track_message(message=_message(
        1, "pronovic", "Hello everyone, is it ok to get started?", 32))
    tracked = meeting.track_message(
        message=_message(2, "unknown_lamer", "Yeah, let's do it", 97))
    tracked = meeting.track_message(message=_message(
        3, "pronovic",
        "#link Agenda at https://whatever/agenda.html like usual", 123))
    meeting.track_event(
        event_type=EventType.LINK,
        message=tracked,
        operand="Agenda at https://whatever/agenda.html like usual")

    # these messages and events are associated with the attendance topic
    # note that we track attendees manually since that's what would be done by the command interpreter
    tracked = meeting.track_message(
        message=_message(4, "pronovic", "#topic Attendance", 125))
    meeting.track_event(event_type=EventType.TOPIC,
                        message=tracked,
                        operand="Attendance")
    tracked = meeting.track_message(message=_message(
        5, "pronovic",
        'If you are present please write "#here $hcoop_username"', 126))
    tracked = meeting.track_message(message=_message(
        6, "pronovic", "#here Pronovic", 127))  # note: alias != nick
    meeting.track_event(event_type=EventType.ATTENDEE,
                        message=tracked,
                        operand="Pronovic")
    meeting.track_attendee(nick="pronovic", alias="Pronovic")
    tracked = meeting.track_message(message=_message(
        7, "unknown_lamer", "#here Clinton Alias", 128))  # note: alias != nick
    meeting.track_event(event_type=EventType.ATTENDEE,
                        message=tracked,
                        operand="Clinton Alias")
    meeting.track_attendee(nick="unknown_lamer", alias="Clinton Alias")
    tracked = meeting.track_message(message=_message(
        8, "keverets", "#here keverets", 129))  # note: alias == nick
    meeting.track_event(event_type=EventType.ATTENDEE,
                        message=tracked,
                        operand="keverets")
    meeting.track_attendee(nick="keverets", alias="keverets")
    tracked = meeting.track_message(message=_message(
        9, "layline", "#here", 130))  # note: no alias, so it's set to nick
    meeting.track_event(event_type=EventType.ATTENDEE,
                        message=tracked,
                        operand="layline")
    meeting.track_attendee(nick="layline", alias="layline")
    tracked = meeting.track_message(
        message=_message(10, "pronovic", "Thanks, everyone", 130))

    # these messages and events are associated with the first topic
    tracked = meeting.track_message(
        message=_message(11, "pronovic", "#topic The first topic", 199))
    meeting.track_event(event_type=EventType.TOPIC,
                        message=tracked,
                        operand="The first topic")
    tracked = meeting.track_message(message=_message(
        12, "pronovic", "Does anyone have any discussion?", 231))
    tracked = meeting.track_message(
        message=_message(13, "layline", "Is this important?", 232))
    tracked = meeting.track_message(
        message=_message(14, "unknown_lamer", "Yes it is", 299))
    tracked = meeting.track_message(
        message=_message(15, "pronovic", "#info moving on then", 305))
    meeting.track_event(event_type=EventType.INFO,
                        message=tracked,
                        operand="moving on then")

    # these messages and events are associated with the second topic
    tracked = meeting.track_message(
        message=_message(16, "pronovic", "#topic The second topic", 332))
    meeting.track_event(event_type=EventType.TOPIC,
                        message=tracked,
                        operand="The second topic")
    tracked = meeting.track_message(message=_message(
        17, "layline", "\x01unknown_lamer: I need you for this action\x01",
        334))
    tracked = meeting.track_message(message=_message(
        18, "pronovic", "#action clinton alias will work with layline on this",
        401))
    meeting.track_event(event_type=EventType.ACTION,
                        message=tracked,
                        operand="clinton alias will work with layline on this")

    # these messages and events are associated with the third topic
    tracked = meeting.track_message(
        message=_message(19, "pronovic", "#topic The third topic", 407))
    meeting.track_event(event_type=EventType.TOPIC,
                        message=tracked,
                        operand="The third topic")
    tracked = meeting.track_message(message=_message(
        20, "pronovic", "#idea we should improve MeetBot", 414))
    meeting.track_event(event_type=EventType.IDEA,
                        message=tracked,
                        operand="we should improve MeetBot")
    tracked = meeting.track_message(message=_message(
        21, "pronovic", "I'll just take this one myself", 435))
    tracked = meeting.track_message(message=_message(
        22, "pronovic", "#action Pronovic will deal with it", 449))
    meeting.track_event(event_type=EventType.ACTION,
                        message=tracked,
                        operand="Pronovic will deal with it")

    # these messages and events are associated with the final topic
    tracked = meeting.track_message(
        message=_message(23, "pronovic", "#topic Cross-site Scripting", 453))
    tracked = meeting.track_message(message=_message(
        24, "pronovic", "#action <script>alert('malicious')</script>", 497))
    meeting.track_event(event_type=EventType.ACTION,
                        message=tracked,
                        operand="<script>alert('malicious')</script>")
    tracked = meeting.track_message(
        message=_message(25, "pronovic", "#motion the motion", 502))
    meeting.track_event(event_type=EventType.MOTION,
                        message=tracked,
                        operand="the motion")
    tracked = meeting.track_message(
        message=_message(26, "pronovic", "#vote +1", 553))
    meeting.track_event(event_type=EventType.VOTE,
                        message=tracked,
                        operand=VotingAction.IN_FAVOR)
    tracked = meeting.track_message(
        message=_message(27, "unknown_lamer", "#vote +1", 555))
    meeting.track_event(event_type=EventType.VOTE,
                        message=tracked,
                        operand=VotingAction.IN_FAVOR)
    tracked = meeting.track_message(
        message=_message(28, "layline", "#vote -1", 557))
    meeting.track_event(event_type=EventType.VOTE,
                        message=tracked,
                        operand=VotingAction.OPPOSED)
    tracked = meeting.track_message(
        message=_message(29, "pronovic", "#close", 559))
    meeting.track_event(event_type=EventType.ACCEPTED,
                        message=tracked,
                        operand="Motion accepted: 2 in favor to 1 opposed")

    # End the meeting
    tracked = meeting.track_message(
        message=_message(30, "pronovic", "#endmeeting", 567))
    meeting.track_event(event_type=EventType.END_MEETING, message=tracked)
    meeting.active = False
    meeting.end_time = _time(567)

    return meeting
Example #15
0
    def test_chair_behavior(self):
        meeting = Meeting("nick", "channel", "network")
        assert meeting.chair == "nick"
        assert meeting.chairs == ["nick"]
        assert meeting.nicks == {"nick": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is False
        assert meeting.is_chair("yyy") is False
        assert meeting.is_chair("zzz") is False

        meeting.add_chair("yyy")
        assert meeting.founder == "nick"
        assert meeting.chair == "yyy"
        assert meeting.chairs == ["nick", "yyy"]
        assert meeting.nicks == {"nick": 0, "yyy": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is False
        assert meeting.is_chair("yyy") is True
        assert meeting.is_chair("zzz") is False

        meeting.add_chair("xxx", primary=False)
        assert meeting.founder == "nick"
        assert meeting.chair == "yyy"
        assert meeting.chairs == ["nick", "xxx", "yyy"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is True
        assert meeting.is_chair("zzz") is False

        meeting.add_chair("nick")
        assert meeting.founder == "nick"
        assert meeting.chair == "nick"
        assert meeting.chairs == ["nick", "xxx", "yyy"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is True
        assert meeting.is_chair("zzz") is False

        meeting.add_chair("zzz")
        assert meeting.founder == "nick"
        assert meeting.chair == "zzz"
        assert meeting.chairs == ["nick", "xxx", "yyy", "zzz"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0, "zzz": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is True
        assert meeting.is_chair("zzz") is True

        meeting.remove_chair("yyy")
        assert meeting.founder == "nick"
        assert meeting.chair == "zzz"
        assert meeting.chairs == ["nick", "xxx", "zzz"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0, "zzz": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is False
        assert meeting.is_chair("zzz") is True

        meeting.remove_chair("nick")  # you can't remove the founder
        assert meeting.founder == "nick"
        assert meeting.chair == "zzz"
        assert meeting.chairs == ["nick", "xxx", "zzz"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0, "zzz": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is False
        assert meeting.is_chair("zzz") is True

        meeting.remove_chair(
            "zzz")  # removing the primary chair makes the founder the primary
        assert meeting.founder == "nick"
        assert meeting.chair == "nick"
        assert meeting.chairs == ["nick", "xxx"]
        assert meeting.nicks == {"nick": 0, "xxx": 0, "yyy": 0, "zzz": 0}
        assert meeting.is_chair("nick") is True
        assert meeting.is_chair("xxx") is True
        assert meeting.is_chair("yyy") is False
        assert meeting.is_chair("zzz") is False
Example #16
0
 def test_meeting_key(self):
     assert Meeting.meeting_key("channel", "network") == "channel/network"