aboutsummaryrefslogtreecommitdiffstats
path: root/activerecord/test/cases/database_selector_test.rb
blob: 6142e223ce7bd4631b57f8d77d2e71fcb70b979a (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
# frozen_string_literal: true

require "cases/helper"
require "models/person"
require "action_dispatch"

module ActiveRecord
  class DatabaseSelectorTest < ActiveRecord::TestCase
    setup do
      @session_store = {}
      @session = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session.new(@session_store)
    end

    def test_empty_session
      assert_equal Time.at(0), @session.last_write_timestamp
    end

    def test_writing_the_session_timestamps
      assert @session.update_last_write_timestamp

      session2 = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session.new(@session_store)
      assert_equal @session.last_write_timestamp, session2.last_write_timestamp
    end

    def test_writing_session_time_changes
      assert @session.update_last_write_timestamp

      before = @session.last_write_timestamp
      sleep(0.1)

      assert @session.update_last_write_timestamp
      assert_not_equal before, @session.last_write_timestamp
    end

    def test_read_from_replicas
      @session_store[:last_write] = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session.convert_time_to_timestamp(Time.now - 5.seconds)

      resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver.new(@session)

      called = false
      resolver.read do
        called = true
        assert ActiveRecord::Base.connected_to?(role: :reading)
      end
      assert called
    end

    def test_read_from_primary
      @session_store[:last_write] = ActiveRecord::Middleware::DatabaseSelector::Resolver::Session.convert_time_to_timestamp(Time.now)

      resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver.new(@session)

      called = false
      resolver.read do
        called = true
        assert ActiveRecord::Base.connected_to?(role: :writing)
      end
      assert called
    end

    def test_write_to_primary
      resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver.new(@session)

      # Session should start empty
      assert_nil @session_store[:last_write]

      called = false
      resolver.write do
        assert ActiveRecord::Base.connected_to?(role: :writing)
        called = true
      end
      assert called

      # and be populated by the last write time
      assert @session_store[:last_write]
    end

    def test_write_to_primary_with_exception
      resolver = ActiveRecord::Middleware::DatabaseSelector::Resolver.new(@session)

      # Session should start empty
      assert_nil @session_store[:last_write]

      called = false
      assert_raises(ActiveRecord::RecordNotFound) do
        resolver.write do
          assert ActiveRecord::Base.connected_to?(role: :writing)
          called = true
          raise ActiveRecord::RecordNotFound
        end
      end
      assert called

      # and be populated by the last write time
      assert @session_store[:last_write]
    end

    def test_the_middleware_chooses_writing_role_with_POST_request
      middleware = ActiveRecord::Middleware::DatabaseSelector.new(lambda { |env|
        assert ActiveRecord::Base.connected_to?(role: :writing)
        [200, {}, ["body"]]
      })
      assert_equal [200, {}, ["body"]], middleware.call("REQUEST_METHOD" => "POST")
    end

    def test_the_middleware_chooses_reading_role_with_GET_request
      middleware = ActiveRecord::Middleware::DatabaseSelector.new(lambda { |env|
        assert ActiveRecord::Base.connected_to?(role: :reading)
        [200, {}, ["body"]]
      })
      assert_equal [200, {}, ["body"]], middleware.call("REQUEST_METHOD" => "GET")
    end
  end
end