docbrown/spec/services/rss_reader_spec.rb
rhymes 3b4bda89df Upgrade Honeycomb gem, fix and improve RssReader tests (#2319)
* Switch from deprecated honeycomb-rails to honeycomb-beeline

* Improve error handling, tests and add refactoring

* Fix multiple fetching test and add one more

The test wasn't actually testing the correct behavior, because the class
by default force fetches. It worked because it wasn't reloading the user
from the database.

* Test that Honeycomb's client is doing its thing

* Use some defensive programming to avoid any possible problem during shutdown

* Fix typo

* Use the new API to add fields to the current measured event

* Use default instrumentation and add user info to event

* Replace user.email with user.username, less personal data around

* Use mocking instead of calling Honeycomb.init

* Freeze time before traveling

* Remove a flaky test dependent on rand
2019-04-07 15:27:53 -04:00

169 lines
5.4 KiB
Ruby

require "rails_helper"
require "rss"
vcr_option = {
cassette_name: "rss_feeds",
allow_playback_repeats: "true"
}
class HoneycombEventStub
attr_reader :data
def initialize
@data = {}
end
def add(metadata)
@data.merge!(metadata)
end
def add_field(key, value)
@data[key] = value
end
end
RSpec.describe RssReader, vcr: vcr_option do
let(:link) { "https://medium.com/feed/@vaidehijoshi" }
let(:nonmedium_link) { "https://circleci.com/blog/feed.xml" }
let(:nonpermanent_link) { "https://medium.com/feed/@macsiri/" }
let(:rss_data) { RSS::Parser.parse(HTTParty.get(link).body, false) }
before do
# Honeycomb.init has too many side effects during testing, so we mock the client
event = HoneycombEventStub.new
allow(event).to receive(:send)
client_double = instance_double("Libhoney::TestClient", event: event, events: [event])
allow(Honeycomb).to receive(:client) { client_double }
end
describe "#get_all_articles" do
before do
[link, nonmedium_link, nonpermanent_link].each do |feed_url|
create(:user, feed_url: feed_url)
end
end
it "fetch only articles from an feed_url" do
described_class.get_all_articles
# the result within the approval file depends on the feed
# not fetching comments is baked into this
verify(format: :txt) { Article.count }
end
it "does not re-create article if it already exist" do
described_class.new.get_all_articles
expect { described_class.new.get_all_articles }.not_to change(Article, :count)
end
it "parses correctly" do
described_class.new.get_all_articles
verify format: :txt do
User.find_by(feed_url: nonpermanent_link).articles.first.body_markdown
end
end
it "sets time current" do
described_class.new.get_all_articles
expect(User.find_by(feed_url: nonpermanent_link).feed_fetched_at).to be > 2.minutes.ago
end
it "does refetch same user over and over by default" do
user = User.find_by(feed_url: nonpermanent_link)
Timecop.freeze(Time.current) do
user.update_column(:feed_fetched_at, Time.current)
fetched_at_time = user.reload.feed_fetched_at
# travel a few seconds in the future to simulate a new time
3.times do |i|
Timecop.travel((i + 5).seconds.from_now) { described_class.new.get_all_articles }
end
expect(user.reload.feed_fetched_at > fetched_at_time).to be(true)
end
end
it "logs an article creation error" do
reader = described_class.new
allow(reader).to receive(:make_from_rss_item).and_raise(StandardError)
allow(Rails.logger).to receive(:error)
reader.get_all_articles
expect(Rails.logger).to have_received(:error).at_least(:once)
end
it "logs a fetching error" do
reader = described_class.new
allow(reader).to receive(:fetch_rss).and_raise(StandardError)
allow(Rails.logger).to receive(:error)
reader.get_all_articles
expect(Rails.logger).to have_received(:error).at_least(:once)
end
end
describe "#fetch_user" do
before do
[link, nonmedium_link, nonpermanent_link].each do |feed_url|
create(:user, feed_url: feed_url)
end
end
it "gets articles for user" do
# the result within the approval file depends on the feed
described_class.new.fetch_user(User.first)
verify(format: :txt) { Article.count }
end
it "does not set featured_number" do
described_class.new.fetch_user(User.first)
expect(Article.all.map(&:featured_number).uniq).to eq([nil])
end
it "logs an article creation error on the standard logger" do
reader = described_class.new
allow(reader).to receive(:make_from_rss_item).and_raise(StandardError)
allow(Rails.logger).to receive(:error)
reader.fetch_user(User.first)
expect(Rails.logger).to have_received(:error).at_least(:once)
end
it "logs an article creation error on the observability tool" do
reader = described_class.new
allow(reader).to receive(:make_from_rss_item).and_raise(StandardError)
reader.fetch_user(User.first)
expected_observable_fields = [
:user, :feed_url, :item_count, :error,
"error_msg", "trace.trace_id", "trace.parent_id", "trace.span_id"
]
expect(Honeycomb.client.events.first.data.keys).to eq(expected_observable_fields)
end
it "logs a fetching error on the standard logger" do
reader = described_class.new
allow(reader).to receive(:fetch_rss).and_raise(StandardError)
allow(Rails.logger).to receive(:error)
reader.fetch_user(User.first)
expect(Rails.logger).to have_received(:error).at_least(:once)
end
it "logs a fetching error on the observability tool" do
reader = described_class.new
allow(reader).to receive(:fetch_rss).and_raise(StandardError)
reader.fetch_user(User.first)
expected_observable_fields = [
:user, :feed_url, :item_count, :error,
"error_msg", "trace.trace_id", "trace.parent_id", "trace.span_id"
]
expect(Honeycomb.client.events.first.data.keys).to eq(expected_observable_fields)
end
end
describe "#valid_feed_url?" do
it "returns true on valid feed url" do
expect(described_class.new.valid_feed_url?(link)).to be true
end
it "returns false on invalid feed url" do
bad_link = "www.google.com"
expect(described_class.new.valid_feed_url?(bad_link)).to be false
end
end
end