Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Split spec/integration_spec.rb #350

Merged
merged 38 commits into from
Aug 7, 2024

Conversation

ellnix
Copy link
Collaborator

@ellnix ellnix commented Feb 29, 2024

Continues after #345: Please only look at commits after "Move Post specs"
More changes toward resolving #332

Fixes #358

This test seems to just use Marshal.dump on an object and then
Marshal.load it later, which would pass for any ruby object.
This test seems to test that an object that is cached can be fetched
back from the cache. As proof, the meilisearch method calls can be
removed and the test passes just fine:

```ruby
context 'with Rails caching' do
  let(:memory_store) { ActiveSupport::Cache.lookup_store(:memory_store) }
  let(:search_query) { '*' }
  let(:cache_key) { "book_search:#{search_query}" }

  before do
    allow(Rails).to receive(:cache).and_return(memory_store)
    Rails.cache.clear
  end

  fit 'caches the search results' do
    # Ensure the cache is empty before the test
    expect(Rails.cache.read(cache_key)).to be_nil

    # Perform the search and cache the results
    Rails.cache.fetch(cache_key) do
      search_query
    end

    # Check if the search result is cached
    expect(Rails.cache.read(cache_key)).to eq(search_query)
  end
end
```
It does not seem like Mongoid::Document has bang methods, so this is
spec is not reproducing a likely naming conflict. In either case, the
plan is to test with real MongoDB models so this test would be removed
eventually.
'is_synchronous' tests a private method and only tests that the
configuration was applied
'has maxValuesPerFacet set' tests meilisearch-ruby's Index class
Copy link

codecov bot commented Feb 29, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 88.90%. Comparing base (40a6abb) to head (487c780).
Report is 45 commits behind head on main.

Additional details and impacted files
@@            Coverage Diff             @@
##             main     #350      +/-   ##
==========================================
- Coverage   89.29%   88.90%   -0.40%     
==========================================
  Files          13       13              
  Lines         757      757              
==========================================
- Hits          676      673       -3     
- Misses         81       84       +3     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@@ -158,10 +158,6 @@
expect(Color.search('').size).to eq(1)
end

it 'has a Rails env-based index name' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to configuration_spec.rb, seemed more appropriate.

Book.index(safe_index_uid('Book')).delete_all_documents
end

it 'returns array of tasks on #ms_index!' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to instance_methods_spec.rb since it concerns the interface (return type) of one of the instance methods we add to models.

)
end

it 'indexes the book in 2 indexes of 3' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb since it tests whether or not the :if option is behaving correctly.

expect(results['hits'].length).to eq(0)
end

it 'sanitizes attributes' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb since it tests whether or not the :sanitize option is behaving correctly.

expect(b['hits'][0]['author']).to eq('alert(1)')
expect(b['hits'][0]['_formatted']['name']).to eq('"> <em>hack</em>0r')
rescue StandardError
# rails 4.2's sanitizer
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Kept only the last sanitization format.

expect(index.uid).to eq("#{safe_index_uid('Book')}_#{Rails.env}")
end

it 'searches with one typo min size' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to settings_spec.rb since it tests the typo_tolerance setting

expect(results.size).to eq(1)
end

describe '#ms_entries' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to instance_methods_spec.rb

end
end

it 'returns facets using max values per facet' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to settings_spec.rb

expect(results.facets_distribution['genre'].size).to eq(3)
end

it 'does not error on facet_search' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to new safe_index_spec.rb since this is a test on whether SafeIndex forwards method arguments correctly

@@ -32,3 +32,11 @@ def public?
released && !premium
end
end

module TestUtil
def self.reset_books!
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved the index and database resetting logic to a method. Since usage of Book is scattered we can no longer use a before hook for this.

Color.delete_all
end

it 'auto indexes' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Already tested in options_spec.rb under :auto_index

end


it 'is able to temporarily disable auto-indexing' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to model_methods_spec.rb

expect(Color.search('blue').size).to eq(1)
end

it 'updates the index if the attribute changed' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to record_is_updated_spec.rb

expect(Color.search('pink').size).to eq(1)
end

it 'uses the specified scope' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to model_methods_spec.rb

expect(Color.search('').size).to eq(1)
end

it 'indexes an array of documents' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to model_methods_spec.rb

expect(json['hits'].count).to eq(Color.raw_search('')['hits'].count)
end

it 'does not index non-saved document' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to instance_method_specs.rb

@@ -35,3 +35,10 @@ def will_save_change_to_short_name?
false
end
end

module TestUtil
def self.reset_colors!
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Same rationale as reset_books!

@@ -631,41 +631,6 @@
end
end

describe 'Animals' do
it 'returns only the requested type' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb under (shared index)

expect(Dog.search('Toby').first.name).to eq('Toby the Dog')
end

it 'shares a single index' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb

expect(cat_index).to eq(dog_index)
end

describe '#ms_entries' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to instance_methods_spec.rb


after(:all) { MeiliSearch::Rails.configuration[:per_environment] = true }

it 'adds custom complex attribute' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to settings_spec.rb

expect(result['hits'][0]['full_name']).to eq('Jane Doe')
end

it 'has as uid the custom name specified' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb

expect(People.index.uid).to eq(safe_index_uid('MyCustomPeople'))
end

it 'has the chosen field as custom primary key' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb

expect(index.primary_key).to eq('card_number')
end

it 'does not call the API if there has been no attribute change' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to record_is_updated_spec.rb

end.not_to change(People.index.tasks['results'], :size)
end

it 'does not auto-remove' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to options_spec.rb

expect(result['hits'].size).to eq(1)
end

it 'is able to remove manually' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to instance_methods_spec.rb

expect(result['hits'].size).to eq(0)
end

it 'clears index manually' do
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Moved to model_methods_spec.rb

Should look into adding pagy specs in the future, along with
meilisearch#362
This is mainly focused around removing interdependencies between tests
and ensuring that there are no race conditions.
Copy link
Collaborator Author

@ellnix ellnix May 25, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Forgot to mention in the commit, but is me adding another layer of tests (system tests).

We would have

  • Unit tests
  • Integration tests (checking that systems fit together given simple scenarios)
  • System tests (do common tasks with a setup of realistic data)
  • Acceptance tests (reserved for full-stack tests, i. e. running a rails app and testing it with selenium verify with 100% certainty that a small subset of setups that we lay out work. Could also be helpful in letting us see what needs to be updated on a user's end when we make changes)

require 'support/models/product'

describe 'Tech shop' do
before(:all) do
Product.clear_index!(true)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Funnily enough, this never worked! Product has indexing disabled and in cases where indexing is disabled clear_index does nothing.

However, this did not present an issue since this one describe block was the only thing using product. When this runs after the recently-added multi search specs where I also used product, many of the expectations fail 🤣

I found out the hard way as you can imagine.

@@ -37,150 +39,142 @@
# Subproducts
@camera = Camera.create!(name: 'canon eos rebel t3', href: 'canon')

100.times { Product.create!(name: 'crapoola', href: 'crappy', tags: ['crappy']) }
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This alone removed over half a second from the test runtime for me. These 100 "crapoola"s are actually used in the specs.

@@ -37,150 +39,142 @@
# Subproducts
@camera = Camera.create!(name: 'canon eos rebel t3', href: 'canon')

100.times { Product.create!(name: 'crapoola', href: 'crappy', tags: ['crappy']) }

@products_in_database = Product.all
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should probably save on memory, but the biggest difference it'll probably make is removing a line of code that we never needed.


products_after_clear = Product.raw_search('')['hits']
expect(products_after_clear).to be_empty
Product.reindex!(MeiliSearch::Rails::IndexSettings::DEFAULT_BATCH_SIZE, true)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This syntax is still clunky but I'm saving it for when I refactor the actual lib, not the test suite.

Comment on lines 116 to 124
ipad.destroy
results = Product.search('ipad')
expect(results.size).to eq(0)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Fun fact: this actually tested nothing.

As one of the later tests asserts, if there is a document in the ms index that cannot be found in AR, it won't be returned by search (although it is returned by raw_search).

This is why this never caused any errors despite the obvious-looking race condition between this assertion and the above ipad.destroy line.

Product.index.add_documents!(@palmpre.attributes.merge(id: -1))
expect(JSON.parse(Product.search('pal').to_json).size).to eq(2)
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I do not understand why this was being converted to json and back. If there's some edge case or special significance to this please let me know.

ellnix added 17 commits May 26, 2024 09:31
It looks to me like this method simply tested that we define a `#search`
method on models, but if we didn't define that method most of the test
suite would fail.

If these was a different purpose to this test I don't see it.
- Searchable attribute warning only happened on the top level block,
  with this fix it will work on additional indexes (added with
  `add_index`)
  - This involved moving the warning method to IndexSettings which has
    the side effect of having no access to the model name, however the
    attribute name alone *should* be enough for a user to figure out the
    error
- The searchable attribute spec created a new class which due to
  ActiveModel naming and our interdependence on it cannot conveniently
  be isolated from other tests
The specs should now be more resilient by using regular expressions
instead of index names.
New test has been added while PR meilisearch#350 was being finished.
- Specs are all moved to their own files!
- The remaining tests were unit tests on the
  `meilisearch_settings_changed?` method which should be tested but not
  this way. Postponing until the logic has been refactored out of the
  MeiliSearch::Rails module.
- Do not require every ActiveRecord table in every test
  - Some require statements that were missing were added in this commit
This should mean less noise in the test, and if we follow this example
going foward when adding Sequel and Mongoid models the test output
should be relevant only to the tests being run.
@ellnix ellnix mentioned this pull request May 27, 2024
@ellnix ellnix marked this pull request as ready for review May 27, 2024 18:30
@ellnix ellnix requested a review from brunoocasali May 27, 2024 18:34
@ellnix
Copy link
Collaborator Author

ellnix commented May 27, 2024

@brunoocasali I tried to keep the commits as small as possible, and annotated a lot of the earlier ones. I would recommend going through this commit by commit rather than through Files changed.

Copy link
Member

@brunoocasali brunoocasali left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LGTM!

bors merge

@brunoocasali brunoocasali merged commit 5b57c6b into meilisearch:main Aug 7, 2024
10 of 11 checks passed
@curquiza curquiza added the maintenance Anything related to maintenance (CI, tests, refactoring...) label Sep 24, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
maintenance Anything related to maintenance (CI, tests, refactoring...)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Race condition in proximity precision test
3 participants