@@ -5,15 +5,27 @@ defmodule RemotePersistentTerm.Fetcher.S3Test do
55 setup :verify_on_exit!
66 import ExUnit.CaptureLog
77
8+ @ bucket "test-bucket"
9+ @ key "test-key"
10+ @ region "test-region"
11+ @ failover_regions [ "failover-region-1" , "failover-region-2" ]
12+ @ version "F76V.weh4uOlU15f7a2OLHPgCLXkDpm4"
13+
814 test "Unknown error returns an error for current_version/1" do
915 expect ( AwsClientMock , :request , fn _op , _opts ->
1016 { :error , :unknown_error }
1117 end )
1218
13- assert capture_log ( fn ->
14- assert { :error , "Unknown error" } = S3 . current_version ( % S3 { bucket: "bucket" } )
15- end ) =~
16- "Elixir.RemotePersistentTerm.Fetcher.S3 - unknown error: :unknown_error"
19+ log =
20+ capture_log ( fn ->
21+ assert { :error , "Unknown error" } =
22+ S3 . current_version ( % S3 { bucket: "bucket" , key: "key" } )
23+ end )
24+
25+ assert log =~ "bucket: \" bucket\" "
26+ assert log =~ "key: \" key\" "
27+ assert log =~ "reason: \" :unknown_error\" "
28+ assert log =~ "Failed to get current version of object - unknown reason"
1729 end
1830
1931 describe "init/1" do
@@ -26,4 +38,166 @@ defmodule RemotePersistentTerm.Fetcher.S3Test do
2638 S3 . init ( bucket: bucket , key: key , region: region )
2739 end
2840 end
41+
42+ describe "failover_regions" do
43+ test "current_identifiers/1 tries first failover region when primary region fails" do
44+ # Setup state with failover regions
45+ state = % S3 {
46+ bucket: @ bucket ,
47+ key: @ key ,
48+ region: @ region ,
49+ failover_regions: @ failover_regions
50+ }
51+
52+ # Mock the AWS client to fail for primary region but succeed for first failover region
53+ expect ( AwsClientMock , :request , 2 , fn _op , opts ->
54+ case opts do
55+ [ region: @ region ] ->
56+ { :error , "Primary region connection error" }
57+
58+ [ region: "failover-region-1" ] ->
59+ { :ok ,
60+ % {
61+ body: % {
62+ versions: [
63+ % { version_id: @ version , etag: "current-etag" , is_latest: "true" }
64+ ]
65+ }
66+ } }
67+ end
68+ end )
69+
70+ log =
71+ capture_log ( fn ->
72+ result = S3 . current_version ( state )
73+ assert { :ok , "current-etag" } = result
74+ end )
75+
76+ assert log =~ "bucket: \" #{ @ bucket } \" "
77+ assert log =~ "key: \" #{ @ key } \" "
78+ assert log =~ "region: \" #{ @ region } \" "
79+ assert log =~ "Failed to fetch from primary region, attempting failover regions"
80+ assert log =~ "region: \" failover-region-1\" "
81+ assert log =~ "Trying failover region"
82+ assert log =~ "Found latest version of object"
83+ end
84+
85+ test "download/1 tries first failover region when primary region fails" do
86+ state = % S3 {
87+ bucket: @ bucket ,
88+ key: @ key ,
89+ region: @ region ,
90+ failover_regions: @ failover_regions
91+ }
92+
93+ # Mock the AWS client to fail for primary region but succeed for first failover region
94+ expect ( AwsClientMock , :request , 2 , fn _op , opts ->
95+ case opts do
96+ [ region: @ region ] ->
97+ { :error , "Primary region connection error" }
98+
99+ [ region: "failover-region-1" ] ->
100+ { :ok , % { body: "content from failover region" } }
101+ end
102+ end )
103+
104+ log =
105+ capture_log ( fn ->
106+ result = S3 . download ( state )
107+ assert { :ok , "content from failover region" } = result
108+ end )
109+
110+ assert log =~ "bucket: \" #{ @ bucket } \" "
111+ assert log =~ "key: \" #{ @ key } \" "
112+ assert log =~ "Downloading object from S3"
113+ assert log =~ "region: \" #{ @ region } \" "
114+ assert log =~ "Failed to fetch from primary region, attempting failover regions"
115+ assert log =~ "region: \" failover-region-1\" "
116+ assert log =~ "Trying failover region"
117+ assert log =~ "Downloaded object from S3"
118+ end
119+
120+ test "returns error when primary and all failover regions fail" do
121+ state = % S3 {
122+ bucket: @ bucket ,
123+ key: @ key ,
124+ region: @ region ,
125+ failover_regions: @ failover_regions
126+ }
127+
128+ # Mock the AWS client to fail for all regions
129+ expect ( AwsClientMock , :request , 3 , fn _op , opts ->
130+ case opts do
131+ [ region: @ region ] ->
132+ { :error , "Primary region connection error" }
133+
134+ [ region: "failover-region-1" ] ->
135+ { :error , "First failover region connection error" }
136+
137+ [ region: "failover-region-2" ] ->
138+ { :error , "Second failover region connection error" }
139+ end
140+ end )
141+
142+ log =
143+ capture_log ( fn ->
144+ result = S3 . download ( state )
145+ assert { :error , message } = result
146+ assert message =~ "All regions failed"
147+ end )
148+
149+ assert log =~ "bucket: \" #{ @ bucket } \" "
150+ assert log =~ "key: \" #{ @ key } \" "
151+ assert log =~ "Downloading object from S3"
152+ assert log =~ "region: \" #{ @ region } \" "
153+ assert log =~ "Failed to fetch from primary region, attempting failover regions"
154+ assert log =~ "region: \" failover-region-1\" "
155+ assert log =~ "Trying failover region"
156+ assert log =~ "reason: \" \\ \" First failover region connection error\\ \" \" "
157+ assert log =~ "Failed to fetch from failover region"
158+ assert log =~ "region: \" failover-region-2\" "
159+ assert log =~ "reason: \" \\ \" Second failover region connection error\\ \" \" "
160+ end
161+
162+ test "tries second failover region when first failover region fails" do
163+ state = % S3 {
164+ bucket: @ bucket ,
165+ key: @ key ,
166+ region: @ region ,
167+ failover_regions: @ failover_regions
168+ }
169+
170+ # Mock the AWS client to fail for primary and first failover region but succeed for second failover region
171+ expect ( AwsClientMock , :request , 3 , fn _op , opts ->
172+ case opts do
173+ [ region: @ region ] ->
174+ { :error , "Primary region connection error" }
175+
176+ [ region: "failover-region-1" ] ->
177+ { :error , "First failover region connection error" }
178+
179+ [ region: "failover-region-2" ] ->
180+ { :ok , % { body: "content from second failover region" } }
181+ end
182+ end )
183+
184+ log =
185+ capture_log ( fn ->
186+ result = S3 . download ( state )
187+ assert { :ok , "content from second failover region" } = result
188+ end )
189+
190+ assert log =~ "bucket: \" #{ @ bucket } \" "
191+ assert log =~ "key: \" #{ @ key } \" "
192+ assert log =~ "Downloading object from S3"
193+ assert log =~ "region: \" #{ @ region } \" "
194+ assert log =~ "Failed to fetch from primary region, attempting failover regions"
195+ assert log =~ "region: \" failover-region-1\" "
196+ assert log =~ "Trying failover region"
197+ assert log =~ "reason: \" \\ \" First failover region connection error\\ \" \" "
198+ assert log =~ "Failed to fetch from failover region"
199+ assert log =~ "region: \" failover-region-2\" "
200+ assert log =~ "Downloaded object from S3"
201+ end
202+ end
29203end
0 commit comments