* Specs for FuctionCaller * Fix accepting nil values from AWS lambda * Specs for the black_box #2524 * Spec for BlackBox#comment_quality_score * Remove vcr cassette usage from the CouponGenerator spec
This commit is contained in:
parent
012b2a482c
commit
d57f8eec4a
7 changed files with 136 additions and 21 deletions
|
|
@ -1,8 +1,6 @@
|
|||
class BlackBox
|
||||
class << self
|
||||
def article_hotness_score(article)
|
||||
return (article.featured_number || 10_000) / 10_000 unless Rails.env.production?
|
||||
|
||||
def article_hotness_score(article, function_caller = FunctionCaller)
|
||||
usable_date = article.crossposted_at || article.published_at
|
||||
reaction_points = article.score
|
||||
super_super_recent_bonus = usable_date > 1.hour.ago ? 28 : 0
|
||||
|
|
@ -11,8 +9,8 @@ class BlackBox
|
|||
today_bonus = usable_date > 26.hours.ago ? 395 : 0
|
||||
two_day_bonus = usable_date > 48.hours.ago ? 330 : 0
|
||||
four_day_bonus = usable_date > 96.hours.ago ? 330 : 0
|
||||
FunctionCaller.new("blackbox-production-articleHotness",
|
||||
{ article: article, user: article.user }.to_json).call +
|
||||
function_caller.call("blackbox-production-articleHotness",
|
||||
{ article: article, user: article.user }.to_json).to_i +
|
||||
reaction_points + recency_bonus + super_recent_bonus + super_super_recent_bonus + today_bonus + two_day_bonus + four_day_bonus
|
||||
end
|
||||
|
||||
|
|
@ -24,13 +22,12 @@ class BlackBox
|
|||
(rep_points + descendants_points + bonus_points - spaminess_rating).to_i
|
||||
end
|
||||
|
||||
def calculate_spaminess(story)
|
||||
def calculate_spaminess(story, function_caller = FunctionCaller)
|
||||
# accepts comment or article as story
|
||||
return 0 unless Rails.env.production?
|
||||
return 100 unless story.user
|
||||
|
||||
FunctionCaller.new("blackbox-production-spamScore",
|
||||
{ story: story, user: story.user }.to_json).call
|
||||
function_caller.call("blackbox-production-spamScore",
|
||||
{ story: story, user: story.user }.to_json).to_i
|
||||
end
|
||||
|
||||
private
|
||||
|
|
|
|||
|
|
@ -1,12 +1,20 @@
|
|||
class FunctionCaller
|
||||
attr_accessor :function_name, :payload
|
||||
def initialize(function_name, payload)
|
||||
def initialize(function_name, payload, aws_lambda_client = AWS_LAMBDA)
|
||||
@function_name = function_name
|
||||
@payload = payload
|
||||
@aws_lambda_client = aws_lambda_client
|
||||
end
|
||||
|
||||
def self.call(*args)
|
||||
new(*args).call
|
||||
end
|
||||
|
||||
def call
|
||||
response = AWS_LAMBDA.invoke(function_name: function_name, payload: payload)
|
||||
response = aws_lambda_client.invoke(function_name: function_name, payload: payload)
|
||||
JSON.parse(JSON.parse(response.payload.as_json[0])["body"])["message"]
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
attr_reader :function_name, :payload, :aws_lambda_client
|
||||
end
|
||||
|
|
|
|||
10
app/services/aws/fake_client.rb
Normal file
10
app/services/aws/fake_client.rb
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
# Fake Aws client is used in non-production environments to prevent actual calls to AWS lambda
|
||||
module Aws
|
||||
class FakeClient
|
||||
def initialize; end
|
||||
|
||||
def invoke(*)
|
||||
OpenStruct.new(payload: [{ body: { message: 0 }.to_json }.to_json])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -1,5 +1,9 @@
|
|||
AWS_LAMBDA = Aws::Lambda::Client.new(
|
||||
region: ApplicationConfig["AWS_DEFAULT_REGION"],
|
||||
access_key_id: ApplicationConfig["AWS_SDK_KEY"],
|
||||
secret_access_key: ApplicationConfig["AWS_SDK_SECRET"],
|
||||
)
|
||||
AWS_LAMBDA = if Rails.env.production?
|
||||
Aws::Lambda::Client.new(
|
||||
region: ApplicationConfig["AWS_DEFAULT_REGION"],
|
||||
access_key_id: ApplicationConfig["AWS_SDK_KEY"],
|
||||
secret_access_key: ApplicationConfig["AWS_SDK_SECRET"],
|
||||
)
|
||||
else
|
||||
AWS_LAMBDA = Aws::FakeClient.new
|
||||
end
|
||||
|
|
|
|||
77
spec/black_box/black_box_spec.rb
Normal file
77
spec/black_box/black_box_spec.rb
Normal file
|
|
@ -0,0 +1,77 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe BlackBox do
|
||||
let!(:function_caller) { double }
|
||||
|
||||
describe "#article_hotness_score" do
|
||||
let!(:article) { create(:article, published_at: Time.current) }
|
||||
|
||||
it "calls function caller" do
|
||||
allow(function_caller).to receive(:call).and_return(5)
|
||||
described_class.article_hotness_score(article, function_caller)
|
||||
expect(function_caller).to have_received(:call).once
|
||||
end
|
||||
|
||||
it "doesn't fail when function caller returns nil" do
|
||||
allow(function_caller).to receive(:call).and_return(nil)
|
||||
described_class.article_hotness_score(article, function_caller)
|
||||
end
|
||||
|
||||
it "returns the correct value" do
|
||||
article.update_column(:score, 99)
|
||||
allow(function_caller).to receive(:call).and_return(5)
|
||||
# recent bonuses (28 + 31 + 80 + 395 + 330 + 330 = 1194)
|
||||
# + score (99)
|
||||
# + value from the function caller (5)
|
||||
score = described_class.article_hotness_score(article, function_caller)
|
||||
expect(score).to eq(1298)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#comment_quality_score" do
|
||||
let(:comment) { create(:comment, commentable: create(:article), body_markdown: "```#{'hello, world! ' * 20}```") }
|
||||
|
||||
before do
|
||||
reaction = create(:reaction, reactable: comment)
|
||||
reaction.update_column(:points, 20)
|
||||
reaction2 = create(:reaction, reactable: comment)
|
||||
reaction2.update_column(:points, 2)
|
||||
end
|
||||
|
||||
it "returns the correct score" do
|
||||
# rep_points + descendants_points + bonus_points - spaminess_rating
|
||||
# rep_points - 22
|
||||
# descendants_points - 0
|
||||
# bonus_points - 2 + 1 = 3
|
||||
# spaminess_rating - 0
|
||||
# 22 + 0 + 3 - 0 = 25
|
||||
expect(described_class.comment_quality_score(comment)).to eq(25)
|
||||
end
|
||||
end
|
||||
|
||||
describe "#calculate_spaminess" do
|
||||
let(:user) { build(:user) }
|
||||
let(:comment) { build(:comment, user: user) }
|
||||
|
||||
before do
|
||||
allow(function_caller).to receive(:call).and_return(1)
|
||||
end
|
||||
|
||||
it "returns 100 if there is no user" do
|
||||
story = instance_double("Comment", user: nil)
|
||||
expect(described_class.calculate_spaminess(story, function_caller)).to eq(100)
|
||||
expect(function_caller).not_to have_received(:call)
|
||||
end
|
||||
|
||||
it "calls the function_caller" do
|
||||
described_class.calculate_spaminess(comment, function_caller)
|
||||
expect(function_caller).to have_received(:call).with("blackbox-production-spamScore",
|
||||
{ story: comment, user: user }.to_json).once
|
||||
end
|
||||
|
||||
it "returns the value that the caller returns" do
|
||||
spaminess = described_class.calculate_spaminess(comment, function_caller)
|
||||
expect(spaminess).to eq(1)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
@ -5,10 +5,8 @@ RSpec.describe CouponGenerator, vcr: {} do
|
|||
|
||||
describe "#expect" do
|
||||
it "generates code with proper prefix ( [version]_[code] )" do
|
||||
VCR.use_cassette "coupon_generator_1" do
|
||||
version = versions.sample
|
||||
expect(described_class.new(1, version).generate).to include("#{version}_")
|
||||
end
|
||||
version = versions.sample
|
||||
expect(described_class.new(1, version).generate).to include("#{version}_")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
|
|
|||
21
spec/labor/function_caller_spec.rb
Normal file
21
spec/labor/function_caller_spec.rb
Normal file
|
|
@ -0,0 +1,21 @@
|
|||
require "rails_helper"
|
||||
|
||||
RSpec.describe FunctionCaller do
|
||||
let(:payload) { { user_id: 1, name: "hello" } }
|
||||
let(:dummy_client) { double }
|
||||
let(:result) { OpenStruct.new(payload: [{ body: { message: "hi" }.to_json }.to_json]) }
|
||||
|
||||
before do
|
||||
allow(dummy_client).to receive(:invoke).and_return(result)
|
||||
end
|
||||
|
||||
it "calls the aws_lambda_client" do
|
||||
described_class.call("some_function", payload, dummy_client)
|
||||
expect(dummy_client).to have_received(:invoke).with(function_name: "some_function", payload: payload)
|
||||
end
|
||||
|
||||
it "returns parsed value" do
|
||||
value = described_class.call("some_function", payload, dummy_client)
|
||||
expect(value).to eq("hi")
|
||||
end
|
||||
end
|
||||
Loading…
Add table
Reference in a new issue