def test_pickle_rick(dump_pickle): try: threading.Thread(target=chatcommunicate.pickle_last_messages, daemon=True).start() chatcommunicate._pickle_run.set() # Yield to the pickling thread until it acquires the lock again while len(chatcommunicate._pickle_run._cond._waiters) == 0: time.sleep(0) assert dump_pickle.call_count == 1 call, _ = dump_pickle.call_args_list[0] assert call[0] == "messageData.p" assert isinstance(call[1], chatcommunicate.LastMessages) finally: remove_pickle("messageData.p")
def test_blacklisted_user(): user_url = 'https://stackoverflow.com/users/1/jeff-atwood' user = get_user_from_url(user_url) add_blacklisted_user(user, "", "") # Construct a "fake" post object in API-format post = Post( api_response={ 'title': '', 'body': '', 'owner': { 'display_name': user, 'reputation': 1, 'link': user_url }, 'site': 'stackoverflow.com', 'question_id': '1', 'IsAnswer': False, 'score': 0 }) is_spam, reason, _ = check_if_spam(post) assert is_spam is True # cleanup remove_pickle("blacklistedUsers.p")
def test_notifications(): chatcommunicate.parse_room_config("test/test_rooms.yml") try: msg1 = Fake({ "owner": { "name": "El'endia Starman", "id": 1, "is_moderator": False }, "room": { "id": 11540, "_client": { "host": "stackexchange.com" } }, "_client": { "host": "stackexchange.com" } }) msg2 = Fake({ "owner": { "name": "angussidney", "id": 145827, "is_moderator": False }, "room": { "id": 11540, "_client": { "host": "stackexchange.com" } }, "_client": { "host": "stackexchange.com" } }) # User 1 assert chatcommands.allnotificationsites("11540", original_msg=msg1) == \ "You won't get notified for any sites in that room." assert chatcommands.willbenotified("11540", "gaming", original_msg=msg1) == \ "No, you won't be notified for that site in that room." assert chatcommands.notify("11540", "gaming", None, original_msg=msg1) == \ "You'll now get pings from me if I report a post on `gaming`, in room `11540` on `chat.stackexchange.com`." assert chatcommands.notify("11540", "codegolf.stackexchange.com", None, original_msg=msg1) == \ "You'll now get pings from me if I report a post on `codegolf.stackexchange.com`, in room `11540` on " \ "`chat.stackexchange.com`." # Check for additional text when notifying only when in room assert chatcommands.notify("11540", "meta.stackexchange.com", False, original_msg=msg1) == \ "You'll now get pings from me if I report a post on `meta.stackexchange.com`, in room `11540` on " \ "`chat.stackexchange.com`, but only when you're in that room." # Remove notification which is active only when in room assert chatcommands.unnotify("11540", "meta.stackexchange.com", original_msg=msg1) == \ "I will no longer ping you if I report a post on `meta.stackexchange.com`, in room `11540` on " \ "`chat.stackexchange.com`." assert chatcommands.willbenotified("11540", "gaming.stackexchange.com", original_msg=msg1) == \ "Yes, you will be notified for that site in that room." assert chatcommands.willbenotified("11540", "codegolf", original_msg=msg1) == \ "Yes, you will be notified for that site in that room." # User 2 assert chatcommands.allnotificationsites("11540", original_msg=msg2) == \ "You won't get notified for any sites in that room." assert chatcommands.willbenotified("11540", "raspberrypi", original_msg=msg2) == \ "No, you won't be notified for that site in that room." assert chatcommands.notify("11540", "raspberrypi", None, original_msg=msg2) == \ "You'll now get pings from me if I report a post on `raspberrypi`, in room `11540` on `chat.stackexchange.com`." assert chatcommands.notify("11540", "raspberrypi", None, original_msg=msg2) == \ "That notification configuration is already registered." assert chatcommands.willbenotified("11540", "raspberrypi.stackexchange.com", original_msg=msg2) == \ "Yes, you will be notified for that site in that room." # Check for no interaction assert chatcommands.allnotificationsites("11540", original_msg=msg1) == \ "You will get notified for these sites:\r\ncodegolf.stackexchange.com, gaming.stackexchange.com" assert chatcommands.allnotificationsites("11540", original_msg=msg2) == \ "You will get notified for these sites:\r\nraspberrypi.stackexchange.com" # Remove all notifications and check assert chatcommands.unnotify("11540", "gaming.stackexchange.com", original_msg=msg1) == \ "I will no longer ping you if I report a post on `gaming.stackexchange.com`, in room `11540` on " \ "`chat.stackexchange.com`." assert chatcommands.unnotify("11540", "codegolf", original_msg=msg1) == \ "I will no longer ping you if I report a post on `codegolf`, in room `11540` on `chat.stackexchange.com`." assert chatcommands.unnotify("11540", "raspberrypi", original_msg=msg2) == \ "I will no longer ping you if I report a post on `raspberrypi`, in room `11540` on `chat.stackexchange.com`." assert chatcommands.unnotify("11540", "raspberrypi", original_msg=msg2) == \ "That configuration doesn't exist." assert chatcommands.allnotificationsites("11540", original_msg=msg1) == \ "You won't get notified for any sites in that room." assert chatcommands.willbenotified("11540", "raspberrypi", original_msg=msg2) == \ "No, you won't be notified for that site in that room." assert chatcommands.allnotificationsites( "asdf", original_msg=msg1) == "Invalid input type given for an argument" assert chatcommands.notify("11540", "charcoalspam.stackexchange.com", None, original_msg=msg1) == \ "The given SE site does not exist." assert chatcommands.notify("11540", "codegolf", "True", original_msg=msg1) == \ "You'll now get pings from me if I report a post on `codegolf`, in room `11540` on `chat.stackexchange.com`." assert chatcommands.notify("11540", "codegolf", "False", original_msg=msg1) == \ "That notification configuration is already registered." finally: # Cleanup remove_pickle("notifications.p")
def test_whitelisted_users(): chatcommunicate.parse_room_config("test/test_rooms.yml") try: msg = Fake({ "owner": { "name": "El'endia Starman", "id": 1, "is_moderator": False }, "room": { "id": 11540, "_client": { "host": "stackexchange.com" } }, "_client": { "host": "stackexchange.com" } }) # Format: !!/*wlu profileurl assert chatcommands.iswlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User is not whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.addwlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User whitelisted (`4622463` on `stackoverflow.com`)." # TODO: Add test here as well assert chatcommands.iswlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User is whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.rmwlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User removed from whitelist (`4622463` on `stackoverflow.com`)." assert chatcommands.iswlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User is not whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.rmwlu("https://stackoverflow.com/users/4622463/angussidney", original_msg=msg) == \ "User is not whitelisted." # Format: !!/*wlu userid sitename assert chatcommands.iswlu("4622463 stackoverflow", original_msg=msg) == \ "User is not whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.addwlu("4622463 stackoverflow", original_msg=msg) == \ "User whitelisted (`4622463` on `stackoverflow.com`)." # TODO: Add test here as well assert chatcommands.iswlu("4622463 stackoverflow", original_msg=msg) == \ "User is whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.rmwlu("4622463 stackoverflow", original_msg=msg) == \ "User removed from whitelist (`4622463` on `stackoverflow.com`)." assert chatcommands.iswlu("4622463 stackoverflow", original_msg=msg) == \ "User is not whitelisted (`4622463` on `stackoverflow.com`)." assert chatcommands.rmwlu("4622463 stackoverflow", original_msg=msg) == \ "User is not whitelisted." # Invalid input assert chatcommands.addwlu("https://meta.stackexchange.com/users", original_msg=msg) == \ "Invalid format. Valid format: `!!/addwlu profileurl` *or* `!!/addwlu userid sitename`." assert chatcommands.rmwlu("https://meta.stackexchange.com/", original_msg=msg) == \ "Invalid format. Valid format: `!!/rmwlu profileurl` *or* `!!/rmwlu userid sitename`." assert chatcommands.iswlu("msklkldsklaskd", original_msg=msg) == \ "Invalid format. Valid format: `!!/iswlu profileurl` *or* `!!/iswlu userid sitename`." # Invalid sitename assert chatcommands.addwlu("1 completelyfakesite", original_msg=msg) == \ "Error: Could not find the given site." assert chatcommands.iswlu("1 completelyfakesite", original_msg=msg) == \ "Error: Could not find the given site." except: # Cleanup remove_pickle("whitelistedUsers.p")
def init(username, password, try_cookies=True): global _clients global _rooms global _room_data global _last_messages for site in _clients.keys(): client = Client(site) logged_in = False if try_cookies: if GlobalVars.cookies is None: datahandling.remove_pickle("cookies.p") GlobalVars.cookies = {} else: cookies = GlobalVars.cookies try: if site in cookies and cookies[site] is not None: client.login_with_cookie(cookies[site]) logged_in = True log( 'debug', 'chat.{}: Logged in using cached cookies'.format( site)) except LoginError as e: exc_type, exc_obj, exc_tb = sys.exc_info() log( 'debug', 'chat.{}: Login error {}: {}'.format( site, exc_type.__name__, exc_obj)) log( 'debug', 'chat.{}: Falling back to credential-based login'. format(site)) del cookies[site] datahandling.dump_cookies() if not logged_in: for retry in range(3): try: GlobalVars.cookies[site] = client.login(username, password) break except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() log( 'debug', 'chat.{}: Login error {}: {}'.format( site, exc_type.__name__, exc_obj)) else: raise Exception("Failed to log into " + site + ", max retries exceeded") _clients[site] = client if os.path.exists("rooms_custom.yml"): parse_room_config("rooms_custom.yml") else: parse_room_config("rooms.yml") if not GlobalVars.standby_mode: join_command_rooms() if datahandling.has_pickle("messageData.p"): try: _last_messages = datahandling.load_pickle("messageData.p") except EOFError: pass threading.Thread(name="pickle ---rick--- runner", target=pickle_last_messages, daemon=True).start() threading.Thread(name="message sender", target=send_messages, daemon=True).start() if try_cookies: datahandling.dump_cookies()
def init(username, password, try_cookies=True): global _clients global _rooms global _room_data global _last_messages for site in _clients.keys(): client = Client(site) logged_in = False if try_cookies: if GlobalVars.cookies is None: datahandling.remove_pickle("cookies.p") GlobalVars.cookies = {} else: cookies = GlobalVars.cookies try: if site in cookies and cookies[site] is not None: try: # This implements a quick login to only chat using the existing cookies. It doesn't # require accessing main SE sites, so should be available when SE is in read-only mode. # Ideally, we'll update ChatExchange with something similar. client._br.session.cookies.update(cookies[site]) # client.get_me() will raise an exception if the cookies don't work. me = client.get_me() if me.id > 0: client.logged_in = True logged_in = True log( 'debug', 'chat.{}: Logged in to chat only using cached cookies' .format(site)) except Exception: # This is a fallback using the ChatExchange functionality we've been using for a long time. log( 'debug', 'chat.{}: chat-only login failed. Falling back to normal cookies' .format(site)) client.login_with_cookie(cookies[site]) logged_in = True log( 'debug', 'chat.{}: Logged in using cached cookies'. format(site)) except LoginError as e: exc_type, exc_obj, exc_tb = sys.exc_info() log( 'debug', 'chat.{}: Login error {}: {}'.format( site, exc_type.__name__, exc_obj)) log( 'debug', 'chat.{}: Falling back to credential-based login'. format(site)) # Instead of deleting the cookies, start with a clean slate of a new client. client = Client(site) if not logged_in: for retry in range(3): try: GlobalVars.cookies[site] = client.login(username, password) break except Exception as e: exc_type, exc_obj, exc_tb = sys.exc_info() log( 'debug', 'chat.{}: Login error {}: {}'.format( site, exc_type.__name__, exc_obj)) if exc_type.__name__ == 'LoginError' and str( exc_obj) == 'fkey input not found': # ChatExchange didn't find the `fkey` <input> in the SE login page. Under most operating # conditions, this means that we've either lost connectivity to SE entirely or SE # is in read-only mode and isn't accepting login attempts. Under those conditions, # there's nothing which we or SD can do other than wait for SE to resolve the issue. # So, instead of spinning the CPU hard in order to retry at the maximum rate, we delay a bit. # The situations where the problem is on our end rather than on SE's end tend sleep_time = 30 * (retry + 1) log( 'warning', 'Login to SE appears unavailable. Can be caused by: SD config issue,' + ' bad network connection, or Stack Exchange is down/read-only.' + ' Sleeping for {} seconds.'.format(sleep_time)) time.sleep(sleep_time) else: raise Exception("Failed to log into " + site + ", max retries exceeded") _clients[site] = client if os.path.exists("rooms_custom.yml"): parse_room_config("rooms_custom.yml") else: parse_room_config("rooms.yml") if not GlobalVars.standby_mode: join_command_rooms() if datahandling.has_pickle("messageData.p"): try: _last_messages = datahandling.load_pickle("messageData.p") except EOFError: pass threading.Thread(name="pickle ---rick--- runner", target=pickle_last_messages, daemon=True).start() threading.Thread(name="message sender", target=send_messages, daemon=True).start() if try_cookies: datahandling.dump_cookies()
def test_whitelisted_user(): user_url = 'https://stackoverflow.com/users/2/geoff-dalgas' user = get_user_from_url(user_url) add_whitelisted_user(user) user_url2 = 'https://stackoverflow.com/users/0/test' user2 = get_user_from_url(user_url2) add_whitelisted_user(user2) post = Post( api_response={ 'title': '', 'body': '', 'owner': { 'display_name': 'bagprada', 'reputation': 1, 'link': user_url }, 'site': 'stackoverflow.com', 'question_id': '1', 'IsAnswer': False, 'score': 0 }) is_spam, reason, _ = check_if_spam(post) assert is_spam is False post = Post( api_response={ 'title': 'baba ji', 'body': '', 'owner': { 'display_name': '', 'reputation': 1, 'link': user_url }, 'site': 'stackoverflow.com', 'question_id': '2', 'IsAnswer': False, 'score': 0 }) is_spam, reason, _ = check_if_spam(post) assert is_spam is True post = Post( api_response={ 'title': 'baba ji', 'body': '', 'owner': { 'display_name': 'bagprada', 'reputation': 1, 'link': user_url }, 'site': 'stackoverflow.com', 'question_id': '3', 'IsAnswer': False, 'score': 0 }) is_spam, reason, _ = check_if_spam(post) assert is_spam is True post = Post( api_response={ 'title': 'test', 'body': '', 'owner': { 'display_name': 'baba ji - muscle building', 'reputation': 1, 'link': user_url2 }, 'site': 'stackoverflow.com', 'question_id': '0', 'IsAnswer': False, 'score': 0 }) is_spam, reason, _ = check_if_spam(post) assert is_spam is False # cleanup remove_pickle("whitelistedUsers.p")