require_relative 'spec_helper' require_relative '../lib/shep' require "stringio" include Shep describe Session, :anonymous do include_context :uses_temp_dir it "retrieves account information." do ss = Session.new(host: HOST, ua_comment: "(integration test)") acct = ss.fetch_account(READ_ACCOUNT) expect( acct.class ) .to be Entity::Account expect( acct.id ) .to eq READ_ACCOUNT %i{username display_name locked bot created_at followers_count following_count} .each {|fld| expect( acct[fld] ) .to_not eq nil } end it "keeps track of rate limit information." do ss = Session.new(host: HOST, ua_comment: "(integration test)") acct = ss.fetch_account(READ_ACCOUNT) expect( ss.rate_limit.remaining ) .to be <= ss.rate_limit.limit # Race condition, but unlikely to be a problem expect( ss.rate_limit.reset ) .to be > Time.now end it "retrieves followers and following accounts." do ss = Session.new(host: HOST, ua_comment: "(integration test)") following = ss.each_following(READ_ACCOUNT, limit: 10).to_a expect( following.size ) .to be <= 10 expect( following[0].class ) .to be Entity::Account following = nil followers = ss.each_follower(READ_ACCOUNT, limit: 10).to_a expect( followers.size ) .to be <= 10 expect( followers[0].class ) .to be Entity::Account end it "retrieves statuses." do ss = Session.new(host: HOST, ua_comment: "(integration test)") sts_all = ss.each_status(READ_ACCOUNT, limit: 50).to_a expect( sts_all.size ) .to be > 0 # This is not complete, alas. The test account doesn't have many # interactions so stuff like exclude_replies doesn't really change stuff. sts_orig = ss.each_status(READ_ACCOUNT, limit: 50, exclude_replies: true, exclude_reblogs: true ).to_a expect( sts_orig.size ) .to be > 0 #expect( sts_orig ) .to_not eq sts_all sts_pinned = ss.each_status(READ_ACCOUNT, limit: 50, pinned: true, ).to_a expect( sts_pinned.size ) .to be > 0 expect( sts_pinned ) .to_not eq sts_all # Retrieves statuses when no limit: value is set count = 0 ss.each_status(READ_ACCOUNT) {|stat| count += 1; break if count > 41 } expect( count ) .to be > 41 end it "does more account stuff." do ss = Session.new(host: HOST, ua_comment: "(integration test)") acct1 = ss.fetch_account_by_username(READ_ACCOUNT_HANDLE) acct2 = ss.fetch_account(acct1.id) expect( acct1 ) .to eq acct2 # If it's missing, you should get nil back. (Funny prank idea: create # this account just to mess with me.) bogus = ss.fetch_account_by_username("bogus_account_not_here_alsidjfals") expect( bogus ) .to be nil end it "fetches individual statuses." do ss = Session.new(host: HOST, ua_comment: "(integration test)") count = 0 ss.each_status(READ_ACCOUNT, limit: 5) {|ref_status| new_status = ss.fetch_status(ref_status.id) expect(new_status) .to eq ref_status count += 1 } expect(count) .to be > 0 end it "leaves optional session fields nil if no token is given." do ss = Session.new(host: HOST, ua_comment: "(integration test)") statuses = ss.each_status(READ_ACCOUNT, limit: 1).to_a expect( statuses.size ) .to be > 0 status = statuses[0] expect( status.favourited ) .to be nil expect( status.reblogged ) .to be nil expect( status.muted ) .to be nil expect( status.bookmarked ) .to be nil expect( status.pinned ) .to be nil end it "fetches status contexts." do ss = Session.new(host: HOST, ua_comment: "(integration test)") # Search for the first status to have a reply match_status = nil match_context = nil count = 0 ss.each_status(READ_ACCOUNT, limit: 500) {|ref_status| count += 1 context = ss.fetch_context(ref_status.id) unless context.descendants.empty? match_status = ref_status match_context = context break end } expect( count ) .to be > 0 expect( !!match_status && !!match_context ) .to be true # Now fetch its descendent and the descendent's ancestors to # confirm that the one we found is in it. kid = ss.fetch_status(match_context.descendants[0].id) kid_ancestors = ss.fetch_context(kid.id).ancestors expect( kid_ancestors.map{|a| a.id} ) .to include(match_status.id) end it "fetches accounts that boosted and/or favourited a status." do ss = Session.new(host: HOST, ua_comment: "(integration test)") status_count = 0 boosted_found = 0 boosters_found = 0 faved_found = 0 favers_found = 0 ss.each_status(READ_ACCOUNT, limit: 500) do |status| status_count += 1 if status.reblogs_count > 0 boosted_found += 1 boosts = ss.each_boost_acct(status.id, limit: 10).to_a boosters_found += boosts.size end if status.favourites_count > 0 faved_found += 1 faves = ss.each_fave_acct(status.id, limit: 10).to_a favers_found += faves.size end break if favers_found > 0 && boosters_found > 0 end puts "\nfaves/boosts: searched #{status_count} statuses." # This will be false if there are no favourited or no boosted # statuses in the searched range of stats. That's not necessarily # a bug here, but it's hard to test without assuming this so we # test for it. expect( faved_found > 0 && boosters_found > 0 ) .to be true # Ditto for these. Depends on account visibility (I *think*) expect( favers_found ) .to be > 0 expect( boosters_found ) .to be > 0 end it "retrieves groups of items via block as well as enumerator." do ss = Session.new(host: HOST, ua_comment: "(integration test)") count = 0 ss.each_following(READ_ACCOUNT, limit: 10) { count += 1 } expect( count ) .to be > 0 count = 0 ss.each_follower(READ_ACCOUNT, limit: 10) { count += 1 } expect( count ) .to be > 0 count = 0 ss.each_status(READ_ACCOUNT, limit: 10) { count += 1 } expect( count ) .to be > 0 end it "retrieves status' media attachments." do ss = Session.new(host: HOST, ua_comment: "(integration test)") # Find the earliest status with one or more media attachments candidate = nil ss.each_status(READ_ACCOUNT, limit: 500) { |stat| if stat.media_attachments.size > 0 candidate = stat break end } # This can happen if there are no statuses with media attachments # in READ_ACCOUNT, but in that case we can't test, so # :shrug_emoji: expect( candidate ) .to_not be nil status, files = ss.fetch_status_with_media(candidate.id, tmp_dir) expect( status ) .to eq candidate # BTW expect( files.empty? ) .to be false file0 = files.values[0] expect( file0 ) .to_not be nil # Ensure the file is present an non-empty. (Technically, it # *could* be empty, but :shrug_emoji: as above). expect( File.exist?( file0 ) ) .to be true fsz = File.size( file0 ) expect( fsz ) .to be > 0 # Test refetch: false; ensure it doesn't overwrite if the file is # present. File.open(file0, "w") {|fh| } # truncate the file expect( File.size( file0 ) ) .to eq 0 _, files2 = ss.fetch_status_with_media(candidate.id, tmp_dir, refetch: false) expect( files2) .to eq files # No overwrite expect( File.size( file0 ) ) .to eq 0 # Now, ensure that refetch:false *does* overwrite the file _, files3 = ss.fetch_status_with_media(candidate.id, tmp_dir, refetch: true) expect( files3) .to eq files expect( File.size( file0 ) ) .to eq fsz end it "retrieves the site's public timeline." do ss = Session.new(host: HOST, ua_comment: "(integration test)") caturday = "caturday" # Find the latest 100 toots. This assumes an average distribution # that may not happen on the actual live server, in which case # this test will fail for no good reason. default_tl = ss.each_public_status(limit: 200).to_a # Some toots are federated expect( default_tl.select{|st| st.account.acct.include? '@'}.empty? ) .to be false # Some toots are local expect( default_tl.reject{|st| st.account.acct.include? '@'}.empty? ) .to be false # Some toots contain media expect( default_tl.reject{|st| st.media_attachments.empty? }.empty? ) .to be false # All statuses should contain media when selecting only_media media_tl = ss.each_public_status(limit: 20, only_media: true).to_a; expect( media_tl.select{|st| st.media_attachments.empty?} ) .to eq [] # local:true should return no toots from a remote site local_tl = ss.each_public_status(limit: 20, local: true).to_a; expect( local_tl.select{|st| st.account.acct.include? '@' } ) .to eq [] # remote:true should return no toots from the local site remote_tl = ss.each_public_status(limit: 20, remote: true).to_a; expect( remote_tl.reject{|st| st.account.acct.include? '@' } ) .to eq [] end it "retrieves posts by tag." do caturday = "caturday" ss = Session.new(host: HOST, ua_comment: "(integration test)") # Find the latest 100 toots. This assumes an average distribution # that may not happen on the actual live server, in which case # this test will fail for no good reason. default_tl = ss.each_tag_status(caturday, limit: 200).to_a # Some toots are federated expect( default_tl.select{|st| st.account.acct.include? '@'}.empty? ) .to be false # Some toots are local expect( default_tl.reject{|st| st.account.acct.include? '@'}.empty? ) .to be false # Some toots contain media expect( default_tl.reject{|st| st.media_attachments.empty? }.empty? ) .to be false # All statuses should contain media when selecting only_media media_tl = ss.each_tag_status(caturday, limit: 20, only_media: true) .to_a expect( media_tl.select{|st| st.media_attachments.empty?} ) .to eq [] # local:true should return no toots from a remote site local_tl = ss.each_tag_status(caturday, limit: 20, local: true).to_a; expect( local_tl.select{|st| st.account.acct.include? '@' } ) .to eq [] # remote:true should return no toots from the local site remote_tl = ss.each_tag_status("caturday", limit: 20, remote: true).to_a expect( remote_tl.reject{|st| st.account.acct.include? '@' } ) .to eq [] # # any/all/none # # Expect all of the extra tags plus_all = ["cats", "catsofmastodon"] remote_tl = ss.each_tag_status(caturday, limit: 20, all: plus_all ).to_a remote_tl.empty? and puts "WARNING: found no posts with tags #{[caturday] + plus_all}" remote_tl.each{|rstat| found_tags = rstat.tags.map{|t| t.name.downcase}.to_set expect( found_tags ) .to be >= plus_all.to_set } # Expect none of the extra tags plus_none = ["cats", "catsofmastodon"] remote_tl = ss.each_tag_status(caturday, limit: 20, none: plus_none ).to_a remote_tl.empty? and puts"WARNING: found no posts w/ #{caturday} but not #{plus_none}" remote_tl.each{|rstat| found_tags = rstat.tags.map{|t| t.name.downcase}.to_set expect( found_tags & plus_none ) .to be_empty } # Expect any of the following plus_any = [caturday, "cats", "catsofmastodon"] remote_tl = ss.each_tag_status(plus_any, limit: 20).to_a remote_tl.empty? and puts"WARNING: found no posts w/ #{caturday} but some of #{plus_any}" expected = plus_any + [caturday] remote_tl.each{|rstat| found_tags = rstat.tags.map{|t| t.name.downcase}.to_set expect( found_tags & expected ) .to_not be_empty } end end