435 lines
14 KiB
Ruby
435 lines
14 KiB
Ruby
# frozen_string_literal: true
|
|
|
|
require "rails_helper"
|
|
require_relative "../dummy_provider"
|
|
|
|
RSpec.describe DiscourseChatIntegration::Manager do
|
|
include_context "with dummy provider"
|
|
|
|
let(:chan1) { DiscourseChatIntegration::Channel.create!(provider: "dummy") }
|
|
let(:chan2) { DiscourseChatIntegration::Channel.create!(provider: "dummy") }
|
|
|
|
let(:category) { Fabricate(:category) }
|
|
let(:tag1) { Fabricate(:tag) }
|
|
let(:tag2) { Fabricate(:tag) }
|
|
let(:tag3) { Fabricate(:tag) }
|
|
|
|
before do
|
|
I18n.backend.store_translations(
|
|
:en,
|
|
{ chat_integration: { provider: { dummy: I18n.t("chat_integration.provider.slack") } } },
|
|
)
|
|
end
|
|
|
|
describe ".process_command" do
|
|
describe "add new rule" do
|
|
# Not testing how filters are merged here, that's done in .smart_create_rule
|
|
# We just want to make sure the commands are being interpretted correctly
|
|
|
|
it "should add a new rule correctly" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["watch", category.slug])
|
|
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.create.created"))
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.channel).to eq(chan1)
|
|
expect(rule.filter).to eq("watch")
|
|
expect(rule.category_id).to eq(category.id)
|
|
expect(rule.tags).to eq(nil)
|
|
end
|
|
|
|
it "should work with all four filter types" do
|
|
response =
|
|
DiscourseChatIntegration::Helper.process_command(chan1, ["thread", category.slug])
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.filter).to eq("thread")
|
|
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["watch", category.slug])
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.filter).to eq("watch")
|
|
|
|
response =
|
|
DiscourseChatIntegration::Helper.process_command(chan1, ["follow", category.slug])
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.filter).to eq("follow")
|
|
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["mute", category.slug])
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.filter).to eq("mute")
|
|
end
|
|
|
|
it "errors on incorrect categories" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, %w[watch blah])
|
|
|
|
expect(response).to eq(
|
|
I18n.t(
|
|
"chat_integration.provider.dummy.not_found.category",
|
|
name: "blah",
|
|
list: "uncategorized",
|
|
),
|
|
)
|
|
end
|
|
|
|
context "with tags enabled" do
|
|
before { SiteSetting.tagging_enabled = true }
|
|
|
|
it "should add a new tag rule correctly" do
|
|
response =
|
|
DiscourseChatIntegration::Helper.process_command(chan1, ["watch", "tag:#{tag1.name}"])
|
|
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.create.created"))
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.channel).to eq(chan1)
|
|
expect(rule.filter).to eq("watch")
|
|
expect(rule.category_id).to eq(nil)
|
|
expect(rule.tags).to eq([tag1.name])
|
|
end
|
|
|
|
it "should work with a category and multiple tags" do
|
|
response =
|
|
DiscourseChatIntegration::Helper.process_command(
|
|
chan1,
|
|
["watch", category.slug, "tag:#{tag1.name}", "tag:#{tag2.name}"],
|
|
)
|
|
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.create.created"))
|
|
|
|
rule = DiscourseChatIntegration::Rule.all.first
|
|
expect(rule.channel).to eq(chan1)
|
|
expect(rule.filter).to eq("watch")
|
|
expect(rule.category_id).to eq(category.id)
|
|
expect(rule.tags).to contain_exactly(tag1.name, tag2.name)
|
|
end
|
|
|
|
it "errors on incorrect tags" do
|
|
response =
|
|
DiscourseChatIntegration::Helper.process_command(
|
|
chan1,
|
|
["watch", category.slug, "tag:blah"],
|
|
)
|
|
expect(response).to eq(
|
|
I18n.t("chat_integration.provider.dummy.not_found.tag", name: "blah"),
|
|
)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe "remove rule" do
|
|
it "removes the rule" do
|
|
rule1 =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(1)
|
|
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, %w[remove 1])
|
|
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.delete.success"))
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(0)
|
|
end
|
|
|
|
it "errors correctly" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, %w[remove 1])
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.delete.error"))
|
|
end
|
|
end
|
|
|
|
describe "help command" do
|
|
it "should return the right response" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["help"])
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.help"))
|
|
end
|
|
end
|
|
|
|
describe "status command" do
|
|
it "should return the right response" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["status"])
|
|
expect(response).to eq(DiscourseChatIntegration::Helper.status_for_channel(chan1))
|
|
end
|
|
end
|
|
|
|
describe "unknown command" do
|
|
it "should return the right response" do
|
|
response = DiscourseChatIntegration::Helper.process_command(chan1, ["somerandomtext"])
|
|
expect(response).to eq(I18n.t("chat_integration.provider.dummy.parse_error"))
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".status_for_channel" do
|
|
context "with no rules" do
|
|
it "includes the heading" do
|
|
string = DiscourseChatIntegration::Helper.status_for_channel(chan1)
|
|
expect(string).to include(I18n.t("chat_integration.provider.dummy.status.header"))
|
|
end
|
|
|
|
it "includes the no_rules string" do
|
|
string = DiscourseChatIntegration::Helper.status_for_channel(chan1)
|
|
expect(string).to include(I18n.t("chat_integration.provider.dummy.status.no_rules"))
|
|
end
|
|
end
|
|
|
|
context "with some rules" do
|
|
let(:group) { Fabricate(:group) }
|
|
before do
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: nil,
|
|
)
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan1,
|
|
filter: "mute",
|
|
category_id: nil,
|
|
tags: nil,
|
|
)
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan1,
|
|
filter: "follow",
|
|
category_id: nil,
|
|
tags: [tag1.name],
|
|
)
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
type: "group_message",
|
|
group_id: group.id,
|
|
)
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan2,
|
|
filter: "watch",
|
|
category_id: 1,
|
|
tags: nil,
|
|
)
|
|
|
|
SiteSetting.tagging_enabled = false
|
|
end
|
|
|
|
it "displays the correct rules" do
|
|
string = DiscourseChatIntegration::Helper.status_for_channel(chan1)
|
|
expect(string.scan("posts in").size).to eq(4)
|
|
end
|
|
|
|
it "only displays tags for rules with tags" do
|
|
string = DiscourseChatIntegration::Helper.status_for_channel(chan1)
|
|
expect(string.scan("with tags").size).to eq(0)
|
|
|
|
SiteSetting.tagging_enabled = true
|
|
string = DiscourseChatIntegration::Helper.status_for_channel(chan1)
|
|
expect(string.scan("with tags").size).to eq(1)
|
|
end
|
|
end
|
|
end
|
|
|
|
describe ".delete_by_index" do
|
|
let(:category2) { Fabricate(:category) }
|
|
let(:category3) { Fabricate(:category) }
|
|
|
|
it "deletes the correct rule" do
|
|
# Three identical rules, with different filters
|
|
# Status will be sorted by precedence
|
|
# be in this order
|
|
rule1 =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "mute",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
rule2 =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category2.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
rule3 =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "follow",
|
|
category_id: category3.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(3)
|
|
|
|
expect(DiscourseChatIntegration::Helper.delete_by_index(chan1, 2)).to eq(:deleted)
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(2)
|
|
expect(DiscourseChatIntegration::Rule.all.map(&:category_id)).to contain_exactly(
|
|
category.id,
|
|
category3.id,
|
|
)
|
|
end
|
|
|
|
it "fails gracefully for out of range indexes" do
|
|
rule1 =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
|
|
expect(DiscourseChatIntegration::Helper.delete_by_index(chan1, -1)).to eq(false)
|
|
expect(DiscourseChatIntegration::Helper.delete_by_index(chan1, 0)).to eq(false)
|
|
expect(DiscourseChatIntegration::Helper.delete_by_index(chan1, 2)).to eq(false)
|
|
|
|
expect(DiscourseChatIntegration::Helper.delete_by_index(chan1, 1)).to eq(:deleted)
|
|
end
|
|
end
|
|
|
|
describe ".smart_create_rule" do
|
|
it "creates a rule when there are none" do
|
|
val =
|
|
DiscourseChatIntegration::Helper.smart_create_rule(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag1.name],
|
|
)
|
|
expect(val).to eq(:created)
|
|
|
|
record = DiscourseChatIntegration::Rule.all.first
|
|
expect(record.channel).to eq(chan1)
|
|
expect(record.filter).to eq("watch")
|
|
expect(record.category_id).to eq(category.id)
|
|
expect(record.tags).to eq([tag1.name])
|
|
end
|
|
|
|
it "updates a rule when it has the same category and tags" do
|
|
existing =
|
|
DiscourseChatIntegration::Rule.create!(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag2.name, tag1.name],
|
|
)
|
|
|
|
val =
|
|
DiscourseChatIntegration::Helper.smart_create_rule(
|
|
channel: chan1,
|
|
filter: "mute",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
|
|
expect(val).to eq(:updated)
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(1)
|
|
expect(DiscourseChatIntegration::Rule.all.first.filter).to eq("mute")
|
|
end
|
|
|
|
it "updates a rule when it has the same category and filter" do
|
|
existing =
|
|
DiscourseChatIntegration::Rule.create(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag2.name],
|
|
)
|
|
|
|
val =
|
|
DiscourseChatIntegration::Helper.smart_create_rule(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: category.id,
|
|
tags: [tag1.name, tag3.name],
|
|
)
|
|
|
|
expect(val).to eq(:updated)
|
|
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(1)
|
|
expect(DiscourseChatIntegration::Rule.all.first.tags).to contain_exactly(
|
|
tag1.name,
|
|
tag2.name,
|
|
tag3.name,
|
|
)
|
|
end
|
|
|
|
it "destroys duplicate rules on save" do
|
|
DiscourseChatIntegration::Rule.create!(channel: chan1, filter: "watch")
|
|
DiscourseChatIntegration::Rule.create!(channel: chan1, filter: "watch")
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(2)
|
|
val =
|
|
DiscourseChatIntegration::Helper.smart_create_rule(
|
|
channel: chan1,
|
|
filter: "watch",
|
|
category_id: nil,
|
|
tags: nil,
|
|
)
|
|
expect(val).to eq(:updated)
|
|
expect(DiscourseChatIntegration::Rule.all.size).to eq(1)
|
|
end
|
|
|
|
it "returns false on error" do
|
|
val = DiscourseChatIntegration::Helper.smart_create_rule(channel: chan1, filter: "blah")
|
|
|
|
expect(val).to eq(false)
|
|
end
|
|
end
|
|
|
|
describe ".save_transcript" do
|
|
it "saves a transcript to redis" do
|
|
key = DiscourseChatIntegration::Helper.save_transcript("Some content here")
|
|
|
|
expect(Discourse.redis.get("chat_integration:transcript:#{key}")).to eq("Some content here")
|
|
|
|
ttl = Discourse.redis.pttl("chat_integration:transcript:#{key}")
|
|
|
|
# Slight hack since freeze_time doens't work on redis
|
|
expect(Discourse.redis.pttl("chat_integration:transcript:#{key}")).to be <= (3601 * 1000)
|
|
expect(Discourse.redis.pttl("chat_integration:transcript:#{key}")).to be >= (3599 * 1000)
|
|
end
|
|
end
|
|
|
|
describe ".formatted_display_name" do
|
|
let(:user) { Fabricate(:user, name: "John Smith", username: "js1") }
|
|
|
|
it "prioritizes correctly" do
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq(
|
|
"@#{user.username} (John Smith)",
|
|
)
|
|
SiteSetting.prioritize_username_in_ux = false
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq(
|
|
"John Smith (@#{user.username})",
|
|
)
|
|
end
|
|
|
|
it "only displays one when name/username are similar" do
|
|
user.update!(username: "john_smith")
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq(
|
|
"@#{user.username}",
|
|
)
|
|
SiteSetting.prioritize_username_in_ux = false
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq("John Smith")
|
|
end
|
|
|
|
it "only displays username when names are disabled" do
|
|
SiteSetting.enable_names = false
|
|
|
|
SiteSetting.prioritize_username_in_ux = true
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq(
|
|
"@#{user.username}",
|
|
)
|
|
SiteSetting.prioritize_username_in_ux = false
|
|
expect(DiscourseChatIntegration::Helper.formatted_display_name(user)).to eq(
|
|
"@#{user.username}",
|
|
)
|
|
end
|
|
end
|
|
end
|