From f4703e692cbdfa5793b2d3dd88f646b34a51788d Mon Sep 17 00:00:00 2001 From: Frisk Date: Tue, 28 Dec 2021 15:08:56 +0100 Subject: [PATCH] added initial testing framework using mockserver to imitate client-server connection --- test/mockserver/configs/settings1.json | 557 ++++++++++++++++++ test/mockserver/data/response_error.json | 14 + test/mockserver/data/response_image.json | 32 + test/mockserver/data/response_init.json | 461 +++++++++++++++ .../data/response_recentchanges.json | 209 +++++++ .../data/response_recentchanges2.json | 78 +++ test/mockserver/data/response_siteinfo.json | 98 +++ test/mockserver/data/response_userinfo.json | 22 + test/mockserver/results/results1.json | 0 test/mockserver/server.py | 113 ++++ test/mockserver/start.py | 55 ++ 11 files changed, 1639 insertions(+) create mode 100644 test/mockserver/configs/settings1.json create mode 100644 test/mockserver/data/response_error.json create mode 100644 test/mockserver/data/response_image.json create mode 100644 test/mockserver/data/response_init.json create mode 100644 test/mockserver/data/response_recentchanges.json create mode 100644 test/mockserver/data/response_recentchanges2.json create mode 100644 test/mockserver/data/response_siteinfo.json create mode 100644 test/mockserver/data/response_userinfo.json create mode 100644 test/mockserver/results/results1.json create mode 100644 test/mockserver/server.py create mode 100644 test/mockserver/start.py diff --git a/test/mockserver/configs/settings1.json b/test/mockserver/configs/settings1.json new file mode 100644 index 0000000..fafa778 --- /dev/null +++ b/test/mockserver/configs/settings1.json @@ -0,0 +1,557 @@ +{ + "cooldown": 30, + "wiki_url": "http://localhost:8080/", + "rc_enabled": true, + "lang": "en", + "header": { + "user-agent": "RcGcDw/{version}" + }, + "limit": 15, + "webhookURL": "http://localhost:8080/webhook/", + "limitrefetch": 15, + "wikiname": "Testing Connection", + "avatars": { + "connection_failed": "https://i.imgur.com/2jWQEt1.png", + "connection_restored": "", + "no_event": "", + "embed": "", + "compact": "" + }, + "ignored": ["external", "newusers/create", "newusers/autocreate", "newusers/create2", "newusers/byemail", "newusers/newusers"], + "show_updown_messages": true, + "ignored_namespaces": [], + "extensions_dir": "extensions", + "error_tolerance": 0, + "overview": false, + "overview_time": "00:00", + "send_empty_overview": false, + "license_detection": true, + "license_regex_detect": "\\{\\{(license|lizenz|licence|copyright)", + "license_regex": "\\{\\{(license|lizenz|licence|copyright)(\\ |\\|)(?P.*?)\\}\\}", + "disallow_regexes": [], + "wiki_bot_login": "", + "wiki_bot_password": "", + "show_added_categories": true, + "show_bots": false, + "show_abuselog": false, + "hide_ips": false, + "discord_message_cooldown": 0, + "auto_suppression": { + "enabled": true, + "db_location": ":memory:" + }, + "logging": { + "version": 1, + "disable_existing_loggers": false, + "formatters": { + "standard": { + "format": "%(name)s - %(asctime)s - %(levelname)s: %(message)s" + } + }, + "handlers": { + "default": { + "formatter": "standard", + "class": "logging.StreamHandler", + "stream": "ext://sys.stdout" + }, + "filelogger": { + "formatter": "standard", + "class": "logging.FileHandler", + "filename": "rcgcdw.log", + "encoding": "utf-8" + } + }, + "loggers": { + "": { + "level": 0, + "handlers": ["default", "filelogger"] + } + } + }, + "appearance":{ + "mode": "embed", + "embed": { + "show_edit_changes": true, + "show_footer": true, + "embed_images": true, + "show_no_description_provided": true + } + }, + "fandom_discussions": { + "enabled": false, + "wiki_url": "", + "cooldown": 60, + "webhookURL": "", + "limit": 5, + "appearance": { + "mode": "embed", + "embed": { + "show_content": true + } + }, + "show_forums": [] + }, + "event_appearance": { + "daily_overview": { + "icon": "", + "color": 16312092, + "emoji": "", + "plot": true + }, + "new": { + "icon": "https://i.imgur.com/6HIbEq8.png", + "color": "THIS COLOR DEPENDS ON EDIT SIZE, PLEASE DON'T CHANGE", + "emoji": "🆕" + }, + "edit": { + "icon": "https://i.imgur.com/zKYHkJm.png", + "color": "THIS COLOR DEPENDS ON EDIT SIZE, PLEASE DON'T CHANGE", + "emoji": "📝" + }, + "upload/overwrite": { + "icon": "https://i.imgur.com/egJpa81.png", + "color": 12390624, + "emoji": "🖼️" + }, + "upload/upload": { + "icon": "https://i.imgur.com/egJpa81.png", + "color": 12390624, + "emoji": "🖼️" + }, + "upload/revert": { + "icon": "https://i.imgur.com/egJpa81.png", + "color": 12390624, + "emoji": "⏮️" + }, + "delete/delete": { + "icon": "https://i.imgur.com/BU77GD3.png", + "color": 1, + "emoji": "🗑️" + }, + "delete/delete_redir": { + "icon": "https://i.imgur.com/BU77GD3.png", + "color": 1, + "emoji": "🗑️" + }, + "delete/restore": { + "icon": "https://i.imgur.com/9MnROIU.png", + "color": 1, + "emoji": "♻️" + }, + "delete/revision": { + "icon": "https://i.imgur.com/1gps6EZ.png", + "color": 1, + "emoji": "👁️" + }, + "delete/event": { + "icon": "https://i.imgur.com/1gps6EZ.png", + "color": 1, + "emoji": "👁️" + }, + "merge/merge": { + "icon": "https://i.imgur.com/uQMK9XK.png", + "color": 25600, + "emoji": "🖇️" + }, + "move/move": { + "icon": "https://i.imgur.com/eXz9dog.png", + "color": 25600, + "emoji": "📨" + }, + "move/move_redir": { + "icon": "https://i.imgur.com/UtC3YX2.png", + "color": 25600, + "emoji": "📨" + }, + "block/block": { + "icon": "https://i.imgur.com/g7KgZHf.png", + "color": 1, + "emoji": "🚫" + }, + "block/unblock": { + "icon": "https://i.imgur.com/bvtBJ8o.png", + "color": 1, + "emoji": "✅" + }, + "block/reblock": { + "icon": "https://i.imgur.com/g7KgZHf.png", + "color": 1, + "emoji": "🚫" + }, + "protect/protect": { + "icon": "https://i.imgur.com/bzPt89Z.png", + "color": 16312092, + "emoji": "🔒" + }, + "protect/modify": { + "icon": "https://i.imgur.com/bzPt89Z.png", + "color": 16312092, + "emoji": "🔐" + }, + "protect/move_prot": { + "icon": "https://i.imgur.com/bzPt89Z.png", + "color": 16312092, + "emoji": "🔏" + }, + "protect/unprotect": { + "icon": "https://i.imgur.com/2wN3Qcq.png", + "color": 16312092, + "emoji": "🔓" + }, + "import/upload": { + "icon": "", + "color": 65280, + "emoji": "📥" + }, + "import/interwiki": { + "icon": "https://i.imgur.com/sFkhghb.png", + "color": 65280, + "emoji": "📥" + }, + "rights/rights": { + "icon": "", + "color": 16711680, + "emoji": "🏅" + }, + "rights/autopromote": { + "icon": "", + "color": 16711680, + "emoji": "🏅" + }, + "abusefilter/modify": { + "icon": "https://i.imgur.com/Sn2NzRJ.png", + "color": 16711680, + "emoji": "🔍" + }, + "abusefilter/create": { + "icon": "https://i.imgur.com/Sn2NzRJ.png", + "color": 16711680, + "emoji": "🔍" + }, + "interwiki/iw_add": { + "icon": "https://i.imgur.com/sFkhghb.png", + "color": 16711680, + "emoji": "🔗" + }, + "interwiki/iw_edit": { + "icon": "https://i.imgur.com/sFkhghb.png", + "color": 16711680, + "emoji": "🔗" + }, + "interwiki/iw_delete": { + "icon": "https://i.imgur.com/sFkhghb.png", + "color": 16711680, + "emoji": "🔗" + }, + "curseprofile/comment-created": { + "icon": "https://i.imgur.com/Lvy5E32.png", + "color": 16089376, + "emoji": "✉️" + }, + "curseprofile/comment-edited": { + "icon": "https://i.imgur.com/Lvy5E32.png", + "color": 16089376, + "emoji": "📧" + }, + "curseprofile/comment-deleted": { + "icon": "", + "color": 16089376, + "emoji": "🗑️" + }, + "curseprofile/comment-purged":{ + "icon":"", + "color": 16089376, + "emoji": "👁️" + }, + "curseprofile/comment-replied": { + "icon": "https://i.imgur.com/hkyYsI1.png", + "color": 16089376, + "emoji": "📩" + }, + "curseprofile/profile-edited": { + "icon": "", + "color": 16089376, + "emoji": "📌" + }, + "contentmodel/change": { + "icon": "", + "color": 25600, + "emoji": "📋" + }, + "contentmodel/new": { + "icon": "", + "color": 25600, + "emoji": "📋" + }, + "cargo/deletetable": { + "icon": "", + "color": 16776960, + "emoji": "📦" + }, + "cargo/createtable": { + "icon": "", + "color": 16776960, + "emoji": "📦" + }, + "cargo/replacetable": { + "icon": "", + "color": 16776960, + "emoji": "📦" + }, + "cargo/recreatetable": { + "icon": "", + "color": 16776960, + "emoji": "📦" + }, + "sprite/sprite": { + "icon": "", + "color": 16776960, + "emoji": "🪟" + }, + "sprite/sheet": { + "icon": "", + "color": 16776960, + "emoji": "🪟" + }, + "sprite/slice": { + "icon": "", + "color": 16776960, + "emoji": "🪟" + }, + "managetags/create": { + "icon": "", + "color": 16776960, + "emoji": "🏷️" + }, + "managetags/delete": { + "icon": "", + "color": 16776960, + "emoji": "🏷️" + }, + "managetags/activate": { + "icon": "", + "color": 16776960, + "emoji": "🏷️" + }, + "managetags/deactivate": { + "icon": "", + "color": 16776960, + "emoji": "🏷️" + }, + "newusers/autocreate": { + "icon": "", + "color": 65280, + "emoji": "🗿" + }, + "newusers/byemail": { + "icon": "", + "color": 65280, + "emoji": "🗿" + }, + "newusers/create": { + "icon": "", + "color": 65280, + "emoji": "🗿" + }, + "newusers/create2": { + "icon": "", + "color": 65280, + "emoji": "🗿" + }, + "newusers/newusers": { + "icon": "", + "color": 65280, + "emoji": "🗿" + }, + "managewiki/delete": { + "icon": "", + "color": 8421504, + "emoji": "🗑️" + }, + "managewiki/lock": { + "icon": "", + "color": 8421504, + "emoji": "🔒" + }, + "managewiki/namespaces": { + "icon": "", + "color": 8421504, + "emoji": "📦" + }, + "managewiki/namespaces-delete": { + "icon": "", + "color": 8421504, + "emoji": "🗑️" + }, + "managewiki/rights": { + "icon": "", + "color": 8421504, + "emoji": "🏅" + }, + "managewiki/settings": { + "icon": "", + "color": 8421504, + "emoji": "⚙️" + }, + "managewiki/undelete": { + "icon": "", + "color": 8421504, + "emoji": "♻️" + }, + "managewiki/unlock": { + "icon": "", + "color": 8421504, + "emoji": "🔓" + }, + "datadump/generate": { + "icon": "", + "color": 8421504, + "emoji": "📤" + }, + "datadump/delete": { + "icon": "", + "color": 8421504, + "emoji": "🗑️" + }, + "pagetranslation/mark": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/unmark": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/moveok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/movenok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/deletefok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/deletefnok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/deletelok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/deletelnok": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/encourage": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/discourage": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/prioritylanguages": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/associate": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagetranslation/dissociate": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "translationreview/message": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "translationreview/group": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "pagelang/pagelang": { + "icon": "", + "color": 8421504, + "emoji": "🌐" + }, + "renameuser/renameuser": { + "icon": "", + "color": 8421504, + "emoji": "📛" + }, + "suppressed": { + "icon": "https://i.imgur.com/1gps6EZ.png", + "color": 1, + "emoji": "👁️" + }, + "discussion": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 54998, + "emoji": "📝" + }, + "discussion/forum/post": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 54998, + "emoji": "📝" + }, + "discussion/forum/reply": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 54998, + "emoji": "📝" + }, + "discussion/forum/poll": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 54998, + "emoji": "📝" + }, + "discussion/forum/quiz": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 54998, + "emoji": "📝" + }, + "discussion/wall/post": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 3752525, + "emoji": "✉️" + }, + "discussion/wall/reply": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 3752525, + "emoji": "📩" + }, + "discussion/comment/post": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 10802, + "emoji": "🗒️" + }, + "discussion/comment/reply": { + "icon": "https://static.wikia.nocookie.net/663e53f7-1e79-4906-95a7-2c1df4ebbada", + "color": 10802, + "emoji": "🗒️" + }, + "unknown": { + "icon": "", + "color": 0, + "emoji": "❓" + } + } +} diff --git a/test/mockserver/data/response_error.json b/test/mockserver/data/response_error.json new file mode 100644 index 0000000..0ca2533 --- /dev/null +++ b/test/mockserver/data/response_error.json @@ -0,0 +1,14 @@ +{ + "errors": [ + { + "code": "unknown_action", + "key": "apierror-unrecognizedvalue", + "params": [ + "action", + "ddd" + ], + "module": "main" + } + ], + "*": "See https://localhost/api.php for API usage. Subscribe to the mediawiki-api-announce mailing list at <https://lists.wikimedia.org/mailman/listinfo/mediawiki-api-announce> for notice of API deprecations and breaking changes." +} \ No newline at end of file diff --git a/test/mockserver/data/response_image.json b/test/mockserver/data/response_image.json new file mode 100644 index 0000000..ed909e5 --- /dev/null +++ b/test/mockserver/data/response_image.json @@ -0,0 +1,32 @@ +{ + "batchcomplete": "", + "query": { + "pages": { + "181124": { + "pageid": 181124, + "ns": 6, + "title": "File:Oak Sign (9).png", + "imagerepository": "local", + "imageinfo": [ + { + "timestamp": "2021-12-26T12:09:04Z", + "url": "http://localhost:8080/test_wiki/images/7/75/Oak_Sign_%289%29.png/revision/latest?cb=20211226120904", + "descriptionurl": "http://localhost:8080/wiki/File:Oak_Sign_(9).png", + "descriptionshorturl": "http://localhost:8080/index.php?curid=181124" + } + ], + "revisions": [ + { + "slots": { + "main": { + "contentmodel": "wikitext", + "contentformat": "text/x-wiki", + "*": "\n== License ==\n{{License Mojang}}" + } + } + } + ] + } + } + } +} \ No newline at end of file diff --git a/test/mockserver/data/response_init.json b/test/mockserver/data/response_init.json new file mode 100644 index 0000000..b588016 --- /dev/null +++ b/test/mockserver/data/response_init.json @@ -0,0 +1,461 @@ +{ + "batchcomplete": "", + "limits": { + "tags": 5000 + }, + "query": { + "tags": [ + { + "name": "abusefilter-condition-limit", + "displayname": "condition limit reached" + }, + { + "name": "added youtube video", + "displayname": "contains YouTube embed" + }, + { + "name": "advanced mobile edit", + "displayname": "Advanced mobile edit" + }, + { + "name": "character-spam", + "displayname": "Character spam" + }, + { + "name": "deletiontemplate-addition", + "displayname": "Requested deletion" + }, + { + "name": "maps-visual-edit", + "displayname": "Visual map edit" + }, + { + "name": "missing signature", + "displayname": "missing signature" + }, + { + "name": "mobile edit", + "displayname": "Mobile edit" + }, + { + "name": "mobile web edit" + }, + { + "name": "mobile-edit", + "displayname": "Mobile edit" + }, + { + "name": "move", + "displayname": "move" + }, + { + "name": "mw-blank", + "displayname": "Blanking" + }, + { + "name": "mw-changed-redirect-target", + "displayname": "Redirect target changed" + }, + { + "name": "mw-contentmodelchange", + "displayname": "content model change" + }, + { + "name": "mw-new-redirect", + "displayname": "New redirect" + }, + { + "name": "mw-removed-redirect", + "displayname": "Removed redirect" + }, + { + "name": "mw-replace", + "displayname": "Replaced" + }, + { + "name": "mw-rollback", + "displayname": "Rollback" + }, + { + "name": "mw-undo", + "displayname": "Undo" + }, + { + "name": "possible-number-spam", + "displayname": "possible-number-spam" + }, + { + "name": "section blanking", + "displayname": "section blanked" + }, + { + "name": "spriteeditor", + "displayname": "Sprite edit" + }, + { + "name": "test", + "displayname": "test" + }, + { + "name": "tor", + "displayname": "Made through Tor" + }, + { + "name": "visualeditor", + "displayname": "Visual edit" + }, + { + "name": "visualeditor-needcheck", + "displayname": "Visual edit: Check" + }, + { + "name": "visualeditor-switched", + "displayname": "Partial visual edit" + }, + { + "name": 0, + "displayname": "0" + }, + { + "name": "visualeditor-wikitext", + "displayname": "2017 source edit" + }, + { + "name": 1, + "displayname": "1" + }, + { + "name": 2, + "displayname": "2" + }, + { + "name": 3, + "displayname": "3" + } + ], + "allmessages": [ + { + "name": "recentchanges-page-added-to-category", + "normalizedname": "recentchanges-page-added-to-category", + "*": "[[:$1]] added to category" + }, + { + "name": "recentchanges-page-removed-from-category", + "normalizedname": "recentchanges-page-removed-from-category", + "*": "[[:$1]] removed from category" + }, + { + "name": "recentchanges-page-added-to-category-bundled", + "normalizedname": "recentchanges-page-added-to-category-bundled", + "*": "[[:$1]] added to category, [[Special:WhatLinksHere/$1|this page is included within other pages]]" + }, + { + "name": "recentchanges-page-removed-from-category-bundled", + "normalizedname": "recentchanges-page-removed-from-category-bundled", + "*": "[[:$1]] removed from category, [[Special:WhatLinksHere/$1|this page is included within other pages]]" + } + ], + "namespaces": { + "0": { + "id": 0, + "case": "first-letter", + "subpages": "", + "content": "", + "*": "" + }, + "1": { + "id": 1, + "case": "first-letter", + "subpages": "", + "canonical": "Talk", + "*": "Talk" + }, + "2": { + "id": 2, + "case": "first-letter", + "subpages": "", + "canonical": "User", + "*": "User" + }, + "3": { + "id": 3, + "case": "first-letter", + "subpages": "", + "canonical": "User talk", + "*": "User talk" + }, + "4": { + "id": 4, + "case": "first-letter", + "subpages": "", + "canonical": "Project", + "*": "Minecraft Wiki" + }, + "5": { + "id": 5, + "case": "first-letter", + "subpages": "", + "canonical": "Project talk", + "*": "Minecraft Wiki talk" + }, + "6": { + "id": 6, + "case": "first-letter", + "subpages": "", + "canonical": "File", + "*": "File" + }, + "7": { + "id": 7, + "case": "first-letter", + "subpages": "", + "canonical": "File talk", + "*": "File talk" + }, + "8": { + "id": 8, + "case": "first-letter", + "subpages": "", + "canonical": "MediaWiki", + "*": "MediaWiki" + }, + "9": { + "id": 9, + "case": "first-letter", + "subpages": "", + "canonical": "MediaWiki talk", + "*": "MediaWiki talk" + }, + "10": { + "id": 10, + "case": "first-letter", + "subpages": "", + "canonical": "Template", + "*": "Template" + }, + "11": { + "id": 11, + "case": "first-letter", + "subpages": "", + "canonical": "Template talk", + "*": "Template talk" + }, + "12": { + "id": 12, + "case": "first-letter", + "subpages": "", + "canonical": "Help", + "*": "Help" + }, + "13": { + "id": 13, + "case": "first-letter", + "subpages": "", + "canonical": "Help talk", + "*": "Help talk" + }, + "14": { + "id": 14, + "case": "first-letter", + "subpages": "", + "canonical": "Category", + "*": "Category" + }, + "15": { + "id": 15, + "case": "first-letter", + "subpages": "", + "canonical": "Category talk", + "*": "Category talk" + }, + "110": { + "id": 110, + "case": "first-letter", + "canonical": "Forum", + "*": "Forum" + }, + "111": { + "id": 111, + "case": "first-letter", + "canonical": "Forum talk", + "*": "Forum talk" + }, + "202": { + "id": 202, + "case": "first-letter", + "canonical": "UserProfile", + "*": "UserProfile" + }, + "274": { + "id": 274, + "case": "first-letter", + "canonical": "Widget", + "*": "Widget" + }, + "275": { + "id": 275, + "case": "first-letter", + "subpages": "", + "canonical": "Widget talk", + "*": "Widget talk" + }, + "420": { + "id": 420, + "case": "first-letter", + "canonical": "GeoJson", + "content": "", + "defaultcontentmodel": "GeoJson", + "*": "GeoJson" + }, + "421": { + "id": 421, + "case": "first-letter", + "subpages": "", + "canonical": "GeoJson talk", + "defaultcontentmodel": "wikitext", + "*": "GeoJson talk" + }, + "500": { + "id": 500, + "case": "first-letter", + "subpages": "", + "canonical": "User blog", + "*": "User blog" + }, + "501": { + "id": 501, + "case": "first-letter", + "subpages": "", + "canonical": "User blog comment", + "*": "User blog comment" + }, + "502": { + "id": 502, + "case": "first-letter", + "subpages": "", + "canonical": "Blog", + "*": "Blog" + }, + "503": { + "id": 503, + "case": "first-letter", + "subpages": "", + "canonical": "Blog talk", + "*": "Blog talk" + }, + "828": { + "id": 828, + "case": "first-letter", + "subpages": "", + "canonical": "Module", + "*": "Module" + }, + "829": { + "id": 829, + "case": "first-letter", + "subpages": "", + "canonical": "Module talk", + "*": "Module talk" + }, + "1200": { + "id": 1200, + "case": "first-letter", + "canonical": "Message Wall", + "*": "Message Wall" + }, + "1201": { + "id": 1201, + "case": "first-letter", + "subpages": "", + "canonical": "Thread", + "*": "Thread" + }, + "1202": { + "id": 1202, + "case": "first-letter", + "canonical": "Message Wall Greeting", + "*": "Message Wall Greeting" + }, + "2300": { + "id": 2300, + "case": "first-letter", + "canonical": "Gadget", + "*": "Gadget" + }, + "2301": { + "id": 2301, + "case": "first-letter", + "canonical": "Gadget talk", + "*": "Gadget talk" + }, + "2302": { + "id": 2302, + "case": "case-sensitive", + "canonical": "Gadget definition", + "defaultcontentmodel": "GadgetDefinition", + "*": "Gadget definition" + }, + "2303": { + "id": 2303, + "case": "case-sensitive", + "canonical": "Gadget definition talk", + "*": "Gadget definition talk" + }, + "10000": { + "id": 10000, + "case": "first-letter", + "subpages": "", + "canonical": "Minecraft Dungeons", + "content": "", + "*": "Minecraft Dungeons" + }, + "10001": { + "id": 10001, + "case": "first-letter", + "canonical": "Minecraft Dungeons talk", + "*": "Minecraft Dungeons talk" + }, + "10002": { + "id": 10002, + "case": "first-letter", + "subpages": "", + "canonical": "Minecraft Earth", + "content": "", + "*": "Minecraft Earth" + }, + "10003": { + "id": 10003, + "case": "first-letter", + "canonical": "Minecraft Earth talk", + "*": "Minecraft Earth talk" + }, + "10004": { + "id": 10004, + "case": "first-letter", + "subpages": "", + "canonical": "Minecraft Story Mode", + "content": "", + "*": "Minecraft Story Mode" + }, + "10005": { + "id": 10005, + "case": "first-letter", + "subpages": "", + "canonical": "Minecraft Story Mode talk", + "*": "Minecraft Story Mode talk" + }, + "-2": { + "id": -2, + "case": "first-letter", + "canonical": "Media", + "*": "Media" + }, + "-1": { + "id": -1, + "case": "first-letter", + "canonical": "Special", + "*": "Special" + } + } + } +} \ No newline at end of file diff --git a/test/mockserver/data/response_recentchanges.json b/test/mockserver/data/response_recentchanges.json new file mode 100644 index 0000000..201eca5 --- /dev/null +++ b/test/mockserver/data/response_recentchanges.json @@ -0,0 +1,209 @@ +{ + "batchcomplete": "", + "continue": { + "rccontinue": "20211226120903|2793420", + "continue": "-||" + }, + "query": { + "recentchanges": [ + { + "type": "edit", + "ns": 0, + "title": "Some different page", + "pageid": 9327, + "revid": 2075232, + "old_revid": 232555, + "rcid": 2793437, + "user": "User3", + "oldlen": 32882, + "newlen": 328, + "timestamp": "2021-12-26T12:26:32Z", + "parsedcomment": "Some changes lol", + "tags": [] + }, + { + "type": "edit", + "ns": 0, + "title": "Java Edition 1.19", + "pageid": 177589, + "revid": 2075231, + "old_revid": 2075230, + "rcid": 2793436, + "user": "User2", + "minor": "", + "oldlen": 811, + "newlen": 771, + "timestamp": "2021-12-26T12:24:23Z", + "parsedcomment": "Revert edits by 192.168.1.1 (talk)", + "tags": [ + "mw-rollback" + ] + }, + { + "type": "log", + "ns": 2, + "title": "User:FineUser2", + "pageid": 72216, + "revid": 0, + "old_revid": 0, + "rcid": 2793427, + "user": "Administrator2", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T12:40:00Z", + "parsedcomment": "", + "logid": 1141234, + "logtype": "rights", + "logaction": "rights", + "logparams": { + "oldgroups": [ + "autopatrol", + "rollback" + ], + "newgroups": [ + "sysop" + ], + "oldmetadata": [ + { + "group": "autopatrol", + "expiry": "infinity" + }, + { + "group": "rollback", + "expiry": "infinity" + } + ], + "newmetadata": [ + { + "group": "sysop", + "expiry": "infinity" + } + ] + }, + "tags": [] + }, + { + "type": "log", + "ns": 202, + "title": "UserProfile:User2", + "pageid": 0, + "revid": 0, + "old_revid": 0, + "rcid": 2793426, + "user": "User2", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T12:20:11Z", + "parsedcomment": "CoolUser#1812", + "logid": 1141233, + "logtype": "curseprofile", + "logaction": "profile-edited", + "logparams": { + "4:section": "profile-link-discord" + }, + "tags": [] + }, + { + "type": "log", + "ns": 2, + "title": "User:Spammer", + "pageid": 0, + "revid": 0, + "old_revid": 0, + "rcid": 2793425, + "user": "Administrator", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T12:15:04Z", + "parsedcomment": "Rule #2: Spam", + "logid": 1141231, + "logtype": "block", + "logaction": "block", + "logparams": { + "duration": "2 weeks", + "flags": [ + "nocreate" + ], + "sitewide": "", + "expiry": "2022-01-11T10:38:23Z" + }, + "tags": [] + }, + { + "type": "edit", + "ns": 0, + "title": "Java Edition 1.19", + "pageid": 177589, + "revid": 2075225, + "old_revid": 2075224, + "rcid": 2793424, + "user": "Good User", + "anon": "", + "oldlen": 811, + "newlen": 771, + "timestamp": "2021-12-26T12:13:38Z", + "parsedcomment": "Unfo revision by 192.168.1.1. Reason: Mad cats", + "tags": [ + "visualeditor" + ] + }, + { + "type": "edit", + "ns": 0, + "title": "Java Edition 1.19", + "pageid": 177589, + "revid": 2075224, + "old_revid": 2074874, + "rcid": 2793423, + "user": "192.168.1.1", + "anon": "", + "oldlen": 771, + "newlen": 811, + "timestamp": "2021-12-26T12:09:18Z", + "parsedcomment": "Hahahahhaha, you will never understand my genius!", + "tags": [ + "mobile edit", + "mobile web edit", + "visualeditor" + ] + }, + { + "type": "categorize", + "ns": 14, + "title": "Category:Mojang images", + "pageid": 181124, + "revid": 2075223, + "old_revid": 0, + "rcid": 2793422, + "user": "User1", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T12:09:04Z", + "parsedcomment": "File:Oak Sign (9).png added to category", + "tags": [] + }, + { + "type": "log", + "ns": 6, + "title": "File:Oak Sign (9).png", + "pageid": 181124, + "revid": 2075223, + "old_revid": 0, + "rcid": 2793421, + "user": "User1", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T12:09:04Z", + "parsedcomment": "", + "logid": 1141230, + "logtype": "upload", + "logaction": "upload", + "logparams": { + "img_sha1": "l9vzs83denqnn2ph8wya6ieue6b7tvo", + "img_timestamp": "2021-12-26T12:09:04Z" + }, + "tags": [] + } + ] + } +} diff --git a/test/mockserver/data/response_recentchanges2.json b/test/mockserver/data/response_recentchanges2.json new file mode 100644 index 0000000..7f15021 --- /dev/null +++ b/test/mockserver/data/response_recentchanges2.json @@ -0,0 +1,78 @@ +{ + "batchcomplete": "", + "continue": { + "rccontinue": "20211226120903|2793420", + "continue": "-||" + }, + "query": { + "recentchanges": [ + { + "type": "edit", + "ns": 0, + "title": "Unique page", + "pageid": 9327, + "revid": 2075234, + "old_revid": 232556, + "rcid": 2793440, + "user": "User3", + "oldlen": 328, + "newlen": 32882, + "timestamp": "2021-12-26T13:37:10Z", + "parsedcomment": "Added content", + "tags": [] + }, + { + "type": "log", + "ns": 0, + "title": "Some different page", + "pageid": 9327, + "revid": 0, + "old_revid": 0, + "rcid": 2793439, + "user": "Frisk", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T13:35:50Z", + "parsedcomment": "aaaaaaaaaaaaaaa", + "logid": 1141236, + "logtype": "delete", + "logaction": "delete", + "logparams": {}, + "tags": [] + }, + { + "type": "log", + "ns": 0, + "title": "Java Edition 1.19", + "pageid": 177589, + "revid": 0, + "old_revid": 0, + "rcid": 2793438, + "user": "Frisk", + "oldlen": 0, + "newlen": 0, + "timestamp": "2021-12-26T13:02:59Z", + "parsedcomment": "Heresy!", + "logid": 1141235, + "logtype": "delete", + "logaction": "revision", + "logparams": { + "type": "revision", + "ids": [ + "2075224" + ], + "old": { + "bitmask": 0 + }, + "new": { + "bitmask": 7, + "content": "", + "comment": "", + "user": "" + } + }, + "tags": [] + } + ] + } +} diff --git a/test/mockserver/data/response_siteinfo.json b/test/mockserver/data/response_siteinfo.json new file mode 100644 index 0000000..0099468 --- /dev/null +++ b/test/mockserver/data/response_siteinfo.json @@ -0,0 +1,98 @@ +{ + "batchcomplete": "", + "query": { + "general": { + "mainpage": "Random Wiki", + "base": "https://localhost:8080/wiki/Mainpage", + "sitename": "Minecraft Wiki", + "logo": "https://localhost:8080/localhost/images/b/bc/Wiki.png", + "generator": "MediaWiki 1.35.3", + "phpversion": "7.3.32", + "phpsapi": "fpm-fcgi", + "dbtype": "mysql", + "dbversion": "5.7.25-28-log", + "externalimages": [], + "langconversion": "", + "titleconversion": "", + "linkprefixcharset": "", + "linkprefix": "", + "linktrail": "/^([a-z]+)(.*)$/sD", + "legaltitlechars": " %!\"$&'()*,\\-.\\/0-9:;=?@A-Z\\\\^_`a-z~\\x80-\\xFF+", + "invalidusernamechars": "@:", + "fixarabicunicode": "", + "fixmalayalamunicode": "", + "case": "first-letter", + "lang": "en", + "fallback": [], + "fallback8bitEncoding": "windows-1252", + "writeapi": "", + "maxarticlesize": 2097152, + "timezone": "UTC", + "timeoffset": 0, + "articlepath": "/wiki/$1", + "scriptpath": "", + "script": "/index.php", + "variantarticlepath": false, + "server": "https://localhost:8080", + "servername": "localhost:8080", + "wikiid": "localhost", + "time": "2021-12-26T21:57:13Z", + "misermode": "", + "uploadsenabled": "", + "maxuploadsize": 10485760, + "minuploadchunksize": 1024, + "galleryoptions": { + "imagesPerRow": 0, + "imageWidth": 120, + "imageHeight": 120, + "captionLength": "", + "showBytes": "", + "showDimensions": "", + "mode": "traditional" + }, + "thumblimits": [ + 120, + 150, + 180, + 200, + 250, + 300 + ], + "imagelimits": [ + { + "width": 320, + "height": 240 + }, + { + "width": 640, + "height": 480 + }, + { + "width": 800, + "height": 600 + }, + { + "width": 1024, + "height": 768 + }, + { + "width": 1280, + "height": 1024 + } + ], + "favicon": "https://localhost:8080/favicon.ico", + "centralidlookupprovider": "local", + "allcentralidlookupproviders": [ + "local" + ], + "interwikimagic": "", + "magiclinks": { + "ISBN": "" + }, + "categorycollation": "uppercase", + "citeresponsivereferences": "", + "gamepedia": "true", + "mobileserver": "https://localhost:8080" + } + } +} \ No newline at end of file diff --git a/test/mockserver/data/response_userinfo.json b/test/mockserver/data/response_userinfo.json new file mode 100644 index 0000000..c240c44 --- /dev/null +++ b/test/mockserver/data/response_userinfo.json @@ -0,0 +1,22 @@ +{ + "batchcomplete": "", + "limits": { + "usercontribs": 5000 + }, + "query": { + "usercontribs": [ + { + "userid": 0, + "user": "192.168.1.1" + }, + { + "userid": 0, + "user": "192.168.1.1" + }, + { + "userid": 0, + "user": "192.168.1.1" + } + ] + } +} \ No newline at end of file diff --git a/test/mockserver/results/results1.json b/test/mockserver/results/results1.json new file mode 100644 index 0000000..e69de29 diff --git a/test/mockserver/server.py b/test/mockserver/server.py new file mode 100644 index 0000000..22db113 --- /dev/null +++ b/test/mockserver/server.py @@ -0,0 +1,113 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . +import pprint +from http.server import BaseHTTPRequestHandler, HTTPServer +import json +import urllib.parse +import requests + +response_jsons: dict[str, dict] = {} + + +def load_response(name: str): + with open("data/{}.json".format(name), "r") as response_file: + response_json: dict = json.loads(response_file.read()) + response_jsons[name] = response_json + + +def get_response(name: str): + return response_jsons.get(name) + + +[load_response(x) for x in ["response_recentchanges", "response_recentchanges2", "response_init", "response_error", "response_siteinfo" + "response_image", "response_userinfo"]] + + +messages_collector = [] + + +# Return server response based on some output from Minecraft Wiki +class MockServerRequestHandler(BaseHTTPRequestHandler): + def do_GET(self): + # We assume testing will be for API endpoint only since RcGcDw doesn't do requests to other URLs so no need to check main path + # For simplicity, return a dictionary of query arguments, we assume duplicate keys will not appear + query = {k: y for (k, y) in urllib.parse.parse_qsl(self.path.split("?")[1])} + if query.get("action") == "query": + # Regular pooled query for recentchanges + if query.get("list") == "recentchanges": + self.send_essentials_ok() + if len(messages_collector) == 0: + # Limit amount of events accordingly to required amount just in case + response_jsons["response_recentchanges"]["query"]["recentchanges"] = get_response("response_recentchanges")["query"]["recentchanges"][0:int(query.get("rclimit", 20))] + response_content = json.dumps(get_response("response_recentchanges")) + else: + response_jsons["response_recentchanges2"]["query"]["recentchanges"] = get_response("response_recentchanges2")["query"]["recentchanges"][0:int(query.get("rclimit", 20))] + response_content = json.dumps(get_response("response_recentchanges2")) + self.wfile.write(response_content.encode('utf-8')) + # Init info + elif query.get("list") == "tags" and query.get("meta") == "allmessages|siteinfo": + self.send_essentials_ok() + response_content = json.dumps(get_response("response_init")) + self.wfile.write(response_content.encode('utf-8')) + elif query.get("meta") == "siteinfo": + self.send_essentials_ok() + response_content = json.dumps(get_response("response_siteinfo")) + self.wfile.write(response_content.encode('utf-8')) + elif query.get("prop") == "imageinfo|revisions": + self.send_essentials_ok() + response_content = json.dumps(get_response("response_image")) + self.wfile.write(response_content.encode('utf-8')) + elif query.get("list") == "usercontribs": + self.send_essentials_ok() + response_content = json.dumps(get_response("response_userinfo")) + self.wfile.write(response_content.encode('utf-8')) + else: + self.send_response(400) + self.send_header('Content-Type', 'application/json; charset=utf-8') + self.end_headers() + response_content = json.dumps(get_response("response_error")) + self.wfile.write(response_content.encode('utf-8')) + + def do_POST(self): + self.read_ok_collect() + + def do_PATCH(self): + self.read_ok_collect() + + def do_DELETE(self): + self.read_ok_collect() + + def read_ok_collect(self): + content_length = int(self.headers['Content-Length']) + patch_data = self.rfile.read(content_length) + messages_collector.append(patch_data.decode('utf-8')) + self.send_essentials_ok() + self.wfile.write(json.dumps({"id": len(messages_collector)}).encode('utf-8')) + + def send_essentials_ok(self): + self.send_response(requests.codes.ok) + self.send_header('Content-Type', 'application/json; charset=utf-8') + self.end_headers() + + +def start_mock_server(port): + mock_server = HTTPServer(('localhost', port), MockServerRequestHandler) + try: + print("Server started successfully at http://localhost:{}".format(port)) + mock_server.serve_forever() + except KeyboardInterrupt: + print("Shutting down...") + print(pprint.pprint(messages_collector)) + pass diff --git a/test/mockserver/start.py b/test/mockserver/start.py new file mode 100644 index 0000000..a8627f9 --- /dev/null +++ b/test/mockserver/start.py @@ -0,0 +1,55 @@ +# This file is part of Recent changes Goat compatible Discord webhook (RcGcDw). +# +# RcGcDw is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# RcGcDw is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with RcGcDw. If not, see . + +import argparse +import json + +import server +import pathlib +import shutil +import sys +import time + +parser = argparse.ArgumentParser(description="Test RcGcDw with mocked data") +parser.add_argument("--config", type=int, default=1, help="Number of config to use while testing the mocked server (default=1). Number corresponds to files in configs/settings#.json") +parser.add_argument("--ignore-config", action='store_false', help="Ignore lack of existing config.json") +parser.add_argument("--no-client", action='store_true', help="Skip starting the client") +command_args = parser.parse_args() + +# Backup old settings.json and copy from configs/settingsX.json to proper relative location +if not command_args.no_client: + new_settings = pathlib.Path(__file__).parent.absolute().joinpath("configs/settings{}.json".format(command_args.config)) + old_config = pathlib.Path(__file__).parent.resolve().parent.resolve().parent.resolve().joinpath("settings.json") # Should be root of RcGcDw + if not old_config.exists() and command_args.ignore_config: + print("Cannot find currently used settings.json! Exiting to prevent potential damage.") + sys.exit(2) + backup_filename = pathlib.Path(__file__).parent.resolve().parent.resolve().parent.resolve().joinpath("settings.json.{}.bak".format(int(time.time()))) + if backup_filename.exists(): + print("Backup file under same name exists! Exiting.") + sys.exit(3) + shutil.move(old_config, backup_filename) + shutil.copy(new_settings, old_config) + # revert data file to some low number + with open(pathlib.Path(__file__).parent.resolve().parent.resolve().parent.resolve().joinpath("data.json"), "r+") as data_file: + data_file_data = json.loads(data_file.read()) + data_file_data["rcid"] = 5 + data_file.write(json.dumps(data_file_data, indent=4)) + +# Start mock server +server.start_mock_server(8080) + +# Revert file changes +if not command_args.no_client: + shutil.copy(backup_filename, old_config) \ No newline at end of file