<NME> journal_spec.rb
<BEF> require 'spec_helper'

describe Chewy::Journal do
  context 'journaling', :orm do
    ['', 'namespace/'].each do |namespace|
      context namespace.present? ? 'with namespace' : 'without namespace' do
        before do
          stub_model(:city) do
            update_index "#{namespace}cities", :self
          end
          stub_model(:country) do
            update_index "#{namespace}countries", :self
          end

          stub_index("#{namespace}cities") do
            index_scope City
            default_import_options journal: true
          end
          stub_index("#{namespace}countries") do
            index_scope Country
            default_import_options journal: true
          end

          Chewy.massacre
          Chewy.settings[:prefix] = 'some_prefix'
          Timecop.freeze(time)
        end

        after do
          Chewy.settings[:prefix] = nil
          Timecop.return
        end

        let(:time) { Time.now }
        let(:import_time) { time + 1 }
        let(:update_time) { time + 2 }
        let(:destroy_time) { time + 3 }

        def timestamp(time)
          time.to_i
        end

        specify do
          cities_index = namespace.present? ? Namespace::CitiesIndex : CitiesIndex
          countries_index = namespace.present? ? Namespace::CountriesIndex : CountriesIndex
          Chewy.strategy(:urgent) do
            cities = Array.new(2) { |i| City.create!(id: i + 1) }
            countries = Array.new(2) { |i| Country.create!(id: i + 1) }
            Country.create!(id: 3)

            Timecop.freeze(import_time)

            cities_index.import
            countries_index.import

            expect(Chewy::Stash::Journal.exists?).to eq true

            Timecop.freeze(update_time)
            cities.first.update!(name: 'Supername')

            Timecop.freeze(destroy_time)
            countries.last.destroy

            journal_entries = Chewy::Stash::Journal.order(:created_at).hits.map { |r| r['_source'] }
            expected_journal = [
              {
                'index_name' => "#{namespace}cities",
                'action' => 'index',
                'references' => ['1'].map(&Base64.method(:encode64)),
                'created_at' => time.utc.as_json
              },
              {
                'index_name' => "#{namespace}cities",
                'action' => 'index',
                'references' => ['2'].map(&Base64.method(:encode64)),
                'created_at' => time.utc.as_json
              },
              {
                'index_name' => "#{namespace}countries",
                'action' => 'index',
                'references' => ['1'].map(&Base64.method(:encode64)),
                'created_at' => time.utc.as_json
              },
              {
                'index_name' => "#{namespace}countries",
                'action' => 'index',
                'references' => ['2'].map(&Base64.method(:encode64)),
                'created_at' => time.utc.as_json
              },
              {
                'index_name' => "#{namespace}countries",
                'action' => 'index',
                'references' => ['3'].map(&Base64.method(:encode64)),
                'created_at' => time.utc.as_json
              },
              {
                'index_name' => "#{namespace}cities",
                'action' => 'index',
                'references' => %w[1 2].map(&Base64.method(:encode64)),
                'created_at' => import_time.utc.as_json
              },
              {
                'index_name' => "#{namespace}countries",
                'action' => 'index',
                'references' => %w[1 2 3].map(&Base64.method(:encode64)),
                'created_at' => import_time.utc.as_json
              },
              {
                'index_name' => "#{namespace}cities",
                'action' => 'index',
                'references' => ['1'].map(&Base64.method(:encode64)),
                'created_at' => update_time.utc.as_json
              },
              {
                'index_name' => "#{namespace}countries",
                'action' => 'delete',
                'references' => ['2'].map(&Base64.method(:encode64)),
                'created_at' => destroy_time.utc.as_json
              }
            ]

            expect(Chewy::Stash::Journal.count).to eq 9
            expect(journal_entries).to eq expected_journal

            journal_entries = Chewy::Stash::Journal.entries(import_time - 1)
            expect(journal_entries.size).to eq 4

            # simulate lost data
            Chewy.client.delete(index: "#{Chewy.settings[:prefix]}_cities", id: 1, refresh: true)
            expect(cities_index.count).to eq 1

            described_class.new.apply(time)
            expect(cities_index.count).to eq 2

            expect(Chewy.client.count(index: Chewy::Journal.index_name)['count']).to eq 9
            expect(journal_records).to eq expected_journal

            journal_entries = Chewy::Journal.entries_from(import_time)
            expect(journal_entries.length).to eq 4
            # we have only 2 types, so we can group all journal entries(4) into 2
            expect(Chewy::Journal.group(journal_entries)).to eq [
              Chewy::Journal::Entry.new('index_name' => "#{namespace}places",
                                        'type_name' => 'city',
                                        'action' => nil,
  end

  context do
    before { Chewy.massacre }
    before do
      stub_model(:city) do
        update_index 'cities', :self
      end
      stub_model(:country) do
        update_index 'countries', :self
            Chewy.client.delete(index: "#{Chewy.settings[:prefix]}_places", type: 'city', id: 1, refresh: true)
            expect(places_index::City.all.to_a.length).to eq 1

            Chewy::Journal.apply_changes_from(time)
            expect(places_index::City.all.to_a.length).to eq 2

            expect(Chewy::Journal.clean_until(import_time)).to eq 7
            expect(Chewy.client.count(index: Chewy::Journal.index_name)['count']).to eq 2

            expect(Chewy::Journal.delete!).to be_truthy
    end

    describe '#apply' do
      specify { expect(described_class.new(CitiesIndex).apply(2.minutes.ago)).to eq(0) }
        end
      end
    end

    context '.apply_changes_from with an index filter' do
      let(:time) { Time.now }

      before do
        stub_model(:city) do
          update_index 'city', :self
        end
        stub_model(:country) do
          update_index 'country', :self
        end

        stub_index('city') do
          define_type City do
            default_import_options journal: true
          end
        end
        stub_index('country') do
          define_type Country do
            default_import_options journal: true
          end
        end

        Chewy.massacre
        Timecop.freeze(time)
      end

      specify do
        Chewy.strategy(:urgent) do
          Array.new(2) { |i| City.create!(id: i + 1) }
          Array.new(2) { |i| Country.create!(id: i + 1) }
          expect(CityIndex.all.to_a.length).to eq 2
          expect(CountryIndex.all.to_a.length).to eq 2

          # simulate lost data
          Chewy.client.delete(index: 'city', type: 'city', id: 1, refresh: true)
          Chewy.client.delete(index: 'country', type: 'country', id: 1, refresh: true)
          expect(CityIndex.all.to_a.length).to eq 1
          expect(CountryIndex.all.to_a.length).to eq 1

          # Replay on specific index
          Chewy::Journal.apply_changes_from(time, only: [CityIndex])
          expect(CityIndex.all.to_a.length).to eq 2
          expect(CountryIndex.all.to_a.length).to eq 1

          # Replay on both
          Chewy.client.delete(index: 'city', type: 'city', id: 1, refresh: true)
          expect(CityIndex.all.to_a.length).to eq 1
          Chewy::Journal.apply_changes_from(time, only: [CityIndex, CountryIndex])
          expect(CityIndex.all.to_a.length).to eq 2
          expect(CountryIndex.all.to_a.length).to eq 2
        end
      end
    end
  end
end
        after { Timecop.return }

        specify do
          Chewy.strategy(:urgent) do
            Array.new(2) { |i| City.create!(id: i + 1) }
            Array.new(2) { |i| Country.create!(id: i + 1) }

            # simulate lost data
            Chewy.client.delete(index: 'cities', id: 1, refresh: true)
            Chewy.client.delete(index: 'countries', id: 1, refresh: true)
            expect(CitiesIndex.all.to_a.length).to eq 1
            expect(CountriesIndex.all.to_a.length).to eq 1

            # Replay on specific index
            expect(described_class.new(CitiesIndex).apply(time)).to eq(2)
            expect(CitiesIndex.all.to_a.length).to eq 2
            expect(CountriesIndex.all.to_a.length).to eq 1

            # Replay on both
            Chewy.client.delete(index: 'cities', id: 1, refresh: true)
            expect(CitiesIndex.all.to_a.length).to eq 1
            expect(described_class.new(CitiesIndex, CountriesIndex).apply(time)).to eq(4)
            expect(CitiesIndex.all.to_a.length).to eq 2
            expect(CountriesIndex.all.to_a.length).to eq 2
          end
        end
      end

      context 'when order is not preserved' do
        let(:time) { Time.now }

        it 'paginates properly through all items' do
          Chewy.strategy(:urgent) do
            Timecop.travel(time + 1.minute) { City.create!(id: 2) }
            Timecop.travel(time + 3.minute) { City.create!(id: 4) }
            Timecop.travel(time + 2.minute) { City.create!(id: 1) }
            Timecop.travel(time + 4.minute) { City.create!(id: 3) }
          end

          CitiesIndex.purge!
          expect(CitiesIndex.all.to_a.length).to eq 0

          # Replay on specific index
          expect(described_class.new(CitiesIndex).apply(time, fetch_limit: 2)).to eq(4)
          expect(CitiesIndex.all.to_a.map(&:id).sort).to eq([1, 2, 3, 4])
        end
      end
    end
  end
end

<MSG> Merge pull request #463 from sergey-kintsel/ensure_journal_is_empty

Ensure journal is empty
<DFF> @@ -135,10 +135,10 @@ describe Chewy::Journal do
             expect(Chewy.client.count(index: Chewy::Journal.index_name)['count']).to eq 9
             expect(journal_records).to eq expected_journal
 
-            journal_entries = Chewy::Journal.entries_from(import_time)
+            journal_entries = Chewy::Journal::Entry.since(import_time)
             expect(journal_entries.length).to eq 4
             # we have only 2 types, so we can group all journal entries(4) into 2
-            expect(Chewy::Journal.group(journal_entries)).to eq [
+            expect(Chewy::Journal::Entry.group(journal_entries)).to eq [
               Chewy::Journal::Entry.new('index_name' => "#{namespace}places",
                                         'type_name' => 'city',
                                         'action' => nil,
@@ -155,10 +155,10 @@ describe Chewy::Journal do
             Chewy.client.delete(index: "#{Chewy.settings[:prefix]}_places", type: 'city', id: 1, refresh: true)
             expect(places_index::City.all.to_a.length).to eq 1
 
-            Chewy::Journal.apply_changes_from(time)
+            Chewy::Journal::Apply.since(time)
             expect(places_index::City.all.to_a.length).to eq 2
 
-            expect(Chewy::Journal.clean_until(import_time)).to eq 7
+            expect(Chewy::Journal::Clean.until(import_time)).to eq 7
             expect(Chewy.client.count(index: Chewy::Journal.index_name)['count']).to eq 2
 
             expect(Chewy::Journal.delete!).to be_truthy
@@ -169,59 +169,5 @@ describe Chewy::Journal do
         end
       end
     end
-
-    context '.apply_changes_from with an index filter' do
-      let(:time) { Time.now }
-
-      before do
-        stub_model(:city) do
-          update_index 'city', :self
-        end
-        stub_model(:country) do
-          update_index 'country', :self
-        end
-
-        stub_index('city') do
-          define_type City do
-            default_import_options journal: true
-          end
-        end
-        stub_index('country') do
-          define_type Country do
-            default_import_options journal: true
-          end
-        end
-
-        Chewy.massacre
-        Timecop.freeze(time)
-      end
-
-      specify do
-        Chewy.strategy(:urgent) do
-          Array.new(2) { |i| City.create!(id: i + 1) }
-          Array.new(2) { |i| Country.create!(id: i + 1) }
-          expect(CityIndex.all.to_a.length).to eq 2
-          expect(CountryIndex.all.to_a.length).to eq 2
-
-          # simulate lost data
-          Chewy.client.delete(index: 'city', type: 'city', id: 1, refresh: true)
-          Chewy.client.delete(index: 'country', type: 'country', id: 1, refresh: true)
-          expect(CityIndex.all.to_a.length).to eq 1
-          expect(CountryIndex.all.to_a.length).to eq 1
-
-          # Replay on specific index
-          Chewy::Journal.apply_changes_from(time, only: [CityIndex])
-          expect(CityIndex.all.to_a.length).to eq 2
-          expect(CountryIndex.all.to_a.length).to eq 1
-
-          # Replay on both
-          Chewy.client.delete(index: 'city', type: 'city', id: 1, refresh: true)
-          expect(CityIndex.all.to_a.length).to eq 1
-          Chewy::Journal.apply_changes_from(time, only: [CityIndex, CountryIndex])
-          expect(CityIndex.all.to_a.length).to eq 2
-          expect(CountryIndex.all.to_a.length).to eq 2
-        end
-      end
-    end
   end
 end

{'addition_count': 4, 'commit_subject': 'Merge pull request #463 from sergey-kintsel/ensure_journal_is_empty', 'deletion_count': 58, 'file_extension': '.rb', 'lang': 'rb', 'license': 'mit', 'repo_name': 'toptal/chewy'}