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.

795 lines
25 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 'https://remote.test/invalid_avatar'
  105. expect(account.header_remote_url).to eq expectation.header_remote_url
  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 '#possibly_stale?' do
  112. let(:account) { Fabricate(:account, last_webfingered_at: last_webfingered_at) }
  113. context 'last_webfingered_at is nil' do
  114. let(:last_webfingered_at) { nil }
  115. it 'returns true' do
  116. expect(account.possibly_stale?).to be true
  117. end
  118. end
  119. context 'last_webfingered_at is more than 24 hours before' do
  120. let(:last_webfingered_at) { 25.hours.ago }
  121. it 'returns true' do
  122. expect(account.possibly_stale?).to be true
  123. end
  124. end
  125. context 'last_webfingered_at is less than 24 hours before' do
  126. let(:last_webfingered_at) { 23.hours.ago }
  127. it 'returns false' do
  128. expect(account.possibly_stale?).to be false
  129. end
  130. end
  131. end
  132. describe '#refresh!' do
  133. let(:account) { Fabricate(:account, domain: domain) }
  134. let(:acct) { account.acct }
  135. context 'domain is nil' do
  136. let(:domain) { nil }
  137. it 'returns nil' do
  138. expect(account.refresh!).to be_nil
  139. end
  140. it 'calls not ResolveAccountService#call' do
  141. expect_any_instance_of(ResolveAccountService).not_to receive(:call).with(acct)
  142. account.refresh!
  143. end
  144. end
  145. context 'domain is present' do
  146. let(:domain) { 'example.com' }
  147. it 'calls ResolveAccountService#call' do
  148. expect_any_instance_of(ResolveAccountService).to receive(:call).with(acct).once
  149. account.refresh!
  150. end
  151. end
  152. end
  153. describe '#to_param' do
  154. it 'returns username' do
  155. account = Fabricate(:account, username: 'alice')
  156. expect(account.to_param).to eq 'alice'
  157. end
  158. end
  159. describe '#keypair' do
  160. it 'returns an RSA key pair' do
  161. account = Fabricate(:account)
  162. expect(account.keypair).to be_instance_of OpenSSL::PKey::RSA
  163. end
  164. end
  165. describe '#object_type' do
  166. it 'is always a person' do
  167. account = Fabricate(:account)
  168. expect(account.object_type).to be :person
  169. end
  170. end
  171. describe '#favourited?' do
  172. let(:original_status) do
  173. author = Fabricate(:account, username: 'original')
  174. Fabricate(:status, account: author)
  175. end
  176. subject { Fabricate(:account) }
  177. context 'when the status is a reblog of another status' do
  178. let(:original_reblog) do
  179. author = Fabricate(:account, username: 'original_reblogger')
  180. Fabricate(:status, reblog: original_status, account: author)
  181. end
  182. it 'is is true when this account has favourited it' do
  183. Fabricate(:favourite, status: original_reblog, account: subject)
  184. expect(subject.favourited?(original_status)).to eq true
  185. end
  186. it 'is false when this account has not favourited it' do
  187. expect(subject.favourited?(original_status)).to eq false
  188. end
  189. end
  190. context 'when the status is an original status' do
  191. it 'is is true when this account has favourited it' do
  192. Fabricate(:favourite, status: original_status, account: subject)
  193. expect(subject.favourited?(original_status)).to eq true
  194. end
  195. it 'is false when this account has not favourited it' do
  196. expect(subject.favourited?(original_status)).to eq false
  197. end
  198. end
  199. end
  200. describe '#reblogged?' do
  201. let(:original_status) do
  202. author = Fabricate(:account, username: 'original')
  203. Fabricate(:status, account: author)
  204. end
  205. subject { Fabricate(:account) }
  206. context 'when the status is a reblog of another status' do
  207. let(:original_reblog) do
  208. author = Fabricate(:account, username: 'original_reblogger')
  209. Fabricate(:status, reblog: original_status, account: author)
  210. end
  211. it 'is true when this account has reblogged it' do
  212. Fabricate(:status, reblog: original_reblog, account: subject)
  213. expect(subject.reblogged?(original_reblog)).to eq true
  214. end
  215. it 'is false when this account has not reblogged it' do
  216. expect(subject.reblogged?(original_reblog)).to eq false
  217. end
  218. end
  219. context 'when the status is an original status' do
  220. it 'is true when this account has reblogged it' do
  221. Fabricate(:status, reblog: original_status, account: subject)
  222. expect(subject.reblogged?(original_status)).to eq true
  223. end
  224. it 'is false when this account has not reblogged it' do
  225. expect(subject.reblogged?(original_status)).to eq false
  226. end
  227. end
  228. end
  229. describe '#excluded_from_timeline_account_ids' do
  230. it 'includes account ids of blockings, blocked_bys and mutes' do
  231. account = Fabricate(:account)
  232. block = Fabricate(:block, account: account)
  233. mute = Fabricate(:mute, account: account)
  234. block_by = Fabricate(:block, target_account: account)
  235. results = account.excluded_from_timeline_account_ids
  236. expect(results.size).to eq 3
  237. expect(results).to include(block.target_account.id)
  238. expect(results).to include(mute.target_account.id)
  239. expect(results).to include(block_by.account.id)
  240. end
  241. end
  242. describe '#excluded_from_timeline_domains' do
  243. it 'returns the domains blocked by the account' do
  244. account = Fabricate(:account)
  245. account.block_domain!('domain')
  246. expect(account.excluded_from_timeline_domains).to match_array ['domain']
  247. end
  248. end
  249. describe '.search_for' do
  250. before do
  251. _missing = Fabricate(
  252. :account,
  253. display_name: "Missing",
  254. username: "missing",
  255. domain: "missing.com"
  256. )
  257. end
  258. it 'accepts ?, \, : and space as delimiter' do
  259. match = Fabricate(
  260. :account,
  261. display_name: 'A & l & i & c & e',
  262. username: 'username',
  263. domain: 'example.com'
  264. )
  265. results = Account.search_for('A?l\i:c e')
  266. expect(results).to eq [match]
  267. end
  268. it 'finds accounts with matching display_name' do
  269. match = Fabricate(
  270. :account,
  271. display_name: "Display Name",
  272. username: "username",
  273. domain: "example.com"
  274. )
  275. results = Account.search_for("display")
  276. expect(results).to eq [match]
  277. end
  278. it 'finds accounts with matching username' do
  279. match = Fabricate(
  280. :account,
  281. display_name: "Display Name",
  282. username: "username",
  283. domain: "example.com"
  284. )
  285. results = Account.search_for("username")
  286. expect(results).to eq [match]
  287. end
  288. it 'finds accounts with matching domain' do
  289. match = Fabricate(
  290. :account,
  291. display_name: "Display Name",
  292. username: "username",
  293. domain: "example.com"
  294. )
  295. results = Account.search_for("example")
  296. expect(results).to eq [match]
  297. end
  298. it 'limits by 10 by default' do
  299. 11.times.each { Fabricate(:account, display_name: "Display Name") }
  300. results = Account.search_for("display")
  301. expect(results.size).to eq 10
  302. end
  303. it 'accepts arbitrary limits' do
  304. 2.times.each { Fabricate(:account, display_name: "Display Name") }
  305. results = Account.search_for("display", 1)
  306. expect(results.size).to eq 1
  307. end
  308. it 'ranks multiple matches higher' do
  309. matches = [
  310. { username: "username", display_name: "username" },
  311. { display_name: "Display Name", username: "username", domain: "example.com" },
  312. ].map(&method(:Fabricate).curry(2).call(:account))
  313. results = Account.search_for("username")
  314. expect(results).to eq matches
  315. end
  316. end
  317. describe '.advanced_search_for' do
  318. it 'accepts ?, \, : and space as delimiter' do
  319. account = Fabricate(:account)
  320. match = Fabricate(
  321. :account,
  322. display_name: 'A & l & i & c & e',
  323. username: 'username',
  324. domain: 'example.com'
  325. )
  326. results = Account.advanced_search_for('A?l\i:c e', account)
  327. expect(results).to eq [match]
  328. end
  329. it 'limits by 10 by default' do
  330. 11.times { Fabricate(:account, display_name: "Display Name") }
  331. results = Account.search_for("display")
  332. expect(results.size).to eq 10
  333. end
  334. it 'accepts arbitrary limits' do
  335. 2.times { Fabricate(:account, display_name: "Display Name") }
  336. results = Account.search_for("display", 1)
  337. expect(results.size).to eq 1
  338. end
  339. it 'ranks followed accounts higher' do
  340. account = Fabricate(:account)
  341. match = Fabricate(:account, username: "Matching")
  342. followed_match = Fabricate(:account, username: "Matcher")
  343. Fabricate(:follow, account: account, target_account: followed_match)
  344. results = Account.advanced_search_for("match", account)
  345. expect(results).to eq [followed_match, match]
  346. expect(results.first.rank).to be > results.last.rank
  347. end
  348. end
  349. describe '#statuses_count' do
  350. subject { Fabricate(:account) }
  351. it 'counts statuses' do
  352. Fabricate(:status, account: subject)
  353. Fabricate(:status, account: subject)
  354. expect(subject.statuses_count).to eq 2
  355. end
  356. it 'does not count direct statuses' do
  357. Fabricate(:status, account: subject, visibility: :direct)
  358. expect(subject.statuses_count).to eq 0
  359. end
  360. it 'is decremented when status is removed' do
  361. status = Fabricate(:status, account: subject)
  362. expect(subject.statuses_count).to eq 1
  363. status.destroy
  364. expect(subject.statuses_count).to eq 0
  365. end
  366. it 'is decremented when status is removed when account is not preloaded' do
  367. status = Fabricate(:status, account: subject)
  368. expect(subject.reload.statuses_count).to eq 1
  369. clean_status = Status.find(status.id)
  370. expect(clean_status.association(:account).loaded?).to be false
  371. clean_status.destroy
  372. expect(subject.reload.statuses_count).to eq 0
  373. end
  374. end
  375. describe '.following_map' do
  376. it 'returns an hash' do
  377. expect(Account.following_map([], 1)).to be_a Hash
  378. end
  379. end
  380. describe '.followed_by_map' do
  381. it 'returns an hash' do
  382. expect(Account.followed_by_map([], 1)).to be_a Hash
  383. end
  384. end
  385. describe '.blocking_map' do
  386. it 'returns an hash' do
  387. expect(Account.blocking_map([], 1)).to be_a Hash
  388. end
  389. end
  390. describe '.requested_map' do
  391. it 'returns an hash' do
  392. expect(Account.requested_map([], 1)).to be_a Hash
  393. end
  394. end
  395. describe 'MENTION_RE' do
  396. subject { Account::MENTION_RE }
  397. it 'matches usernames in the middle of a sentence' do
  398. expect(subject.match('Hello to @alice from me')[1]).to eq 'alice'
  399. end
  400. it 'matches usernames in the beginning of status' do
  401. expect(subject.match('@alice Hey how are you?')[1]).to eq 'alice'
  402. end
  403. it 'matches full usernames' do
  404. expect(subject.match('@alice@example.com')[1]).to eq 'alice@example.com'
  405. end
  406. it 'matches full usernames with a dot at the end' do
  407. expect(subject.match('Hello @alice@example.com.')[1]).to eq 'alice@example.com'
  408. end
  409. it 'matches dot-prepended usernames' do
  410. expect(subject.match('.@alice I want everybody to see this')[1]).to eq 'alice'
  411. end
  412. it 'does not match e-mails' do
  413. expect(subject.match('Drop me an e-mail at alice@example.com')).to be_nil
  414. end
  415. it 'does not match URLs' do
  416. expect(subject.match('Check this out https://medium.com/@alice/some-article#.abcdef123')).to be_nil
  417. end
  418. xit 'does not match URL querystring' do
  419. expect(subject.match('https://example.com/?x=@alice')).to be_nil
  420. end
  421. end
  422. describe 'validations' do
  423. it 'has a valid fabricator' do
  424. account = Fabricate.build(:account)
  425. account.valid?
  426. expect(account).to be_valid
  427. end
  428. it 'is invalid without a username' do
  429. account = Fabricate.build(:account, username: nil)
  430. account.valid?
  431. expect(account).to model_have_error_on_field(:username)
  432. end
  433. it 'squishes the username before validation' do
  434. account = Fabricate(:account, domain: nil, username: " \u3000bob \t \u00a0 \n ")
  435. expect(account.username).to eq 'bob'
  436. end
  437. context 'when is local' do
  438. it 'is invalid if the username is not unique in case-insensitive comparison among local accounts' do
  439. account_1 = Fabricate(:account, username: 'the_doctor')
  440. account_2 = Fabricate.build(:account, username: 'the_Doctor')
  441. account_2.valid?
  442. expect(account_2).to model_have_error_on_field(:username)
  443. end
  444. it 'is invalid if the username is reserved' do
  445. account = Fabricate.build(:account, username: 'support')
  446. account.valid?
  447. expect(account).to model_have_error_on_field(:username)
  448. end
  449. it 'is valid when username is reserved but record has already been created' do
  450. account = Fabricate.build(:account, username: 'support')
  451. account.save(validate: false)
  452. expect(account.valid?).to be true
  453. end
  454. it 'is valid if we are creating an instance actor account with a period' do
  455. account = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com')
  456. expect(account.valid?).to be true
  457. end
  458. it 'is valid if we are creating a possibly-conflicting instance actor account' do
  459. account_1 = Fabricate(:account, username: 'examplecom')
  460. account_2 = Fabricate.build(:account, id: -99, actor_type: 'Application', locked: true, username: 'example.com')
  461. expect(account_2.valid?).to be true
  462. end
  463. it 'is invalid if the username doesn\'t only contains letters, numbers and underscores' do
  464. account = Fabricate.build(:account, username: 'the-doctor')
  465. account.valid?
  466. expect(account).to model_have_error_on_field(:username)
  467. end
  468. it 'is invalid if the username contains a period' do
  469. account = Fabricate.build(:account, username: 'the.doctor')
  470. account.valid?
  471. expect(account).to model_have_error_on_field(:username)
  472. end
  473. it 'is invalid if the username is longer then 30 characters' do
  474. account = Fabricate.build(:account, username: Faker::Lorem.characters(number: 31))
  475. account.valid?
  476. expect(account).to model_have_error_on_field(:username)
  477. end
  478. it 'is invalid if the display name is longer than 30 characters' do
  479. account = Fabricate.build(:account, display_name: Faker::Lorem.characters(number: 31))
  480. account.valid?
  481. expect(account).to model_have_error_on_field(:display_name)
  482. end
  483. it 'is invalid if the note is longer than 500 characters' do
  484. account = Fabricate.build(:account, note: Faker::Lorem.characters(number: 501))
  485. account.valid?
  486. expect(account).to model_have_error_on_field(:note)
  487. end
  488. end
  489. context 'when is remote' do
  490. it 'is invalid if the username is same among accounts in the same normalized domain' do
  491. Fabricate(:account, domain: 'にゃん', username: 'username')
  492. account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'username')
  493. account.valid?
  494. expect(account).to model_have_error_on_field(:username)
  495. end
  496. it 'is invalid if the username is not unique in case-insensitive comparison among accounts in the same normalized domain' do
  497. Fabricate(:account, domain: 'にゃん', username: 'username')
  498. account = Fabricate.build(:account, domain: 'xn--r9j5b5b', username: 'Username')
  499. account.valid?
  500. expect(account).to model_have_error_on_field(:username)
  501. end
  502. it 'is valid even if the username contains hyphens' do
  503. account = Fabricate.build(:account, domain: 'domain', username: 'the-doctor')
  504. account.valid?
  505. expect(account).to_not model_have_error_on_field(:username)
  506. end
  507. it 'is invalid if the username doesn\'t only contains letters, numbers, underscores and hyphens' do
  508. account = Fabricate.build(:account, domain: 'domain', username: 'the doctor')
  509. account.valid?
  510. expect(account).to model_have_error_on_field(:username)
  511. end
  512. it 'is valid even if the username is longer then 30 characters' do
  513. account = Fabricate.build(:account, domain: 'domain', username: Faker::Lorem.characters(number: 31))
  514. account.valid?
  515. expect(account).not_to model_have_error_on_field(:username)
  516. end
  517. it 'is valid even if the display name is longer than 30 characters' do
  518. account = Fabricate.build(:account, domain: 'domain', display_name: Faker::Lorem.characters(number: 31))
  519. account.valid?
  520. expect(account).not_to model_have_error_on_field(:display_name)
  521. end
  522. it 'is valid even if the note is longer than 500 characters' do
  523. account = Fabricate.build(:account, domain: 'domain', note: Faker::Lorem.characters(number: 501))
  524. account.valid?
  525. expect(account).not_to model_have_error_on_field(:note)
  526. end
  527. end
  528. end
  529. describe 'scopes' do
  530. describe 'alphabetic' do
  531. it 'sorts by alphabetic order of domain and username' do
  532. matches = [
  533. { username: 'a', domain: 'a' },
  534. { username: 'b', domain: 'a' },
  535. { username: 'a', domain: 'b' },
  536. { username: 'b', domain: 'b' },
  537. ].map(&method(:Fabricate).curry(2).call(:account))
  538. expect(Account.where('id > 0').alphabetic).to eq matches
  539. end
  540. end
  541. describe 'matches_display_name' do
  542. it 'matches display name which starts with the given string' do
  543. match = Fabricate(:account, display_name: 'pattern and suffix')
  544. Fabricate(:account, display_name: 'prefix and pattern')
  545. expect(Account.matches_display_name('pattern')).to eq [match]
  546. end
  547. end
  548. describe 'matches_username' do
  549. it 'matches display name which starts with the given string' do
  550. match = Fabricate(:account, username: 'pattern_and_suffix')
  551. Fabricate(:account, username: 'prefix_and_pattern')
  552. expect(Account.matches_username('pattern')).to eq [match]
  553. end
  554. end
  555. describe 'by_domain_and_subdomains' do
  556. it 'returns exact domain matches' do
  557. account = Fabricate(:account, domain: 'example.com')
  558. expect(Account.by_domain_and_subdomains('example.com')).to eq [account]
  559. end
  560. it 'returns subdomains' do
  561. account = Fabricate(:account, domain: 'foo.example.com')
  562. expect(Account.by_domain_and_subdomains('example.com')).to eq [account]
  563. end
  564. it 'does not return partially matching domains' do
  565. account = Fabricate(:account, domain: 'grexample.com')
  566. expect(Account.by_domain_and_subdomains('example.com')).to_not eq [account]
  567. end
  568. end
  569. describe 'remote' do
  570. it 'returns an array of accounts who have a domain' do
  571. account_1 = Fabricate(:account, domain: nil)
  572. account_2 = Fabricate(:account, domain: 'example.com')
  573. expect(Account.remote).to match_array([account_2])
  574. end
  575. end
  576. describe 'local' do
  577. it 'returns an array of accounts who do not have a domain' do
  578. account_1 = Fabricate(:account, domain: nil)
  579. account_2 = Fabricate(:account, domain: 'example.com')
  580. expect(Account.where('id > 0').local).to match_array([account_1])
  581. end
  582. end
  583. describe 'partitioned' do
  584. it 'returns a relation of accounts partitioned by domain' do
  585. matches = ['a', 'b', 'a', 'b']
  586. matches.size.times.to_a.shuffle.each do |index|
  587. matches[index] = Fabricate(:account, domain: matches[index])
  588. end
  589. expect(Account.where('id > 0').partitioned).to match_array(matches)
  590. end
  591. end
  592. describe 'recent' do
  593. it 'returns a relation of accounts sorted by recent creation' do
  594. matches = 2.times.map { Fabricate(:account) }
  595. expect(Account.where('id > 0').recent).to match_array(matches)
  596. end
  597. end
  598. describe 'silenced' do
  599. it 'returns an array of accounts who are silenced' do
  600. account_1 = Fabricate(:account, silenced: true)
  601. account_2 = Fabricate(:account, silenced: false)
  602. expect(Account.silenced).to match_array([account_1])
  603. end
  604. end
  605. describe 'suspended' do
  606. it 'returns an array of accounts who are suspended' do
  607. account_1 = Fabricate(:account, suspended: true)
  608. account_2 = Fabricate(:account, suspended: false)
  609. expect(Account.suspended).to match_array([account_1])
  610. end
  611. end
  612. end
  613. context 'when is local' do
  614. # Test disabled because test environment omits autogenerating keys for performance
  615. xit 'generates keys' do
  616. account = Account.create!(domain: nil, username: Faker::Internet.user_name(separators: ['_']))
  617. expect(account.keypair.private?).to eq true
  618. end
  619. end
  620. context 'when is remote' do
  621. it 'does not generate keys' do
  622. key = OpenSSL::PKey::RSA.new(1024).public_key
  623. account = Account.create!(domain: 'remote', username: Faker::Internet.user_name(separators: ['_']), public_key: key.to_pem)
  624. expect(account.keypair.params).to eq key.params
  625. end
  626. it 'normalizes domain' do
  627. account = Account.create!(domain: 'にゃん', username: Faker::Internet.user_name(separators: ['_']))
  628. expect(account.domain).to eq 'xn--r9j5b5b'
  629. end
  630. end
  631. include_examples 'AccountAvatar', :account
  632. include_examples 'AccountHeader', :account
  633. describe '#increment_count!' do
  634. subject { Fabricate(:account) }
  635. it 'increments the count in multi-threaded an environment when account_stat is not yet initialized' do
  636. subject
  637. increment_by = 15
  638. wait_for_start = true
  639. threads = Array.new(increment_by) do
  640. Thread.new do
  641. true while wait_for_start
  642. Account.find(subject.id).increment_count!(:followers_count)
  643. end
  644. end
  645. wait_for_start = false
  646. threads.each(&:join)
  647. expect(subject.reload.followers_count).to eq 15
  648. end
  649. end
  650. end