tests.rake 20 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507
  1. # frozen_string_literal: true
  2. namespace :tests do
  3. namespace :migrations do
  4. desc 'Prepares all migrations and test data for consistency checks'
  5. task prepare_database: :environment do
  6. {
  7. '2' => 2017_10_10_025614,
  8. '2_4' => 2018_05_14_140000,
  9. '2_4_3' => 2018_07_07_154237,
  10. '3_3_0' => 2020_12_18_054746,
  11. }.each do |release, version|
  12. ActiveRecord::Tasks::DatabaseTasks
  13. .migration_connection_pool
  14. .migration_context
  15. .migrate(version)
  16. Rake::Task["tests:migrations:populate_v#{release}"]
  17. .invoke
  18. end
  19. end
  20. desc 'Check that database state is consistent with a successful migration from populated data'
  21. task check_database: :environment do
  22. unless Account.find_by(username: 'admin', domain: nil)&.hide_collections? == false
  23. puts 'Unexpected value for Account#hide_collections? for user @admin'
  24. exit(1)
  25. end
  26. unless Account.find_by(username: 'user', domain: nil)&.hide_collections? == true
  27. puts 'Unexpected value for Account#hide_collections? for user @user'
  28. exit(1)
  29. end
  30. unless Account.find_by(username: 'evil', domain: 'activitypub.com')&.suspended?
  31. puts 'Unexpected value for Account#suspended? for user @evil@activitypub.com'
  32. exit(1)
  33. end
  34. unless Status.find(6).account_id == Status.find(7).account_id
  35. puts 'Users @remote@remote.com and @Remote@remote.com not properly merged'
  36. exit(1)
  37. end
  38. if Account.exists?(domain: Rails.configuration.x.local_domain)
  39. puts 'Faux remote accounts not properly cleaned up'
  40. exit(1)
  41. end
  42. unless AccountConversation.first&.last_status_id == 11
  43. puts 'AccountConversation records not created as expected'
  44. exit(1)
  45. end
  46. if Account.find(Account::INSTANCE_ACTOR_ID).private_key.blank?
  47. puts 'Instance actor does not have a private key'
  48. exit(1)
  49. end
  50. unless Account.find_by(username: 'user', domain: nil).custom_filters.map { |filter| filter.keywords.pluck(:keyword) } == [['test'], ['take']]
  51. puts 'CustomFilterKeyword records not created as expected'
  52. exit(1)
  53. end
  54. unless Admin::ActionLog.find_by(target_type: 'DomainBlock', target_id: 1).human_identifier == 'example.org'
  55. puts 'Admin::ActionLog domain block records not updated as expected'
  56. exit(1)
  57. end
  58. unless Admin::ActionLog.find_by(target_type: 'EmailDomainBlock', target_id: 1).human_identifier == 'example.org'
  59. puts 'Admin::ActionLog email domain block records not updated as expected'
  60. exit(1)
  61. end
  62. unless User.find(1).settings['notification_emails.favourite'] == true && User.find(1).settings['notification_emails.mention'] == false
  63. puts 'User settings not kept as expected'
  64. exit(1)
  65. end
  66. unless User.find(1).settings['web.trends'] == false
  67. puts 'User settings not kept as expected'
  68. exit(1)
  69. end
  70. unless Account.find_remote('bob', 'ActivityPub.com').domain == 'activitypub.com'
  71. puts 'Account domains not properly normalized'
  72. exit(1)
  73. end
  74. unless PreviewCard.where(id: PreviewCardsStatus.where(status_id: 12).select(:preview_card_id)).pluck(:url) == ['https://joinmastodon.org/']
  75. puts 'Preview cards not deduplicated as expected'
  76. exit(1)
  77. end
  78. unless Account.find_local('kmruser').user.chosen_languages == %w(en ku ckb)
  79. puts 'Chosen languages not migrated as expected for kmr users'
  80. exit(1)
  81. end
  82. unless Account.find_local('kmruser').user.settings['default_language'] == 'ku'
  83. puts 'Default posting language not migrated as expected for kmr users'
  84. exit(1)
  85. end
  86. unless Account.find_local('qcuser').user.locale == 'fr-CA'
  87. puts 'Locale for fr-QC users not updated to fr-CA as expected'
  88. exit(1)
  89. end
  90. policy = NotificationPolicy.find_by(account: User.find(1).account)
  91. unless policy.for_private_mentions == 'accept' && policy.for_not_following == 'filter'
  92. puts "Notification policy not migrated as expected: #{policy.for_private_mentions.inspect}, #{policy.for_not_following.inspect}"
  93. exit(1)
  94. end
  95. unless Identity.where(provider: 'foo', uid: 0).count == 1
  96. puts 'Identities not deduplicated as expected'
  97. exit(1)
  98. end
  99. unless WebauthnCredential.where(user_id: 1, nickname: 'foo').count == 1
  100. puts 'Webauthn credentials not deduplicated as expected'
  101. exit(1)
  102. end
  103. unless AccountAlias.where(account_id: 1, uri: 'https://example.com/users/foobar').count == 1
  104. puts 'Account aliases not deduplicated as expected'
  105. exit(1)
  106. end
  107. # This is checking the attribute rather than the method, to avoid the legacy fallback
  108. # and ensure the data has been migrated
  109. unless Account.find_local('qcuser').user[:otp_secret] == 'anotpsecretthatshouldbeencrypted'
  110. puts 'OTP secret for user not preserved as expected'
  111. exit(1)
  112. end
  113. unless Doorkeeper::Application.find(2)[:scopes] == 'write:accounts profile'
  114. puts 'Application OAuth scopes not rewritten as expected'
  115. exit(1)
  116. end
  117. unless Doorkeeper::Application.find(2).access_tokens.first[:scopes] == 'write:accounts profile'
  118. puts 'OAuth access token scopes not rewritten as expected'
  119. exit(1)
  120. end
  121. puts 'No errors found. Database state is consistent with a successful migration process.'
  122. end
  123. desc 'Populate the database with test data for 3.3.0'
  124. task populate_v3_3_0: :environment do # rubocop:disable Naming/VariableNumber
  125. ActiveRecord::Base.connection.execute(<<~SQL.squish)
  126. INSERT INTO "webauthn_credentials"
  127. (user_id, nickname, external_id, public_key, created_at, updated_at)
  128. VALUES
  129. (1, 'foo', 1, 'foo', now(), now()),
  130. (1, 'foo', 2, 'bar', now(), now());
  131. INSERT INTO "account_aliases"
  132. (account_id, uri, acct, created_at, updated_at)
  133. VALUES
  134. (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now()),
  135. (1, 'https://example.com/users/foobar', 'foobar@example.com', now(), now());
  136. /* Doorkeeper records
  137. While the `read:me` scope was technically not valid in 3.3.0,
  138. it is still useful for the purposes of testing the `ChangeReadMeScopeToProfile`
  139. migration.
  140. */
  141. INSERT INTO "oauth_applications"
  142. (id, name, uid, secret, redirect_uri, scopes, created_at, updated_at)
  143. VALUES
  144. (2, 'foo', 'foo', 'foo', 'https://example.com/#foo', 'write:accounts read:me', now(), now()),
  145. (3, 'bar', 'bar', 'bar', 'https://example.com/#bar', 'read:me', now(), now());
  146. INSERT INTO "oauth_access_tokens"
  147. (token, application_id, scopes, resource_owner_id, created_at)
  148. VALUES
  149. ('secret', 2, 'write:accounts read:me', 4, now());
  150. SQL
  151. end
  152. desc 'Populate the database with test data for 2.4.3'
  153. task populate_v2_4_3: :environment do # rubocop:disable Naming/VariableNumber
  154. user_key = OpenSSL::PKey::RSA.new(2048)
  155. user_private_key = ActiveRecord::Base.connection.quote(user_key.to_pem)
  156. user_public_key = ActiveRecord::Base.connection.quote(user_key.public_key.to_pem)
  157. ActiveRecord::Base.connection.execute(<<~SQL)
  158. INSERT INTO "custom_filters"
  159. (id, account_id, phrase, context, whole_word, irreversible, created_at, updated_at)
  160. VALUES
  161. (1, 2, 'test', '{ "home", "public" }', true, true, now(), now()),
  162. (2, 2, 'take', '{ "home" }', false, false, now(), now());
  163. -- Orphaned admin action logs
  164. INSERT INTO "admin_action_logs"
  165. (account_id, action, target_type, target_id, created_at, updated_at)
  166. VALUES
  167. (1, 'destroy', 'Account', 1312, now(), now()),
  168. (1, 'destroy', 'User', 1312, now(), now()),
  169. (1, 'destroy', 'Report', 1312, now(), now()),
  170. (1, 'destroy', 'DomainBlock', 1312, now(), now()),
  171. (1, 'destroy', 'EmailDomainBlock', 1312, now(), now()),
  172. (1, 'destroy', 'Status', 1312, now(), now()),
  173. (1, 'destroy', 'CustomEmoji', 1312, now(), now());
  174. -- Admin action logs with linked objects
  175. INSERT INTO "domain_blocks"
  176. (id, domain, created_at, updated_at)
  177. VALUES
  178. (1, 'example.org', now(), now());
  179. INSERT INTO "email_domain_blocks"
  180. (id, domain, created_at, updated_at)
  181. VALUES
  182. (1, 'example.org', now(), now());
  183. INSERT INTO "admin_action_logs"
  184. (account_id, action, target_type, target_id, created_at, updated_at)
  185. VALUES
  186. (1, 'destroy', 'Account', 1, now(), now()),
  187. (1, 'destroy', 'User', 1, now(), now()),
  188. (1, 'destroy', 'DomainBlock', 1, now(), now()),
  189. (1, 'destroy', 'EmailDomainBlock', 1, now(), now()),
  190. (1, 'destroy', 'Status', 1, now(), now()),
  191. (1, 'destroy', 'CustomEmoji', 3, now(), now());
  192. INSERT INTO "settings"
  193. (id, thing_type, thing_id, var, value, created_at, updated_at)
  194. VALUES
  195. (3, 'User', 1, 'notification_emails', E'--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nfollow: false\nreblog: true\nfavourite: true\nmention: false\nfollow_request: true\ndigest: true\nreport: true\npending_account: false\ntrending_tag: true\nappeal: true\n', now(), now()),
  196. (4, 'User', 1, 'trends', E'--- false\n', now(), now());
  197. INSERT INTO "accounts"
  198. (id, username, domain, private_key, public_key, created_at, updated_at)
  199. VALUES
  200. (10, 'kmruser', NULL, #{user_private_key}, #{user_public_key}, now(), now()),
  201. (11, 'qcuser', NULL, #{user_private_key}, #{user_public_key}, now(), now());
  202. INSERT INTO "users"
  203. (id, account_id, email, created_at, updated_at, admin, locale, chosen_languages)
  204. VALUES
  205. (4, 10, 'kmruser@localhost', now(), now(), false, 'ku', '{en,kmr,ku,ckb}');
  206. INSERT INTO "users"
  207. (id, account_id, email, created_at, updated_at, locale,
  208. encrypted_otp_secret, encrypted_otp_secret_iv, encrypted_otp_secret_salt,
  209. otp_required_for_login)
  210. VALUES
  211. (5, 11, 'qcuser@localhost', now(), now(), 'fr-QC',
  212. E'Fttsy7QAa0edaDfdfSz094rRLAxc8cJweDQ4BsWH/zozcdVA8o9GLqcKhn2b\nGi/V\n',
  213. 'rys3THICkr60BoWC',
  214. '_LMkAGvdg7a+sDIKjI3mR2Q==',
  215. true);
  216. INSERT INTO "settings"
  217. (id, thing_type, thing_id, var, value, created_at, updated_at)
  218. VALUES
  219. (5, 'User', 4, 'default_language', E'--- kmr\n', now(), now()),
  220. (6, 'User', 1, 'interactions', E'--- !ruby/hash:ActiveSupport::HashWithIndifferentAccess\nmust_be_follower: false\nmust_be_following: true\nmust_be_following_dm: false\n', now(), now());
  221. INSERT INTO "identities"
  222. (provider, uid, user_id, created_at, updated_at)
  223. VALUES
  224. ('foo', 0, 1, now(), now()),
  225. ('foo', 0, 1, now(), now());
  226. SQL
  227. end
  228. desc 'Populate the database with test data for 2.4.0'
  229. task populate_v2_4: :environment do # rubocop:disable Naming/VariableNumber
  230. ActiveRecord::Base.connection.execute(<<~SQL.squish)
  231. INSERT INTO "settings"
  232. (id, thing_type, thing_id, var, value, created_at, updated_at)
  233. VALUES
  234. (1, 'User', 1, 'hide_network', E'--- false\n', now(), now()),
  235. (2, 'User', 2, 'hide_network', E'--- true\n', now(), now());
  236. SQL
  237. end
  238. desc 'Populate the database with test data for 2.0.0'
  239. task populate_v2: :environment do
  240. admin_key = OpenSSL::PKey::RSA.new(2048)
  241. user_key = OpenSSL::PKey::RSA.new(2048)
  242. remote_key = OpenSSL::PKey::RSA.new(2048)
  243. remote_key2 = OpenSSL::PKey::RSA.new(2048)
  244. remote_key3 = OpenSSL::PKey::RSA.new(2048)
  245. admin_private_key = ActiveRecord::Base.connection.quote(admin_key.to_pem)
  246. admin_public_key = ActiveRecord::Base.connection.quote(admin_key.public_key.to_pem)
  247. user_private_key = ActiveRecord::Base.connection.quote(user_key.to_pem)
  248. user_public_key = ActiveRecord::Base.connection.quote(user_key.public_key.to_pem)
  249. remote_public_key = ActiveRecord::Base.connection.quote(remote_key.public_key.to_pem)
  250. remote_public_key2 = ActiveRecord::Base.connection.quote(remote_key2.public_key.to_pem)
  251. remote_public_key_ap = ActiveRecord::Base.connection.quote(remote_key3.public_key.to_pem)
  252. local_domain = ActiveRecord::Base.connection.quote(Rails.configuration.x.local_domain)
  253. ActiveRecord::Base.connection.execute(<<~SQL)
  254. -- accounts
  255. INSERT INTO "accounts"
  256. (id, username, domain, private_key, public_key, created_at, updated_at)
  257. VALUES
  258. (1, 'admin', NULL, #{admin_private_key}, #{admin_public_key}, now(), now()),
  259. (2, 'user', NULL, #{user_private_key}, #{user_public_key}, now(), now());
  260. INSERT INTO "accounts"
  261. (id, username, domain, private_key, public_key, created_at, updated_at, remote_url, salmon_url)
  262. VALUES
  263. (3, 'remote', 'remote.com', NULL, #{remote_public_key}, now(), now(),
  264. 'https://remote.com/@remote', 'https://remote.com/salmon/1'),
  265. (4, 'Remote', 'remote.com', NULL, #{remote_public_key}, now(), now(),
  266. 'https://remote.com/@Remote', 'https://remote.com/salmon/1'),
  267. (5, 'REMOTE', 'Remote.com', NULL, #{remote_public_key2}, now() - interval '1 year', now() - interval '1 year',
  268. 'https://remote.com/stale/@REMOTE', 'https://remote.com/stale/salmon/1');
  269. INSERT INTO "accounts"
  270. (id, username, domain, private_key, public_key, created_at, updated_at, protocol, inbox_url, outbox_url, followers_url)
  271. VALUES
  272. (6, 'bob', 'ActivityPub.com', NULL, #{remote_public_key_ap}, now(), now(),
  273. 1, 'https://activitypub.com/users/bob/inbox', 'https://activitypub.com/users/bob/outbox', 'https://activitypub.com/users/bob/followers');
  274. INSERT INTO "accounts"
  275. (id, username, domain, private_key, public_key, created_at, updated_at)
  276. VALUES
  277. (7, 'user', #{local_domain}, #{user_private_key}, #{user_public_key}, now(), now()),
  278. (8, 'pt_user', NULL, #{user_private_key}, #{user_public_key}, now(), now());
  279. INSERT INTO "accounts"
  280. (id, username, domain, private_key, public_key, created_at, updated_at, protocol, inbox_url, outbox_url, followers_url, suspended)
  281. VALUES
  282. (9, 'evil', 'activitypub.com', NULL, #{remote_public_key_ap}, now(), now(),
  283. 1, 'https://activitypub.com/users/evil/inbox', 'https://activitypub.com/users/evil/outbox',
  284. 'https://activitypub.com/users/evil/followers', true);
  285. -- users
  286. INSERT INTO "users"
  287. (id, account_id, email, created_at, updated_at, admin)
  288. VALUES
  289. (1, 1, 'admin@localhost', now(), now(), true),
  290. (2, 2, 'user@localhost', now(), now(), false);
  291. INSERT INTO "users"
  292. (id, account_id, email, created_at, updated_at, admin, locale)
  293. VALUES
  294. (3, 8, 'ptuser@localhost', now(), now(), false, 'pt');
  295. -- conversations
  296. INSERT INTO "conversations" (id, created_at, updated_at) VALUES (1, now(), now());
  297. -- statuses
  298. INSERT INTO "statuses"
  299. (id, account_id, text, created_at, updated_at)
  300. VALUES
  301. (1, 1, 'test', now(), now()),
  302. (2, 1, '@remote@remote.com hello', now(), now()),
  303. (3, 1, '@Remote@remote.com hello', now(), now()),
  304. (4, 1, '@REMOTE@remote.com hello', now(), now());
  305. INSERT INTO "statuses"
  306. (id, account_id, text, created_at, updated_at, uri, local)
  307. VALUES
  308. (5, 1, 'activitypub status', now(), now(), 'https://localhost/users/admin/statuses/4', true);
  309. INSERT INTO "statuses"
  310. (id, account_id, text, created_at, updated_at)
  311. VALUES
  312. (6, 3, 'test', now(), now());
  313. INSERT INTO "statuses"
  314. (id, account_id, text, created_at, updated_at, in_reply_to_id, in_reply_to_account_id)
  315. VALUES
  316. (7, 4, '@admin hello', now(), now(), 3, 1);
  317. INSERT INTO "statuses"
  318. (id, account_id, text, created_at, updated_at)
  319. VALUES
  320. (8, 5, 'test', now(), now());
  321. INSERT INTO "statuses"
  322. (id, account_id, reblog_of_id, created_at, updated_at)
  323. VALUES
  324. (9, 1, 2, now(), now());
  325. INSERT INTO "statuses"
  326. (id, account_id, text, in_reply_to_id, conversation_id, visibility, created_at, updated_at)
  327. VALUES
  328. (10, 2, '@admin hey!', NULL, 1, 3, now(), now()),
  329. (11, 1, '@user hey!', 10, 1, 3, now(), now());
  330. INSERT INTO "statuses"
  331. (id, account_id, text, created_at, updated_at)
  332. VALUES
  333. (12, 1, 'check out https://joinmastodon.org/', now(), now());
  334. -- mentions (from previous statuses)
  335. INSERT INTO "mentions"
  336. (id, status_id, account_id, created_at, updated_at)
  337. VALUES
  338. (1, 2, 3, now(), now()),
  339. (2, 3, 4, now(), now()),
  340. (3, 4, 5, now(), now()),
  341. (4, 10, 1, now(), now()),
  342. (5, 11, 2, now(), now());
  343. -- stream entries
  344. INSERT INTO "stream_entries"
  345. (activity_id, account_id, activity_type, created_at, updated_at)
  346. VALUES
  347. (1, 1, 'status', now(), now()),
  348. (2, 1, 'status', now(), now()),
  349. (3, 1, 'status', now(), now()),
  350. (4, 1, 'status', now(), now()),
  351. (5, 1, 'status', now(), now()),
  352. (6, 3, 'status', now(), now()),
  353. (7, 4, 'status', now(), now()),
  354. (8, 5, 'status', now(), now()),
  355. (9, 1, 'status', now(), now());
  356. -- custom emoji
  357. INSERT INTO "custom_emojis"
  358. (id, shortcode, created_at, updated_at)
  359. VALUES
  360. (1, 'test', now(), now()),
  361. (2, 'Test', now(), now()),
  362. (3, 'blobcat', now(), now());
  363. INSERT INTO "custom_emojis"
  364. (id, shortcode, domain, uri, created_at, updated_at)
  365. VALUES
  366. (4, 'blobcat', 'remote.org', 'https://remote.org/emoji/blobcat', now(), now()),
  367. (5, 'blobcat', 'Remote.org', 'https://remote.org/emoji/blobcat', now(), now()),
  368. (6, 'Blobcat', 'remote.org', 'https://remote.org/emoji/Blobcat', now(), now());
  369. -- favourites
  370. INSERT INTO "favourites"
  371. (account_id, status_id, created_at, updated_at)
  372. VALUES
  373. (1, 1, now(), now()),
  374. (1, 7, now(), now()),
  375. (4, 1, now(), now()),
  376. (3, 1, now(), now()),
  377. (5, 1, now(), now());
  378. -- pinned statuses
  379. INSERT INTO "status_pins"
  380. (account_id, status_id, created_at, updated_at)
  381. VALUES
  382. (1, 1, now(), now()),
  383. (3, 6, now(), now()),
  384. (4, 7, now(), now());
  385. -- follows
  386. INSERT INTO "follows"
  387. (id, account_id, target_account_id, created_at, updated_at)
  388. VALUES
  389. (1, 1, 5, now(), now()),
  390. (2, 6, 2, now(), now()),
  391. (3, 5, 2, now(), now()),
  392. (4, 6, 1, now(), now());
  393. -- follow requests
  394. INSERT INTO "follow_requests"
  395. (account_id, target_account_id, created_at, updated_at)
  396. VALUES
  397. (2, 5, now(), now()),
  398. (5, 1, now(), now());
  399. -- notifications
  400. INSERT INTO "notifications"
  401. (id, from_account_id, account_id, activity_type, activity_id, created_at, updated_at)
  402. VALUES
  403. (1, 6, 2, 'Follow', 2, now(), now()),
  404. (2, 2, 1, 'Mention', 4, now(), now()),
  405. (3, 1, 2, 'Mention', 5, now(), now());
  406. -- preview cards
  407. INSERT INTO "preview_cards"
  408. (id, url, title, created_at, updated_at)
  409. VALUES
  410. (1, 'https://joinmastodon.org/', 'Mastodon - Decentralized social media', now(), now());
  411. -- many-to-many association between preview cards and statuses
  412. INSERT INTO "preview_cards_statuses"
  413. (status_id, preview_card_id)
  414. VALUES
  415. (12, 1),
  416. (12, 1);
  417. SQL
  418. end
  419. end
  420. end