You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

870 lines
28 KiB

8 years ago
8 years ago
  1. require 'rails_helper'
  2. RSpec.describe Account, type: :model do
  3. context do
  4. let(:bob) { Fabricate(:account, username: 'bob') }
  5. subject { Fabricate(:account) }
  6. describe '#follow!' do
  7. it 'creates a follow' do
  8. follow = subject.follow!(bob)
  9. expect(follow).to be_instance_of Follow
  10. expect(follow.account).to eq subject
  11. expect(follow.target_account).to eq bob
  12. end
  13. end
  14. describe '#unfollow!' do
  15. before do
  16. subject.follow!(bob)
  17. end
  18. it 'destroys a follow' do
  19. unfollow = subject.unfollow!(bob)
  20. expect(unfollow).to be_instance_of Follow
  21. expect(unfollow.account).to eq subject
  22. expect(unfollow.target_account).to eq bob
  23. expect(unfollow.destroyed?).to be true
  24. end
  25. end
  26. describe '#following?' do
  27. it 'returns true when the target is followed' do
  28. subject.follow!(bob)
  29. expect(subject.following?(bob)).to be true
  30. end
  31. it 'returns false if the target is not followed' do
  32. expect(subject.following?(bob)).to be false
  33. end
  34. end
  35. end
  36. describe '#local?' do
  37. it 'returns true when the account is local' do
  38. account = Fabricate(:account, domain: nil)
  39. expect(account.local?).to be true
  40. end
  41. it 'returns false when the account is on a different domain' do
  42. account = Fabricate(:account, domain: 'foreign.tld')
  43. expect(account.local?).to be false
  44. end
  45. end
  46. describe 'Local domain user methods' do
  47. around do |example|
  48. before = Rails.configuration.x.local_domain
  49. example.run
  50. Rails.configuration.x.local_domain = before
  51. end
  52. subject { Fabricate(:account, domain: nil, username: 'alice') }
  53. describe '#to_webfinger_s' do
  54. it 'returns a webfinger string for the account' do
  55. Rails.configuration.x.local_domain = 'example.com'
  56. expect(subject.to_webfinger_s).to eq 'acct:alice@example.com'
  57. end
  58. end
  59. describe '#local_username_and_domain' do
  60. it 'returns the username and local domain for the account' do
  61. Rails.configuration.x.local_domain = 'example.com'
  62. expect(subject.local_username_and_domain).to eq 'alice@example.com'
  63. end
  64. end
  65. end
  66. describe '#acct' do
  67. it 'returns username for local users' do
  68. account = Fabricate(:account, domain: nil, username: 'alice')
  69. expect(account.acct).to eql 'alice'
  70. end
  71. it 'returns username@domain for foreign users' do
  72. account = Fabricate(:account, domain: 'foreign.tld', username: 'alice')
  73. expect(account.acct).to eql 'alice@foreign.tld'
  74. end
  75. end
  76. describe '#save_with_optional_media!' do
  77. before do
  78. stub_request(:get, 'https://remote.test/valid_avatar').to_return(request_fixture('avatar.txt'))
  79. stub_request(:get, 'https://remote.test/invalid_avatar').to_return(request_fixture('feed.txt'))
  80. end
  81. let(:account) do
  82. Fabricate(:account,
  83. avatar_remote_url: 'https://remote.test/valid_avatar',
  84. header_remote_url: 'https://remote.test/valid_avatar')
  85. end
  86. let!(:expectation) { account.dup }
  87. context 'with valid properties' do
  88. before do
  89. account.save_with_optional_media!
  90. end
  91. it 'unchanges avatar, header, avatar_remote_url, and header_remote_url' do
  92. expect(account.avatar_remote_url).to eq expectation.avatar_remote_url
  93. expect(account.header_remote_url).to eq expectation.header_remote_url
  94. expect(account.avatar_file_name).to eq expectation.avatar_file_name
  95. expect(account.header_file_name).to eq expectation.header_file_name
  96. end
  97. end
  98. context 'with invalid properties' do
  99. before do
  100. account.avatar_remote_url = 'https://remote.test/invalid_avatar'
  101. account.save_with_optional_media!
  102. end
  103. it 'sets default avatar, header, avatar_remote_url, and header_remote_url' do
  104. expect(account.avatar_remote_url).to eq ''
  105. expect(account.header_remote_url).to eq ''
  106. expect(account.avatar_file_name).to eq nil
  107. expect(account.header_file_name).to eq nil
  108. end
  109. end
  110. end
  111. describe '#subscribed?' do
  112. it 'returns false when no subscription expiration information is present' do
  113. account = Fabricate(:account, subscription_expires_at: nil)
  114. expect(account.subscribed?).to be false
  115. end
  116. it 'returns true when subscription expiration has been set' do
  117. account = Fabricate(:account, subscription_expires_at: 30.days.from_now)
  118. expect(account.subscribed?).to be true
  119. end
  120. end
  121. describe '#possibly_stale?' do
  122. let(:account) { Fabricate(:account, last_webfingered_at: last_webfingered_at) }
  123. context 'last_webfingered_at is nil' do
  124. let(:last_webfingered_at) { nil }
  125. it 'returns true' do
  126. expect(account.possibly_stale?).to be true
  127. end
  128. end
  129. context 'last_webfingered_at is more than 24 hours before' do
  130. let(:last_webfingered_at) { 25.hours.ago }
  131. it 'returns true' do
  132. expect(account.possibly_stale?).to be true
  133. end
  134. end
  135. context 'last_webfingered_at is less than 24 hours before' do
  136. let(:last_webfingered_at) { 23.hours.ago }
  137. it 'returns false' do
  138. expect(account.possibly_stale?).to be false
  139. end
  140. end
  141. end
  142. describe '#refresh!' do
  143. let(:account) { Fabricate(:account, domain: domain) }
  144. let(:acct) { account.acct }
  145. context 'domain is nil' do
  146. let(:domain) { nil }
  147. it 'returns nil' do
  148. expect(account.refresh!).to be_nil
  149. end
  150. it 'calls not ResolveAccountService#call' do
  151. expect_any_instance_of(ResolveAccountService).not_to receive(:call).with(acct)
  152. account.refresh!
  153. end
  154. end
  155. context 'domain is present' do
  156. let(:domain) { 'example.com' }
  157. it 'calls ResolveAccountService#call' do
  158. expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once
  159. account.refresh!
  160. end
  161. end
  162. end
  163. describe '#to_param' do
  164. it 'returns username' do
  165. account = Fabricate(:account, username: 'alice')
  166. expect(account.to_param).to eq 'alice'
  167. end
  168. end
  169. describe '#keypair' do
  170. it 'returns an RSA key pair' do
  171. account = Fabricate(:account)
  172. expect(account.keypair).to be_instance_of OpenSSL::PKey::RSA
  173. end
  174. end
  175. describe '#subscription' do
  176. it 'returns an OStatus subscription' do
  177. account = Fabricate(:account)
  178. expect(account.subscription('')).to be_instance_of OStatus2::Subscription
  179. end
  180. end
  181. describe '#object_type' do
  182. it 'is always a person' do
  183. account = Fabricate(:account)
  184. expect(account.object_type).to be :person
  185. end
  186. end
  187. describe '#favourited?' do
  188. let(:original_status) do
  189. author = Fabricate(:account, username: 'original')
  190. Fabricate(:status, account: author)
  191. end
  192. subject { Fabricate(:account) }
  193. context 'when the status is a reblog of another status' do
  194. let(:original_reblog) do
  195. author = Fabricate(:account, username: 'original_reblogger')
  196. Fabricate(:status, reblog: original_status, account: author)
  197. end
  198. it 'is is true when this account has favourited it' do
  199. Fabricate(:favourite, status: original_reblog, account: subject)
  200. expect(subject.favourited?(original_status)).to eq true
  201. end
  202. it 'is false when this account has not favourited it' do
  203. expect(subject.favourited?(original_status)).to eq false
  204. end
  205. end
  206. context 'when the status is an original status' do
  207. it 'is is true when this account has favourited it' do
  208. Fabricate(:favourite, status: original_status, account: subject)
  209. expect(subject.favourited?(original_status)).to eq true
  210. end
  211. it 'is false when this account has not favourited it' do
  212. expect(subject.favourited?(original_status)).to eq false
  213. end
  214. end
  215. end
  216. describe '#reblogged?' do
  217. let(:original_status) do
  218. author = Fabricate(:account, username: 'original')
  219. Fabricate(:status, account: author)
  220. end
  221. subject { Fabricate(:account) }
  222. context 'when the status is a reblog of another status'do
  223. let(:original_reblog) do
  224. author = Fabricate(:account, username: 'original_reblogger')
  225. Fabricate(:status, reblog: original_status, account: author)
  226. end
  227. it 'is true when this account has reblogged it' do
  228. Fabricate(:status, reblog: original_reblog, account: subject)
  229. expect(subject.reblogged?(original_reblog)).to eq true
  230. end
  231. it 'is false when this account has not reblogged it' do
  232. expect(subject.reblogged?(original_reblog)).to eq false
  233. end
  234. end
  235. context 'when the status is an original status' do
  236. it 'is true when this account has reblogged it' do
  237. Fabricate(:status, reblog: original_status, account: subject)
  238. expect(subject.reblogged?(original_status)).to eq true
  239. end
  240. it 'is false when this account has not reblogged it' do
  241. expect(subject.reblogged?(original_status)).to eq false
  242. end
  243. end
  244. end
  245. describe '#excluded_from_timeline_account_ids' do
  246. it 'includes account ids of blockings, blocked_bys and mutes' do
  247. account = Fabricate(:account)
  248. block = Fabricate(:block, account: account)
  249. mute = Fabricate(:mute, account: account)
  250. block_by = Fabricate(:block, target_account: account)
  251. results = account.excluded_from_timeline_account_ids
  252. expect(results.size).to eq 3
  253. expect(results).to include(block.target_account.id)
  254. expect(results).to include(mute.target_account.id)
  255. expect(results).to include(block_by.account.id)
  256. end
  257. end
  258. describe '#excluded_from_timeline_domains' do
  259. it 'returns the domains blocked by the account' do
  260. account = Fabricate(:account)
  261. account.block_domain!('domain')
  262. expect(account.excluded_from_timeline_domains).to match_array ['domain']
  263. end
  264. end
  265. describe '.search_for' do
  266. before do
  267. _missing = Fabricate(
  268. :account,
  269. display_name: "Missing",
  270. username: "missing",
  271. domain: "missing.com"
  272. )
  273. end
  274. it 'accepts ?, \, : and space as delimiter' do
  275. match = Fabricate(
  276. :account,
  277. display_name: 'A & l & i & c & e',
  278. username: 'username',
  279. domain: 'example.com'
  280. )
  281. results = Account.search_for('A?l\i:c e')
  282. expect(results).to eq [match]
  283. end
  284. it 'finds accounts with matching display_name' do
  285. match = Fabricate(
  286. :account,
  287. display_name: "Display Name",
  288. username: "username",
  289. domain: "example.com"
  290. )
  291. results = Account.search_for("display")
  292. expect(results).to eq [match]
  293. end
  294. it 'finds accounts with matching username' do
  295. match = Fabricate(
  296. :account,
  297. display_name: "Display Name",
  298. username: "username",
  299. domain: "example.com"
  300. )
  301. results = Account.search_for("username")
  302. expect(results).to eq [match]
  303. end
  304. it 'finds accounts with matching domain' do
  305. match = Fabricate(
  306. :account,
  307. display_name: "Display Name",
  308. username: "username",
  309. domain: "example.com"
  310. )
  311. results = Account.search_for("example")
  312. expect(results).to eq [match]
  313. end
  314. it 'limits by 10 by default' do
  315. 11.times.each { Fabricate(:account, display_name: "Display Name") }
  316. results = Account.search_for("display")
  317. expect(results.size).to eq 10
  318. end
  319. it 'accepts arbitrary limits' do
  320. 2.times.each { Fabricate(:account, display_name: "Display Name") }
  321. results = Account.search_for("display", 1)
  322. expect(results.size).to eq 1
  323. end
  324. it 'ranks multiple matches higher' do
  325. matches = [
  326. { username: "username", display_name: "username" },
  327. { display_name: "Display Name", username: "username", domain: "example.com" },
  328. ].map(&method(:Fabricate).curry(2).call(:account))
  329. results = Account.search_for("username")
  330. expect(results).to eq matches
  331. end
  332. end
  333. describe '.advanced_search_for' do
  334. it 'accepts ?, \, : and space as delimiter' do
  335. account = Fabricate(:account)
  336. match = Fabricate(
  337. :account,
  338. display_name: 'A & l & i & c & e',
  339. username: 'username',
  340. domain: 'example.com'
  341. )
  342. results = Account.advanced_search_for('A?l\i:c e', account)
  343. expect(results).to eq [match]
  344. end
  345. it 'limits by 10 by default' do
  346. 11.times { Fabricate(:account, display_name: "Display Name") }
  347. results = Account.search_for("display")
  348. expect(results.size).to eq 10
  349. end
  350. it 'accepts arbitrary limits' do
  351. 2.times { Fabricate(:account, display_name: "Display Name") }
  352. results = Account.search_for("display", 1)
  353. expect(results.size).to eq 1
  354. end
  355. it 'ranks followed accounts higher' do
  356. account = Fabricate(:account)
  357. match = Fabricate(:account, username: "Matching")
  358. followed_match = Fabricate(:account, username: "Matcher")
  359. Fabricate(:follow, account: account, target_account: followed_match)
  360. results = Account.advanced_search_for("match", account)
  361. expect(results).to eq [followed_match, match]
  362. expect(results.first.rank).to be > results.last.rank
  363. end
  364. end
  365. describe '.domains' do
  366. it 'returns domains' do
  367. Fabricate(:account, domain: 'domain')
  368. expect(Account.domains).to match_array(['domain'])
  369. end
  370. end
  371. describe '.triadic_closures' do
  372. let!(:me) { Fabricate(:account) }
  373. let!(:friend) { Fabricate(:account) }
  374. let!(:friends_friend) { Fabricate(:account) }
  375. let!(:both_follow) { Fabricate(:account) }
  376. before do
  377. me.follow!(friend)
  378. friend.follow!(friends_friend)
  379. me.follow!(both_follow)
  380. friend.follow!(both_follow)
  381. end
  382. it 'finds accounts you dont follow which are followed by accounts you do follow' do
  383. expect(described_class.triadic_closures(me)).to eq [friends_friend]
  384. end
  385. it 'limits by 5 with offset 0 by defualt' do
  386. first_degree = 6.times.map { Fabricate(:account) }
  387. matches = 5.times.map { Fabricate(:account) }
  388. first_degree.each { |account| me.follow!(account) }
  389. matches.each do |match|
  390. first_degree.each { |account| account.follow!(match) }
  391. first_degree.shift
  392. end
  393. expect(described_class.triadic_closures(me)).to eq matches
  394. end
  395. it 'accepts arbitrary limits' do
  396. another_friend = Fabricate(:account)
  397. higher_friends_friend = Fabricate(:account)
  398. me.follow!(another_friend)
  399. friend.follow!(higher_friends_friend)
  400. another_friend.follow!(higher_friends_friend)
  401. expect(described_class.triadic_closures(me, limit: 1)).to eq [higher_friends_friend]
  402. end
  403. it 'acceps arbitrary offset' do
  404. another_friend = Fabricate(:account)
  405. higher_friends_friend = Fabricate(:account)
  406. me.follow!(another_friend)
  407. friend.follow!(higher_friends_friend)
  408. another_friend.follow!(higher_friends_friend)
  409. expect(described_class.triadic_closures(me, offset: 1)).to eq [friends_friend]
  410. end
  411. context 'when you block account' do
  412. before do
  413. me.block!(friends_friend)
  414. end
  415. it 'rejects blocked accounts' do
  416. expect(described_class.triadic_closures(me)).to be_empty
  417. end
  418. end
  419. context 'when you mute account' do
  420. before do
  421. me.mute!(friends_friend)
  422. end
  423. it 'rejects muted accounts' do
  424. expect(described_class.triadic_closures(me)).to be_empty
  425. end
  426. end
  427. end
  428. describe '#statuses_count' do
  429. subject { Fabricate(:account) }
  430. it 'counts statuses' do
  431. Fabricate(:status, account: subject)
  432. Fabricate(:status, account: subject)
  433. expect(subject.statuses_count).to eq 2
  434. end
  435. it 'does not count direct statuses' do
  436. Fabricate(:status, account: subject, visibility: :direct)
  437. expect(subject.statuses_count).to eq 0
  438. end
  439. it 'is decremented when status is removed' do
  440. status = Fabricate(:status, account: subject)
  441. expect(subject.statuses_count).to eq 1
  442. status.destroy
  443. expect(subject.statuses_count).to eq 0
  444. end
  445. it 'is decremented when status is removed when account is not preloaded' do
  446. status = Fabricate(:status, account: subject)
  447. expect(subject.reload.statuses_count).to eq 1
  448. clean_status = Status.find(status.id)
  449. expect(clean_status.association(:account).loaded?).to be false
  450. clean_status.destroy
  451. expect(subject.reload.statuses_count).to eq 0
  452. end
  453. end
  454. describe '.following_map' do
  455. it 'returns an hash' do
  456. expect(Account.following_map([], 1)).to be_a Hash
  457. end
  458. end
  459. describe '.followed_by_map' do
  460. it 'returns an hash' do
  461. expect(Account.followed_by_map([], 1)).to be_a Hash
  462. end
  463. end
  464. describe '.blocking_map' do
  465. it 'returns an hash' do
  466. expect(Account.blocking_map([], 1)).to be_a Hash
  467. end
  468. end
  469. describe '.requested_map' do
  470. it 'returns an hash' do
  471. expect(Account.requested_map([], 1)).to be_a Hash
  472. end
  473. end
  474. describe 'MENTION_RE' do
  475. subject { Account::MENTION_RE }
  476. it 'matches usernames in the middle of a sentence' do
  477. expect(subject.match('Hello to @alice from me')[1]).to eq 'alice'
  478. end
  479. it 'matches usernames in the beginning of status' do
  480. expect(subject.match('@alice Hey how are you?')[1]).to eq 'alice'
  481. end
  482. it 'matches full usernames' do
  483. expect(subject.match('@alice@example.com')[1]).to eq 'alice@example.com'
  484. end
  485. it 'matches full usernames with a dot at the end' do
  486. expect(subject.match('Hello @alice@example.com.')[1]).to eq 'alice@example.com'
  487. end
  488. it 'matches dot-prepended usernames' do
  489. expect(subject.match('.@alice I want everybody to see this')[1]).to eq 'alice'
  490. end
  491. it 'does not match e-mails' do
  492. expect(subject.match('Drop me an e-mail at alice@example.com')).to be_nil
  493. end
  494. it 'does not match URLs' do
  495. expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil
  496. end
  497. xit 'does not match URL querystring' do
  498. expect(subject.match('https://example.com/?x=@alice')).to be_nil
  499. end
  500. end
  501. describe 'validations' do
  502. it 'has a valid fabricator' do
  503. account = Fabricate.build(:account)
  504. account.valid?
  505. expect(account).to be_valid
  506. end
  507. it 'is invalid without a username' do
  508. account = Fabricate.build(:account, username: nil)
  509. account.valid?
  510. expect(account).to model_have_error_on_field(:username)
  511. end
  512. context 'when is local' do
  513. it 'is invalid if the username is not unique in case-insensitive comparsion among local accounts' do
  514. account_1 = Fabricate(:account, username: 'the_doctor')
  515. account_2 = Fabricate.build(:account, username: 'the_Doctor')
  516. account_2.valid?
  517. expect(account_2).to model_have_error_on_field(:username)
  518. end
  519. it 'is invalid if the username is reserved' do
  520. account = Fabricate.build(:account, username: 'support')
  521. account.valid?
  522. expect(account).to model_have_error_on_field(:username)
  523. end
  524. it 'is valid when username is reserved but record has already been created' do
  525. account = Fabricate.build(:account, username: 'support')
  526. account.save(validate: false)
  527. expect(account.valid?).to be true
  528. end
  529. it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do
  530. account = Fabricate.build(:account, username: 'the-doctor')
  531. account.valid?
  532. expect(account).to model_have_error_on_field(:username)
  533. end
  534. it 'is invalid if the username is longer then 30 characters' do
  535. account = Fabricate.build(:account, username: Faker::Lorem.characters(31))
  536. account.valid?
  537. expect(account).to model_have_error_on_field(:username)
  538. end
  539. it 'is invalid if the display name is longer than 30 characters' do
  540. account = Fabricate.build(:account, display_name: Faker::Lorem.characters(31))
  541. account.valid?
  542. expect(account).to model_have_error_on_field(:display_name)
  543. end
  544. it 'is invalid if the note is longer than 160 characters' do
  545. account = Fabricate.build(:account, note: Faker::Lorem.characters(161))
  546. account.valid?
  547. expect(account).to model_have_error_on_field(:note)
  548. end
  549. end
  550. context 'when is remote' do
  551. it 'is invalid if the username is not unique in case-sensitive comparison among accounts in the same normalized domain' do
  552. Fabricate(:account, domain: 'にゃん', username: 'username')
  553. account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'username')
  554. account.valid?
  555. expect(account).to model_have_error_on_field(:username)
  556. end
  557. it 'is valid even if the username is unique only in case-sensitive comparison among accounts in the same normalized domain' do
  558. Fabricate(:account, domain: 'にゃん', username: 'username')
  559. account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'Username')
  560. account.valid?
  561. expect(account).not_to model_have_error_on_field(:username)
  562. end
  563. it 'is valid even if the username doesn\'t only contains letters, numbers and underscores' do
  564. account = Fabricate.build(:account, domain: 'domain', username: 'the-doctor')
  565. account.valid?
  566. expect(account).not_to model_have_error_on_field(:username)
  567. end
  568. it 'is valid even if the username is longer then 30 characters' do
  569. account = Fabricate.build(:account, domain: 'domain', username: Faker::Lorem.characters(31))
  570. account.valid?
  571. expect(account).not_to model_have_error_on_field(:username)
  572. end
  573. it 'is valid even if the display name is longer than 30 characters' do
  574. account = Fabricate.build(:account, domain: 'domain', display_name: Faker::Lorem.characters(31))
  575. account.valid?
  576. expect(account).not_to model_have_error_on_field(:display_name)
  577. end
  578. it 'is valid even if the note is longer than 160 characters' do
  579. account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(161))
  580. account.valid?
  581. expect(account).not_to model_have_error_on_field(:note)
  582. end
  583. end
  584. end
  585. describe 'scopes' do
  586. describe 'alphabetic' do
  587. it 'sorts by alphabetic order of domain and username' do
  588. matches = [
  589. { username: 'a', domain: 'a' },
  590. { username: 'b', domain: 'a' },
  591. { username: 'a', domain: 'b' },
  592. { username: 'b', domain: 'b' },
  593. ].map(&method(:Fabricate).curry(2).call(:account))
  594. expect(Account.alphabetic).to eq matches
  595. end
  596. end
  597. describe 'matches_display_name' do
  598. it 'matches display name which starts with the given string' do
  599. match = Fabricate(:account, display_name: 'pattern and suffix')
  600. Fabricate(:account, display_name: 'prefix and pattern')
  601. expect(Account.matches_display_name('pattern')).to eq [match]
  602. end
  603. end
  604. describe 'matches_username' do
  605. it 'matches display name which starts with the given string' do
  606. match = Fabricate(:account, username: 'pattern_and_suffix')
  607. Fabricate(:account, username: 'prefix_and_pattern')
  608. expect(Account.matches_username('pattern')).to eq [match]
  609. end
  610. end
  611. describe 'expiring' do
  612. it 'returns remote accounts with followers whose subscription expiration date is past or not given' do
  613. local = Fabricate(:account, domain: nil)
  614. matches = [
  615. { domain: 'remote', subscription_expires_at: '2000-01-01T00:00:00Z' },
  616. ].map(&method(:Fabricate).curry(2).call(:account))
  617. matches.each(&local.method(:follow!))
  618. Fabricate(:account, domain: 'remote', subscription_expires_at: nil)
  619. local.follow!(Fabricate(:account, domain: 'remote', subscription_expires_at: '2000-01-03T00:00:00Z'))
  620. local.follow!(Fabricate(:account, domain: nil, subscription_expires_at: nil))
  621. expect(Account.expiring('2000-01-02T00:00:00Z').recent).to eq matches.reverse
  622. end
  623. end
  624. describe 'remote' do
  625. it 'returns an array of accounts who have a domain' do
  626. account_1 = Fabricate(:account, domain: nil)
  627. account_2 = Fabricate(:account, domain: 'example.com')
  628. expect(Account.remote).to match_array([account_2])
  629. end
  630. end
  631. describe 'by_domain_accounts' do
  632. it 'returns accounts grouped by domain sorted by accounts' do
  633. 2.times { Fabricate(:account, domain: 'example.com') }
  634. Fabricate(:account, domain: 'example2.com')
  635. results = Account.by_domain_accounts
  636. expect(results.length).to eq 2
  637. expect(results.first.domain).to eq 'example.com'
  638. expect(results.first.accounts_count).to eq 2
  639. expect(results.last.domain).to eq 'example2.com'
  640. expect(results.last.accounts_count).to eq 1
  641. end
  642. end
  643. describe 'local' do
  644. it 'returns an array of accounts who do not have a domain' do
  645. account_1 = Fabricate(:account, domain: nil)
  646. account_2 = Fabricate(:account, domain: 'example.com')
  647. expect(Account.local).to match_array([account_1])
  648. end
  649. end
  650. describe 'partitioned' do
  651. it 'returns a relation of accounts partitioned by domain' do
  652. matches = ['a', 'b', 'a', 'b']
  653. matches.size.times.to_a.shuffle.each do |index|
  654. matches[index] = Fabricate(:account, domain: matches[index])
  655. end
  656. expect(Account.partitioned).to match_array(matches)
  657. end
  658. end
  659. describe 'recent' do
  660. it 'returns a relation of accounts sorted by recent creation' do
  661. matches = 2.times.map { Fabricate(:account) }
  662. expect(Account.recent).to match_array(matches)
  663. end
  664. end
  665. describe 'silenced' do
  666. it 'returns an array of accounts who are silenced' do
  667. account_1 = Fabricate(:account, silenced: true)
  668. account_2 = Fabricate(:account, silenced: false)
  669. expect(Account.silenced).to match_array([account_1])
  670. end
  671. end
  672. describe 'suspended' do
  673. it 'returns an array of accounts who are suspended' do
  674. account_1 = Fabricate(:account, suspended: true)
  675. account_2 = Fabricate(:account, suspended: false)
  676. expect(Account.suspended).to match_array([account_1])
  677. end
  678. end
  679. describe 'without_followers' do
  680. it 'returns a relation of accounts without followers' do
  681. account_1 = Fabricate(:account)
  682. account_2 = Fabricate(:account)
  683. Fabricate(:follow, account: account_1, target_account: account_2)
  684. expect(Account.without_followers).to match_array([account_1])
  685. end
  686. end
  687. describe 'with_followers' do
  688. it 'returns a relation of accounts with followers' do
  689. account_1 = Fabricate(:account)
  690. account_2 = Fabricate(:account)
  691. Fabricate(:follow, account: account_1, target_account: account_2)
  692. expect(Account.with_followers).to match_array([account_2])
  693. end
  694. end
  695. end
  696. context 'when is local' do
  697. # Test disabled because test environment omits autogenerating keys for performance
  698. xit 'generates keys' do
  699. account = Account.create!(domain: nil, username: Faker::Internet.user_name(nil, ['_']))
  700. expect(account.keypair.private?).to eq true
  701. end
  702. end
  703. context 'when is remote' do
  704. it 'does not generate keys' do
  705. key = OpenSSL::PKey::RSA.new(1024).public_key
  706. account = Account.create!(domain: 'remote', username: Faker::Internet.user_name(nil, ['_']), public_key: key.to_pem)
  707. expect(account.keypair.params).to eq key.params
  708. end
  709. it 'normalizes domain' do
  710. account = Account.create!(domain: 'にゃん', username: Faker::Internet.user_name(nil, ['_']))
  711. expect(account.domain).to eq 'xn--r9j5b5b'
  712. end
  713. end
  714. include_examples 'AccountAvatar', :account
  715. end