mirror of
https://github.com/discourse/discourse.git
synced 2025-02-25 18:55:32 -06:00
DEV: Apply syntax_tree formatting to spec/*
This commit is contained in:
@@ -39,7 +39,6 @@ RSpec.describe CachedCounting do
|
||||
end
|
||||
|
||||
it "can dispatch counts to backing class" do
|
||||
|
||||
CachedCounting.queue("a,a", TestCachedCounting)
|
||||
CachedCounting.queue("a,a", TestCachedCounting)
|
||||
CachedCounting.queue("b", TestCachedCounting)
|
||||
@@ -48,7 +47,6 @@ RSpec.describe CachedCounting do
|
||||
CachedCounting.flush_to_db
|
||||
|
||||
expect(TestCachedCounting.data).to eq({ "a,a" => 2, "b" => 1 })
|
||||
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -76,20 +74,15 @@ RSpec.describe CachedCounting do
|
||||
CachedCounting.enable
|
||||
end
|
||||
|
||||
after do
|
||||
CachedCounting.disable
|
||||
end
|
||||
after { CachedCounting.disable }
|
||||
|
||||
it "can dispatch data via background thread" do
|
||||
|
||||
freeze_time
|
||||
d1 = Time.now.utc.to_date
|
||||
|
||||
RailsCacheCounter.perform_increment!("a,a")
|
||||
RailsCacheCounter.perform_increment!("b")
|
||||
20.times do
|
||||
RailsCacheCounter.perform_increment!("a,a")
|
||||
end
|
||||
20.times { RailsCacheCounter.perform_increment!("a,a") }
|
||||
|
||||
freeze_time 2.days.from_now
|
||||
d2 = Time.now.utc.to_date
|
||||
@@ -99,12 +92,7 @@ RSpec.describe CachedCounting do
|
||||
|
||||
CachedCounting.flush
|
||||
|
||||
expected = {
|
||||
["a,a", d1] => 21,
|
||||
["b", d1] => 1,
|
||||
["a,a", d2] => 1,
|
||||
["d", d2] => 1,
|
||||
}
|
||||
expected = { ["a,a", d1] => 21, ["b", d1] => 1, ["a,a", d2] => 1, ["d", d2] => 1 }
|
||||
|
||||
expect(RailsCacheCounter.cache_data).to eq(expected)
|
||||
end
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
# frozen_string_literal: true
|
||||
|
||||
RSpec.describe CategoryHashtag do
|
||||
describe '#query_from_hashtag_slug' do
|
||||
describe "#query_from_hashtag_slug" do
|
||||
fab!(:parent_category) { Fabricate(:category) }
|
||||
fab!(:child_category) { Fabricate(:category, parent_category: parent_category) }
|
||||
|
||||
it "should return the right result for a parent category slug" do
|
||||
expect(Category.query_from_hashtag_slug(parent_category.slug))
|
||||
.to eq(parent_category)
|
||||
expect(Category.query_from_hashtag_slug(parent_category.slug)).to eq(parent_category)
|
||||
end
|
||||
|
||||
it "should return the right result for a parent and child category slug" do
|
||||
expect(Category.query_from_hashtag_slug("#{parent_category.slug}#{CategoryHashtag::SEPARATOR}#{child_category.slug}"))
|
||||
.to eq(child_category)
|
||||
expect(
|
||||
Category.query_from_hashtag_slug(
|
||||
"#{parent_category.slug}#{CategoryHashtag::SEPARATOR}#{child_category.slug}",
|
||||
),
|
||||
).to eq(child_category)
|
||||
end
|
||||
|
||||
it "should return nil for incorrect parent category slug" do
|
||||
@@ -20,22 +22,29 @@ RSpec.describe CategoryHashtag do
|
||||
end
|
||||
|
||||
it "should return nil for incorrect parent and child category slug" do
|
||||
expect(Category.query_from_hashtag_slug("random-slug#{CategoryHashtag::SEPARATOR}random-slug")).to eq(nil)
|
||||
expect(
|
||||
Category.query_from_hashtag_slug("random-slug#{CategoryHashtag::SEPARATOR}random-slug"),
|
||||
).to eq(nil)
|
||||
end
|
||||
|
||||
it "should return nil for a non-existent root and a parent subcategory" do
|
||||
expect(Category.query_from_hashtag_slug("non-existent#{CategoryHashtag::SEPARATOR}#{parent_category.slug}")).to eq(nil)
|
||||
expect(
|
||||
Category.query_from_hashtag_slug(
|
||||
"non-existent#{CategoryHashtag::SEPARATOR}#{parent_category.slug}",
|
||||
),
|
||||
).to eq(nil)
|
||||
end
|
||||
|
||||
context "with multi-level categories" do
|
||||
before do
|
||||
SiteSetting.max_category_nesting = 3
|
||||
end
|
||||
before { SiteSetting.max_category_nesting = 3 }
|
||||
|
||||
it "should return the right result for a grand child category slug" do
|
||||
category = Fabricate(:category, parent_category: child_category)
|
||||
expect(Category.query_from_hashtag_slug("#{child_category.slug}#{CategoryHashtag::SEPARATOR}#{category.slug}"))
|
||||
.to eq(category)
|
||||
expect(
|
||||
Category.query_from_hashtag_slug(
|
||||
"#{child_category.slug}#{CategoryHashtag::SEPARATOR}#{category.slug}",
|
||||
),
|
||||
).to eq(category)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,9 @@ RSpec.describe HasCustomFields do
|
||||
describe "custom_fields" do
|
||||
before do
|
||||
DB.exec("create temporary table custom_fields_test_items(id SERIAL primary key)")
|
||||
DB.exec("create temporary table custom_fields_test_item_custom_fields(id SERIAL primary key, custom_fields_test_item_id int, name varchar(256) not null, value text, created_at TIMESTAMP, updated_at TIMESTAMP)")
|
||||
DB.exec(
|
||||
"create temporary table custom_fields_test_item_custom_fields(id SERIAL primary key, custom_fields_test_item_id int, name varchar(256) not null, value text, created_at TIMESTAMP, updated_at TIMESTAMP)",
|
||||
)
|
||||
DB.exec(<<~SQL)
|
||||
CREATE UNIQUE INDEX ON custom_fields_test_item_custom_fields (custom_fields_test_item_id)
|
||||
WHERE NAME = 'rare'
|
||||
@@ -38,7 +40,9 @@ RSpec.describe HasCustomFields do
|
||||
it "errors if a custom field is not preloaded" do
|
||||
test_item = CustomFieldsTestItem.new
|
||||
CustomFieldsTestItem.preload_custom_fields([test_item], ["test_field"])
|
||||
expect { test_item.custom_fields["other_field"] }.to raise_error(HasCustomFields::NotPreloadedError)
|
||||
expect { test_item.custom_fields["other_field"] }.to raise_error(
|
||||
HasCustomFields::NotPreloadedError,
|
||||
)
|
||||
end
|
||||
|
||||
it "resets the preloaded_custom_fields if preload_custom_fields is called twice" do
|
||||
@@ -105,7 +109,10 @@ RSpec.describe HasCustomFields do
|
||||
# should be casted right after saving
|
||||
expect(test_item.custom_fields["a"]).to eq("0")
|
||||
|
||||
DB.exec("UPDATE custom_fields_test_item_custom_fields SET value='1' WHERE custom_fields_test_item_id=? AND name='a'", test_item.id)
|
||||
DB.exec(
|
||||
"UPDATE custom_fields_test_item_custom_fields SET value='1' WHERE custom_fields_test_item_id=? AND name='a'",
|
||||
test_item.id,
|
||||
)
|
||||
|
||||
# still the same, did not load
|
||||
expect(test_item.custom_fields["a"]).to eq("0")
|
||||
@@ -137,25 +144,25 @@ RSpec.describe HasCustomFields do
|
||||
expect(db_item.custom_fields).to eq("array" => [1])
|
||||
|
||||
test_item = CustomFieldsTestItem.new
|
||||
test_item.custom_fields = { "a" => ["b", "c", "d"] }
|
||||
test_item.custom_fields = { "a" => %w[b c d] }
|
||||
test_item.save
|
||||
|
||||
db_item = CustomFieldsTestItem.find(test_item.id)
|
||||
expect(db_item.custom_fields).to eq("a" => ["b", "c", "d"])
|
||||
expect(db_item.custom_fields).to eq("a" => %w[b c d])
|
||||
|
||||
db_item.custom_fields.update('a' => ['c', 'd'])
|
||||
db_item.custom_fields.update("a" => %w[c d])
|
||||
db_item.save
|
||||
expect(db_item.custom_fields).to eq("a" => ["c", "d"])
|
||||
expect(db_item.custom_fields).to eq("a" => %w[c d])
|
||||
|
||||
# It can be updated to the exact same value
|
||||
db_item.custom_fields.update('a' => ['c'])
|
||||
db_item.custom_fields.update("a" => ["c"])
|
||||
db_item.save
|
||||
expect(db_item.custom_fields).to eq("a" => "c")
|
||||
db_item.custom_fields.update('a' => ['c'])
|
||||
db_item.custom_fields.update("a" => ["c"])
|
||||
db_item.save
|
||||
expect(db_item.custom_fields).to eq("a" => "c")
|
||||
|
||||
db_item.custom_fields.delete('a')
|
||||
db_item.custom_fields.delete("a")
|
||||
expect(db_item.custom_fields).to eq({})
|
||||
end
|
||||
|
||||
@@ -176,10 +183,10 @@ RSpec.describe HasCustomFields do
|
||||
test_item = CustomFieldsTestItem.new
|
||||
test_item.custom_fields = { "a" => ["b", 10, "d"] }
|
||||
test_item.save
|
||||
expect(test_item.custom_fields).to eq("a" => ["b", "10", "d"])
|
||||
expect(test_item.custom_fields).to eq("a" => %w[b 10 d])
|
||||
|
||||
db_item = CustomFieldsTestItem.find(test_item.id)
|
||||
expect(db_item.custom_fields).to eq("a" => ["b", "10", "d"])
|
||||
expect(db_item.custom_fields).to eq("a" => %w[b 10 d])
|
||||
end
|
||||
|
||||
it "supports type coercion" do
|
||||
@@ -192,14 +199,22 @@ RSpec.describe HasCustomFields do
|
||||
test_item.save
|
||||
test_item.reload
|
||||
|
||||
expect(test_item.custom_fields).to eq("bool" => true, "int" => 1, "json" => { "foo" => "bar" })
|
||||
expect(test_item.custom_fields).to eq(
|
||||
"bool" => true,
|
||||
"int" => 1,
|
||||
"json" => {
|
||||
"foo" => "bar",
|
||||
},
|
||||
)
|
||||
|
||||
before_ids = CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
|
||||
before_ids =
|
||||
CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
|
||||
|
||||
test_item.custom_fields["bool"] = false
|
||||
test_item.save
|
||||
|
||||
after_ids = CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
|
||||
after_ids =
|
||||
CustomFieldsTestItemCustomField.where(custom_fields_test_item_id: test_item.id).pluck(:id)
|
||||
|
||||
# we updated only 1 custom field, so there should be only 1 different id
|
||||
expect((before_ids - after_ids).size).to eq(1)
|
||||
@@ -234,23 +249,19 @@ RSpec.describe HasCustomFields do
|
||||
CustomFieldsTestItem.register_custom_field_type(field_type, :json)
|
||||
|
||||
item = CustomFieldsTestItem.new
|
||||
item.custom_fields = {
|
||||
"json_array" => [{ a: "test" }, { b: "another" }]
|
||||
}
|
||||
item.custom_fields = { "json_array" => [{ a: "test" }, { b: "another" }] }
|
||||
item.save
|
||||
|
||||
item.reload
|
||||
|
||||
expect(item.custom_fields[field_type]).to eq(
|
||||
[{ "a" => "test" }, { "b" => "another" }]
|
||||
)
|
||||
expect(item.custom_fields[field_type]).to eq([{ "a" => "test" }, { "b" => "another" }])
|
||||
|
||||
item.custom_fields["json_array"] = ['a', 'b']
|
||||
item.custom_fields["json_array"] = %w[a b]
|
||||
item.save
|
||||
|
||||
item.reload
|
||||
|
||||
expect(item.custom_fields[field_type]).to eq(["a", "b"])
|
||||
expect(item.custom_fields[field_type]).to eq(%w[a b])
|
||||
end
|
||||
|
||||
it "will not fail to load custom fields if json is corrupt" do
|
||||
@@ -262,7 +273,7 @@ RSpec.describe HasCustomFields do
|
||||
CustomFieldsTestItemCustomField.create!(
|
||||
custom_fields_test_item_id: item.id,
|
||||
name: field_type,
|
||||
value: "{test"
|
||||
value: "{test",
|
||||
)
|
||||
|
||||
item = item.reload
|
||||
@@ -271,34 +282,34 @@ RSpec.describe HasCustomFields do
|
||||
|
||||
it "supports bulk retrieval with a list of ids" do
|
||||
item1 = CustomFieldsTestItem.new
|
||||
item1.custom_fields = { "a" => ["b", "c", "d"], 'not_allowlisted' => 'secret' }
|
||||
item1.custom_fields = { "a" => %w[b c d], "not_allowlisted" => "secret" }
|
||||
item1.save
|
||||
|
||||
item2 = CustomFieldsTestItem.new
|
||||
item2.custom_fields = { "e" => 'hallo' }
|
||||
item2.custom_fields = { "e" => "hallo" }
|
||||
item2.save
|
||||
|
||||
fields = CustomFieldsTestItem.custom_fields_for_ids([item1.id, item2.id], ['a', 'e'])
|
||||
fields = CustomFieldsTestItem.custom_fields_for_ids([item1.id, item2.id], %w[a e])
|
||||
expect(fields).to be_present
|
||||
expect(fields[item1.id]['a']).to match_array(['b', 'c', 'd'])
|
||||
expect(fields[item1.id]['not_allowlisted']).to be_blank
|
||||
expect(fields[item2.id]['e']).to eq('hallo')
|
||||
expect(fields[item1.id]["a"]).to match_array(%w[b c d])
|
||||
expect(fields[item1.id]["not_allowlisted"]).to be_blank
|
||||
expect(fields[item2.id]["e"]).to eq("hallo")
|
||||
end
|
||||
|
||||
it "handles interleaving saving properly" do
|
||||
field_type = 'deep-nest-test'
|
||||
field_type = "deep-nest-test"
|
||||
CustomFieldsTestItem.register_custom_field_type(field_type, :json)
|
||||
test_item = CustomFieldsTestItem.create!
|
||||
|
||||
test_item.custom_fields[field_type] ||= {}
|
||||
test_item.custom_fields[field_type]['b'] ||= {}
|
||||
test_item.custom_fields[field_type]['b']['c'] = 'd'
|
||||
test_item.custom_fields[field_type]["b"] ||= {}
|
||||
test_item.custom_fields[field_type]["b"]["c"] = "d"
|
||||
test_item.save_custom_fields(true)
|
||||
|
||||
db_item = CustomFieldsTestItem.find(test_item.id)
|
||||
db_item.custom_fields[field_type]['b']['e'] = 'f'
|
||||
test_item.custom_fields[field_type]['b']['e'] = 'f'
|
||||
expected = { field_type => { 'b' => { 'c' => 'd', 'e' => 'f' } } }
|
||||
db_item.custom_fields[field_type]["b"]["e"] = "f"
|
||||
test_item.custom_fields[field_type]["b"]["e"] = "f"
|
||||
expected = { field_type => { "b" => { "c" => "d", "e" => "f" } } }
|
||||
|
||||
db_item.save_custom_fields(true)
|
||||
expect(db_item.reload.custom_fields).to eq(expected)
|
||||
@@ -307,7 +318,7 @@ RSpec.describe HasCustomFields do
|
||||
expect(test_item.reload.custom_fields).to eq(expected)
|
||||
end
|
||||
|
||||
it 'determines clean state correctly for mutable fields' do
|
||||
it "determines clean state correctly for mutable fields" do
|
||||
json_field = "json_field"
|
||||
array_field = "array_field"
|
||||
CustomFieldsTestItem.register_custom_field_type(json_field, :json)
|
||||
@@ -339,94 +350,94 @@ RSpec.describe HasCustomFields do
|
||||
describe "create_singular" do
|
||||
it "creates new records" do
|
||||
item = CustomFieldsTestItem.create!
|
||||
item.create_singular('hello', 'world')
|
||||
expect(item.reload.custom_fields['hello']).to eq('world')
|
||||
item.create_singular("hello", "world")
|
||||
expect(item.reload.custom_fields["hello"]).to eq("world")
|
||||
end
|
||||
|
||||
it "upserts on a database constraint error" do
|
||||
item0 = CustomFieldsTestItem.new
|
||||
item0.custom_fields = { "rare" => "gem" }
|
||||
item0.save
|
||||
expect(item0.reload.custom_fields['rare']).to eq("gem")
|
||||
expect(item0.reload.custom_fields["rare"]).to eq("gem")
|
||||
|
||||
item0.create_singular('rare', "diamond")
|
||||
expect(item0.reload.custom_fields['rare']).to eq("diamond")
|
||||
item0.create_singular("rare", "diamond")
|
||||
expect(item0.reload.custom_fields["rare"]).to eq("diamond")
|
||||
end
|
||||
end
|
||||
|
||||
describe "upsert_custom_fields" do
|
||||
it 'upserts records' do
|
||||
it "upserts records" do
|
||||
test_item = CustomFieldsTestItem.create
|
||||
test_item.upsert_custom_fields('hello' => 'world', 'abc' => 'def')
|
||||
test_item.upsert_custom_fields("hello" => "world", "abc" => "def")
|
||||
|
||||
# In memory
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('def')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("def")
|
||||
|
||||
# Persisted
|
||||
test_item.reload
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('def')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("def")
|
||||
|
||||
# In memory
|
||||
test_item.upsert_custom_fields('abc' => 'ghi')
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('ghi')
|
||||
test_item.upsert_custom_fields("abc" => "ghi")
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("ghi")
|
||||
|
||||
# Persisted
|
||||
test_item.reload
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('ghi')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("ghi")
|
||||
end
|
||||
|
||||
it 'allows upsert to use keywords' do
|
||||
it "allows upsert to use keywords" do
|
||||
test_item = CustomFieldsTestItem.create
|
||||
test_item.upsert_custom_fields(hello: 'world', abc: 'def')
|
||||
test_item.upsert_custom_fields(hello: "world", abc: "def")
|
||||
|
||||
# In memory
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('def')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("def")
|
||||
|
||||
# Persisted
|
||||
test_item.reload
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('def')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("def")
|
||||
|
||||
# In memory
|
||||
test_item.upsert_custom_fields('abc' => 'ghi')
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('ghi')
|
||||
test_item.upsert_custom_fields("abc" => "ghi")
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("ghi")
|
||||
|
||||
# Persisted
|
||||
test_item.reload
|
||||
expect(test_item.custom_fields['hello']).to eq('world')
|
||||
expect(test_item.custom_fields['abc']).to eq('ghi')
|
||||
expect(test_item.custom_fields["hello"]).to eq("world")
|
||||
expect(test_item.custom_fields["abc"]).to eq("ghi")
|
||||
end
|
||||
|
||||
it 'allows using string and symbol indices interchangeably' do
|
||||
it "allows using string and symbol indices interchangeably" do
|
||||
test_item = CustomFieldsTestItem.new
|
||||
|
||||
test_item.custom_fields["bob"] = "marley"
|
||||
test_item.custom_fields["jack"] = "black"
|
||||
|
||||
# In memory
|
||||
expect(test_item.custom_fields[:bob]).to eq('marley')
|
||||
expect(test_item.custom_fields[:jack]).to eq('black')
|
||||
expect(test_item.custom_fields[:bob]).to eq("marley")
|
||||
expect(test_item.custom_fields[:jack]).to eq("black")
|
||||
|
||||
# Persisted
|
||||
test_item.save
|
||||
test_item.reload
|
||||
expect(test_item.custom_fields[:bob]).to eq('marley')
|
||||
expect(test_item.custom_fields[:jack]).to eq('black')
|
||||
expect(test_item.custom_fields[:bob]).to eq("marley")
|
||||
expect(test_item.custom_fields[:jack]).to eq("black")
|
||||
|
||||
# Update via string index again
|
||||
test_item.custom_fields['bob'] = 'the builder'
|
||||
test_item.custom_fields["bob"] = "the builder"
|
||||
|
||||
expect(test_item.custom_fields[:bob]).to eq('the builder')
|
||||
expect(test_item.custom_fields[:bob]).to eq("the builder")
|
||||
test_item.save
|
||||
test_item.reload
|
||||
|
||||
expect(test_item.custom_fields[:bob]).to eq('the builder')
|
||||
expect(test_item.custom_fields[:bob]).to eq("the builder")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,7 +4,9 @@ RSpec.describe HasSearchData do
|
||||
describe "belongs to its model" do
|
||||
before do
|
||||
DB.exec("create temporary table model_items(id SERIAL primary key)")
|
||||
DB.exec("create temporary table model_item_search_data(model_item_id int primary key, search_data tsvector, raw_data text, locale text)")
|
||||
DB.exec(
|
||||
"create temporary table model_item_search_data(model_item_id int primary key, search_data tsvector, raw_data text, locale text)",
|
||||
)
|
||||
|
||||
class ModelItem < ActiveRecord::Base
|
||||
has_one :model_item_search_data, dependent: :destroy
|
||||
@@ -29,17 +31,18 @@ RSpec.describe HasSearchData do
|
||||
item = ModelItem.create!
|
||||
item.create_model_item_search_data!(
|
||||
model_item_id: item.id,
|
||||
search_data: 'a',
|
||||
raw_data: 'a',
|
||||
locale: 'en')
|
||||
search_data: "a",
|
||||
raw_data: "a",
|
||||
locale: "en",
|
||||
)
|
||||
item
|
||||
end
|
||||
|
||||
it 'sets its primary key into associated model' do
|
||||
expect(ModelItemSearchData.primary_key).to eq 'model_item_id'
|
||||
it "sets its primary key into associated model" do
|
||||
expect(ModelItemSearchData.primary_key).to eq "model_item_id"
|
||||
end
|
||||
|
||||
it 'can access the model' do
|
||||
it "can access the model" do
|
||||
record_id = item.id
|
||||
expect(ModelItemSearchData.find_by(model_item_id: record_id).model_item_id).to eq record_id
|
||||
end
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
|
||||
RSpec.describe Positionable do
|
||||
def positions
|
||||
TestItem.order('position asc, id asc').pluck(:id)
|
||||
TestItem.order("position asc, id asc").pluck(:id)
|
||||
end
|
||||
|
||||
describe "move_to" do
|
||||
@@ -23,9 +23,7 @@ RSpec.describe Positionable do
|
||||
end
|
||||
|
||||
it "can position stuff correctly" do
|
||||
5.times do |i|
|
||||
DB.exec("insert into test_items(id,position) values(#{i}, #{i})")
|
||||
end
|
||||
5.times { |i| DB.exec("insert into test_items(id,position) values(#{i}, #{i})") }
|
||||
|
||||
expect(positions).to eq([0, 1, 2, 3, 4])
|
||||
TestItem.find(3).move_to(0)
|
||||
|
||||
@@ -4,14 +4,16 @@ RSpec.describe Searchable do
|
||||
describe "has search data" do
|
||||
before do
|
||||
DB.exec("create temporary table searchable_records(id SERIAL primary key)")
|
||||
DB.exec("create temporary table searchable_record_search_data(searchable_record_id int primary key, search_data tsvector, raw_data text, locale text)")
|
||||
DB.exec(
|
||||
"create temporary table searchable_record_search_data(searchable_record_id int primary key, search_data tsvector, raw_data text, locale text)",
|
||||
)
|
||||
|
||||
class SearchableRecord < ActiveRecord::Base
|
||||
include Searchable
|
||||
end
|
||||
|
||||
class SearchableRecordSearchData < ActiveRecord::Base
|
||||
self.primary_key = 'searchable_record_id'
|
||||
self.primary_key = "searchable_record_id"
|
||||
belongs_to :test_item
|
||||
end
|
||||
end
|
||||
@@ -28,26 +30,20 @@ RSpec.describe Searchable do
|
||||
|
||||
let(:item) { SearchableRecord.create! }
|
||||
|
||||
it 'can build the data' do
|
||||
it "can build the data" do
|
||||
expect(item.build_searchable_record_search_data).to be_truthy
|
||||
end
|
||||
|
||||
it 'can save the data' do
|
||||
item.build_searchable_record_search_data(
|
||||
search_data: '',
|
||||
raw_data: 'a',
|
||||
locale: 'en')
|
||||
it "can save the data" do
|
||||
item.build_searchable_record_search_data(search_data: "", raw_data: "a", locale: "en")
|
||||
item.save
|
||||
|
||||
loaded = SearchableRecord.find(item.id)
|
||||
expect(loaded.searchable_record_search_data.raw_data).to eq 'a'
|
||||
expect(loaded.searchable_record_search_data.raw_data).to eq "a"
|
||||
end
|
||||
|
||||
it 'destroy the search data when the item is deprived' do
|
||||
item.build_searchable_record_search_data(
|
||||
search_data: '',
|
||||
raw_data: 'a',
|
||||
locale: 'en')
|
||||
it "destroy the search data when the item is deprived" do
|
||||
item.build_searchable_record_search_data(search_data: "", raw_data: "a", locale: "en")
|
||||
item.save
|
||||
item_id = item.id
|
||||
item.destroy
|
||||
|
||||
@@ -8,29 +8,31 @@ RSpec.describe SecondFactorManager do
|
||||
:user_security_key,
|
||||
user: user,
|
||||
public_key: valid_security_key_data[:public_key],
|
||||
credential_id: valid_security_key_data[:credential_id]
|
||||
credential_id: valid_security_key_data[:credential_id],
|
||||
)
|
||||
end
|
||||
fab!(:another_user) { Fabricate(:user) }
|
||||
|
||||
fab!(:user_second_factor_backup) { Fabricate(:user_second_factor_backup) }
|
||||
let(:user_backup) { user_second_factor_backup.user }
|
||||
let(:user_backup) { user_second_factor_backup.user }
|
||||
|
||||
describe '#totp' do
|
||||
it 'should return the right data' do
|
||||
describe "#totp" do
|
||||
it "should return the right data" do
|
||||
totp = nil
|
||||
|
||||
expect do
|
||||
totp = another_user.create_totp(enabled: true)
|
||||
end.to change { UserSecondFactor.count }.by(1)
|
||||
expect do totp = another_user.create_totp(enabled: true) end.to change {
|
||||
UserSecondFactor.count
|
||||
}.by(1)
|
||||
|
||||
expect(totp.totp_object.issuer).to eq(SiteSetting.title)
|
||||
expect(totp.totp_object.secret).to eq(another_user.reload.user_second_factors.totps.first.data)
|
||||
expect(totp.totp_object.secret).to eq(
|
||||
another_user.reload.user_second_factors.totps.first.data,
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_totp' do
|
||||
it 'should create the right record' do
|
||||
describe "#create_totp" do
|
||||
it "should create the right record" do
|
||||
second_factor = another_user.create_totp(enabled: true)
|
||||
|
||||
expect(second_factor.method).to eq(UserSecondFactor.methods[:totp])
|
||||
@@ -39,28 +41,28 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#totp_provisioning_uri' do
|
||||
it 'should return the right uri' do
|
||||
describe "#totp_provisioning_uri" do
|
||||
it "should return the right uri" do
|
||||
expect(user.user_second_factors.totps.first.totp_provisioning_uri).to eq(
|
||||
"otpauth://totp/#{SiteSetting.title}:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=#{SiteSetting.title}"
|
||||
"otpauth://totp/#{SiteSetting.title}:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=#{SiteSetting.title}",
|
||||
)
|
||||
end
|
||||
it 'should handle a colon in the site title' do
|
||||
SiteSetting.title = 'Spaceballs: The Discourse'
|
||||
it "should handle a colon in the site title" do
|
||||
SiteSetting.title = "Spaceballs: The Discourse"
|
||||
expect(user.user_second_factors.totps.first.totp_provisioning_uri).to eq(
|
||||
"otpauth://totp/Spaceballs%20The%20Discourse:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=Spaceballs%20The%20Discourse"
|
||||
"otpauth://totp/Spaceballs%20The%20Discourse:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=Spaceballs%20The%20Discourse",
|
||||
)
|
||||
end
|
||||
it 'should handle a two words before a colon in the title' do
|
||||
SiteSetting.title = 'Our Spaceballs: The Discourse'
|
||||
it "should handle a two words before a colon in the title" do
|
||||
SiteSetting.title = "Our Spaceballs: The Discourse"
|
||||
expect(user.user_second_factors.totps.first.totp_provisioning_uri).to eq(
|
||||
"otpauth://totp/Our%20Spaceballs%20The%20Discourse:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=Our%20Spaceballs%20The%20Discourse"
|
||||
"otpauth://totp/Our%20Spaceballs%20The%20Discourse:#{ERB::Util.url_encode(user.email)}?secret=#{user_second_factor_totp.data}&issuer=Our%20Spaceballs%20The%20Discourse",
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#authenticate_totp' do
|
||||
it 'should be able to authenticate a token' do
|
||||
describe "#authenticate_totp" do
|
||||
it "should be able to authenticate a token" do
|
||||
freeze_time do
|
||||
expect(user.user_second_factors.totps.first.last_used).to eq(nil)
|
||||
|
||||
@@ -72,52 +74,52 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when token is blank' do
|
||||
it 'should be false' do
|
||||
describe "when token is blank" do
|
||||
it "should be false" do
|
||||
expect(user.authenticate_totp(nil)).to eq(false)
|
||||
expect(user.user_second_factors.totps.first.last_used).to eq(nil)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when token is invalid' do
|
||||
it 'should be false' do
|
||||
expect(user.authenticate_totp('111111')).to eq(false)
|
||||
describe "when token is invalid" do
|
||||
it "should be false" do
|
||||
expect(user.authenticate_totp("111111")).to eq(false)
|
||||
expect(user.user_second_factors.totps.first.last_used).to eq(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#totp_enabled?' do
|
||||
describe 'when user does not have a second factor record' do
|
||||
it 'should return false' do
|
||||
describe "#totp_enabled?" do
|
||||
describe "when user does not have a second factor record" do
|
||||
it "should return false" do
|
||||
expect(another_user.totp_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user's second factor record is disabled" do
|
||||
it 'should return false' do
|
||||
it "should return false" do
|
||||
disable_totp
|
||||
expect(user.totp_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user's second factor record is enabled" do
|
||||
it 'should return true' do
|
||||
it "should return true" do
|
||||
expect(user.totp_enabled?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when SSO is enabled' do
|
||||
it 'should return false' do
|
||||
SiteSetting.discourse_connect_url = 'http://someurl.com'
|
||||
describe "when SSO is enabled" do
|
||||
it "should return false" do
|
||||
SiteSetting.discourse_connect_url = "http://someurl.com"
|
||||
SiteSetting.enable_discourse_connect = true
|
||||
|
||||
expect(user.totp_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when local login is disabled' do
|
||||
it 'should return false' do
|
||||
describe "when local login is disabled" do
|
||||
it "should return false" do
|
||||
SiteSetting.enable_local_logins = false
|
||||
|
||||
expect(user.totp_enabled?).to eq(false)
|
||||
@@ -166,9 +168,7 @@ RSpec.describe SecondFactorManager do
|
||||
let(:secure_session) { {} }
|
||||
|
||||
context "when neither security keys nor totp/backup codes are enabled" do
|
||||
before do
|
||||
disable_security_key && disable_totp
|
||||
end
|
||||
before { disable_security_key && disable_totp }
|
||||
it "returns OK, because it doesn't need to authenticate" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).ok).to eq(true)
|
||||
end
|
||||
@@ -186,13 +186,20 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
context "when security key params are valid" do
|
||||
let(:params) { { second_factor_token: valid_security_key_auth_post_data, second_factor_method: UserSecondFactor.methods[:security_key] } }
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: valid_security_key_auth_post_data,
|
||||
second_factor_method: UserSecondFactor.methods[:security_key],
|
||||
}
|
||||
end
|
||||
it "returns OK" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).ok).to eq(true)
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to security keys" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:security_key])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:security_key],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -200,12 +207,12 @@ RSpec.describe SecondFactorManager do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: {
|
||||
signature: 'bad',
|
||||
clientData: 'bad',
|
||||
authenticatorData: 'bad',
|
||||
credentialId: 'bad'
|
||||
signature: "bad",
|
||||
clientData: "bad",
|
||||
authenticatorData: "bad",
|
||||
credentialId: "bad",
|
||||
},
|
||||
second_factor_method: UserSecondFactor.methods[:security_key]
|
||||
second_factor_method: UserSecondFactor.methods[:security_key],
|
||||
}
|
||||
end
|
||||
it "returns not OK" do
|
||||
@@ -218,15 +225,13 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
context "when only totp is enabled" do
|
||||
before do
|
||||
disable_security_key
|
||||
end
|
||||
before { disable_security_key }
|
||||
|
||||
context "when totp is valid" do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: user.user_second_factors.totps.first.totp_object.now,
|
||||
second_factor_method: UserSecondFactor.methods[:totp]
|
||||
second_factor_method: UserSecondFactor.methods[:totp],
|
||||
}
|
||||
end
|
||||
it "returns OK" do
|
||||
@@ -234,16 +239,15 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to totp" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:totp])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:totp],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when totp is invalid" do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: "blah",
|
||||
second_factor_method: UserSecondFactor.methods[:totp]
|
||||
}
|
||||
{ second_factor_token: "blah", second_factor_method: UserSecondFactor.methods[:totp] }
|
||||
end
|
||||
it "returns not OK" do
|
||||
result = user.authenticate_second_factor(params, secure_session)
|
||||
@@ -277,26 +281,21 @@ RSpec.describe SecondFactorManager do
|
||||
let(:token) { user.user_second_factors.totps.first.totp_object.now }
|
||||
|
||||
context "when totp params are provided" do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: token,
|
||||
second_factor_method: method
|
||||
}
|
||||
end
|
||||
let(:params) { { second_factor_token: token, second_factor_method: method } }
|
||||
|
||||
it "validates totp OK" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).ok).to eq(true)
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to totp" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:totp])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:totp],
|
||||
)
|
||||
end
|
||||
|
||||
context "when the user does not have TOTP enabled" do
|
||||
let(:token) { 'test' }
|
||||
before do
|
||||
user.totps.destroy_all
|
||||
end
|
||||
let(:token) { "test" }
|
||||
before { user.totps.destroy_all }
|
||||
|
||||
it "returns an error" do
|
||||
result = user.authenticate_second_factor(params, secure_session)
|
||||
@@ -317,19 +316,21 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
context "when security key params are valid" do
|
||||
let(:params) { { second_factor_token: valid_security_key_auth_post_data, second_factor_method: method } }
|
||||
let(:params) do
|
||||
{ second_factor_token: valid_security_key_auth_post_data, second_factor_method: method }
|
||||
end
|
||||
it "returns OK" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).ok).to eq(true)
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to security keys" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:security_key])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:security_key],
|
||||
)
|
||||
end
|
||||
|
||||
context "when the user does not have security keys enabled" do
|
||||
before do
|
||||
user.security_keys.destroy_all
|
||||
end
|
||||
before { user.security_keys.destroy_all }
|
||||
|
||||
it "returns an error" do
|
||||
result = user.authenticate_second_factor(params, secure_session)
|
||||
@@ -347,10 +348,7 @@ RSpec.describe SecondFactorManager do
|
||||
|
||||
context "when backup code params are provided" do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: 'iAmValidBackupCode',
|
||||
second_factor_method: method
|
||||
}
|
||||
{ second_factor_token: "iAmValidBackupCode", second_factor_method: method }
|
||||
end
|
||||
|
||||
context "when backup codes enabled" do
|
||||
@@ -359,14 +357,14 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to backup codes" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:backup_codes])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:backup_codes],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
context "when backup codes disabled" do
|
||||
before do
|
||||
user.user_second_factors.backup_codes.destroy_all
|
||||
end
|
||||
before { user.user_second_factors.backup_codes.destroy_all }
|
||||
|
||||
it "returns an error" do
|
||||
result = user.authenticate_second_factor(params, secure_session)
|
||||
@@ -379,14 +377,21 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
context "when no totp params are provided" do
|
||||
let(:params) { { second_factor_token: valid_security_key_auth_post_data, second_factor_method: UserSecondFactor.methods[:security_key] } }
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: valid_security_key_auth_post_data,
|
||||
second_factor_method: UserSecondFactor.methods[:security_key],
|
||||
}
|
||||
end
|
||||
|
||||
it "validates the security key OK" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).ok).to eq(true)
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to security keys" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:security_key])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:security_key],
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -394,7 +399,7 @@ RSpec.describe SecondFactorManager do
|
||||
let(:params) do
|
||||
{
|
||||
second_factor_token: user.user_second_factors.totps.first.totp_object.now,
|
||||
second_factor_method: UserSecondFactor.methods[:totp]
|
||||
second_factor_method: UserSecondFactor.methods[:totp],
|
||||
}
|
||||
end
|
||||
|
||||
@@ -403,26 +408,30 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
|
||||
it "sets used_2fa_method to totp" do
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(UserSecondFactor.methods[:totp])
|
||||
expect(user.authenticate_second_factor(params, secure_session).used_2fa_method).to eq(
|
||||
UserSecondFactor.methods[:totp],
|
||||
)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe 'backup codes' do
|
||||
describe '#generate_backup_codes' do
|
||||
it 'should generate and store 10 backup codes' do
|
||||
describe "backup codes" do
|
||||
describe "#generate_backup_codes" do
|
||||
it "should generate and store 10 backup codes" do
|
||||
backup_codes = user.generate_backup_codes
|
||||
|
||||
expect(backup_codes.length).to be 10
|
||||
expect(user_backup.user_second_factors.backup_codes).to be_present
|
||||
expect(user_backup.user_second_factors.backup_codes.pluck(:method).uniq[0]).to eq(UserSecondFactor.methods[:backup_codes])
|
||||
expect(user_backup.user_second_factors.backup_codes.pluck(:method).uniq[0]).to eq(
|
||||
UserSecondFactor.methods[:backup_codes],
|
||||
)
|
||||
expect(user_backup.user_second_factors.backup_codes.pluck(:enabled).uniq[0]).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe '#create_backup_codes' do
|
||||
it 'should create 10 backup code records' do
|
||||
describe "#create_backup_codes" do
|
||||
it "should create 10 backup code records" do
|
||||
raw_codes = Array.new(10) { SecureRandom.hex(8) }
|
||||
backup_codes = another_user.create_backup_codes(raw_codes)
|
||||
|
||||
@@ -430,58 +439,58 @@ RSpec.describe SecondFactorManager do
|
||||
end
|
||||
end
|
||||
|
||||
describe '#authenticate_backup_code' do
|
||||
it 'should be able to authenticate a backup code' do
|
||||
describe "#authenticate_backup_code" do
|
||||
it "should be able to authenticate a backup code" do
|
||||
backup_code = "iAmValidBackupCode"
|
||||
|
||||
expect(user_backup.authenticate_backup_code(backup_code)).to eq(true)
|
||||
expect(user_backup.authenticate_backup_code(backup_code)).to eq(false)
|
||||
end
|
||||
|
||||
describe 'when code is blank' do
|
||||
it 'should be false' do
|
||||
describe "when code is blank" do
|
||||
it "should be false" do
|
||||
expect(user_backup.authenticate_backup_code(nil)).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when code is invalid' do
|
||||
it 'should be false' do
|
||||
describe "when code is invalid" do
|
||||
it "should be false" do
|
||||
expect(user_backup.authenticate_backup_code("notValidBackupCode")).to eq(false)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
describe '#backup_codes_enabled?' do
|
||||
describe 'when user does not have a second factor backup enabled' do
|
||||
it 'should return false' do
|
||||
describe "#backup_codes_enabled?" do
|
||||
describe "when user does not have a second factor backup enabled" do
|
||||
it "should return false" do
|
||||
expect(another_user.backup_codes_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user's second factor backup codes have been used" do
|
||||
it 'should return false' do
|
||||
it "should return false" do
|
||||
user_backup.user_second_factors.backup_codes.update_all(enabled: false)
|
||||
expect(user_backup.backup_codes_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe "when user's second factor code is available" do
|
||||
it 'should return true' do
|
||||
it "should return true" do
|
||||
expect(user_backup.backup_codes_enabled?).to eq(true)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when SSO is enabled' do
|
||||
it 'should return false' do
|
||||
SiteSetting.discourse_connect_url = 'http://someurl.com'
|
||||
describe "when SSO is enabled" do
|
||||
it "should return false" do
|
||||
SiteSetting.discourse_connect_url = "http://someurl.com"
|
||||
SiteSetting.enable_discourse_connect = true
|
||||
|
||||
expect(user_backup.backup_codes_enabled?).to eq(false)
|
||||
end
|
||||
end
|
||||
|
||||
describe 'when local login is disabled' do
|
||||
it 'should return false' do
|
||||
describe "when local login is disabled" do
|
||||
it "should return false" do
|
||||
SiteSetting.enable_local_logins = false
|
||||
|
||||
expect(user_backup.backup_codes_enabled?).to eq(false)
|
||||
|
||||
Reference in New Issue
Block a user