gandi_v5 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (108) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +24 -0
  3. data/.rspec +3 -0
  4. data/.rubocop.yml +20 -0
  5. data/.travis.yml +23 -0
  6. data/CHANGELOG.md +3 -0
  7. data/Gemfile +6 -0
  8. data/Guardfile +40 -0
  9. data/LICENSE.md +32 -0
  10. data/README.md +94 -0
  11. data/Rakefile +3 -0
  12. data/TODO.md +29 -0
  13. data/bin/console +13 -0
  14. data/gandi_v5.gemspec +41 -0
  15. data/lib/gandi_v5/billing/info/prepaid.rb +33 -0
  16. data/lib/gandi_v5/billing/info.rb +26 -0
  17. data/lib/gandi_v5/billing.rb +28 -0
  18. data/lib/gandi_v5/data/converter/array_of.rb +35 -0
  19. data/lib/gandi_v5/data/converter/symbol.rb +26 -0
  20. data/lib/gandi_v5/data/converter/time.rb +28 -0
  21. data/lib/gandi_v5/data/converter.rb +41 -0
  22. data/lib/gandi_v5/data.rb +244 -0
  23. data/lib/gandi_v5/domain/auto_renew.rb +64 -0
  24. data/lib/gandi_v5/domain/contact.rb +102 -0
  25. data/lib/gandi_v5/domain/contract.rb +22 -0
  26. data/lib/gandi_v5/domain/dates.rb +44 -0
  27. data/lib/gandi_v5/domain/renewal_information.rb +41 -0
  28. data/lib/gandi_v5/domain/restore_information.rb +18 -0
  29. data/lib/gandi_v5/domain/sharing_space.rb +21 -0
  30. data/lib/gandi_v5/domain.rb +431 -0
  31. data/lib/gandi_v5/email/mailbox/responder.rb +36 -0
  32. data/lib/gandi_v5/email/mailbox.rb +236 -0
  33. data/lib/gandi_v5/email/offer.rb +27 -0
  34. data/lib/gandi_v5/email/slot.rb +134 -0
  35. data/lib/gandi_v5/email.rb +11 -0
  36. data/lib/gandi_v5/error/gandi_error.rb +21 -0
  37. data/lib/gandi_v5/error.rb +9 -0
  38. data/lib/gandi_v5/live_dns/domain.rb +211 -0
  39. data/lib/gandi_v5/live_dns/record_set.rb +79 -0
  40. data/lib/gandi_v5/live_dns/zone/snapshot.rb +62 -0
  41. data/lib/gandi_v5/live_dns/zone.rb +301 -0
  42. data/lib/gandi_v5/live_dns.rb +30 -0
  43. data/lib/gandi_v5/organization.rb +66 -0
  44. data/lib/gandi_v5/version.rb +5 -0
  45. data/lib/gandi_v5.rb +178 -0
  46. data/spec/.rubocop.yml +4 -0
  47. data/spec/features/domain_spec.rb +45 -0
  48. data/spec/features/livedns_domain_spec.rb +8 -0
  49. data/spec/features/livedns_zone_spec.rb +45 -0
  50. data/spec/features/mailbox_spec.rb +18 -0
  51. data/spec/fixtures/bodies/GandiV5_Billing/info.yaml +10 -0
  52. data/spec/fixtures/bodies/GandiV5_Domain/availability.yaml +15 -0
  53. data/spec/fixtures/bodies/GandiV5_Domain/fetch_contacts.yaml +8 -0
  54. data/spec/fixtures/bodies/GandiV5_Domain/get.yaml +37 -0
  55. data/spec/fixtures/bodies/GandiV5_Domain/list.yaml +20 -0
  56. data/spec/fixtures/bodies/GandiV5_Domain/renewal_info.yaml +12 -0
  57. data/spec/fixtures/bodies/GandiV5_Domain/restore_info.yaml +5 -0
  58. data/spec/fixtures/bodies/GandiV5_Domain/tld.yaml +10 -0
  59. data/spec/fixtures/bodies/GandiV5_Domain/tlds.yaml +7 -0
  60. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/get.yaml +16 -0
  61. data/spec/fixtures/bodies/GandiV5_Email_Mailbox/list.yaml +8 -0
  62. data/spec/fixtures/bodies/GandiV5_Email_Slot/get.yaml +10 -0
  63. data/spec/fixtures/bodies/GandiV5_Email_Slot/list.yaml +8 -0
  64. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/get.yaml +4 -0
  65. data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list.yaml +2 -0
  66. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/get.yaml +11 -0
  67. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yaml +11 -0
  68. data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/get.yaml +9 -0
  69. data/spec/fixtures/bodies/GandiV5_Organization/get.yaml +17 -0
  70. data/spec/fixtures/vcr/Domain_features/List_domains.yml +54 -0
  71. data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +133 -0
  72. data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +32 -0
  73. data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +42 -0
  74. data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +72 -0
  75. data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +28 -0
  76. data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +39 -0
  77. data/spec/spec_helper.rb +60 -0
  78. data/spec/test.env +1 -0
  79. data/spec/units/gandi_v5/billing/info/prepaid_spec.rb +20 -0
  80. data/spec/units/gandi_v5/billing/info_spec.rb +4 -0
  81. data/spec/units/gandi_v5/billing_spec.rb +41 -0
  82. data/spec/units/gandi_v5/data/converter/array_of_spec.rb +18 -0
  83. data/spec/units/gandi_v5/data/converter/symbol_spec.rb +16 -0
  84. data/spec/units/gandi_v5/data/converter/time_spec.rb +16 -0
  85. data/spec/units/gandi_v5/data/converter_spec.rb +31 -0
  86. data/spec/units/gandi_v5/data_spec.rb +340 -0
  87. data/spec/units/gandi_v5/domain/auto_renew_spec.rb +70 -0
  88. data/spec/units/gandi_v5/domain/contact_spec.rb +36 -0
  89. data/spec/units/gandi_v5/domain/contract_spec.rb +4 -0
  90. data/spec/units/gandi_v5/domain/dates_spec.rb +4 -0
  91. data/spec/units/gandi_v5/domain/renewal_information_spec.rb +81 -0
  92. data/spec/units/gandi_v5/domain/restore_information_spec.rb +4 -0
  93. data/spec/units/gandi_v5/domain/sharing_space_spec.rb +4 -0
  94. data/spec/units/gandi_v5/domain_spec.rb +451 -0
  95. data/spec/units/gandi_v5/email/mailbox/responder_spec.rb +131 -0
  96. data/spec/units/gandi_v5/email/mailbox_spec.rb +384 -0
  97. data/spec/units/gandi_v5/email/offer_spec.rb +17 -0
  98. data/spec/units/gandi_v5/email/slot_spec.rb +102 -0
  99. data/spec/units/gandi_v5/error/gandi_error_spec.rb +30 -0
  100. data/spec/units/gandi_v5/error_spec.rb +4 -0
  101. data/spec/units/gandi_v5/live_dns/domain_spec.rb +247 -0
  102. data/spec/units/gandi_v5/live_dns/record_set_spec.rb +74 -0
  103. data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +37 -0
  104. data/spec/units/gandi_v5/live_dns/zone_spec.rb +329 -0
  105. data/spec/units/gandi_v5/live_dns_spec.rb +17 -0
  106. data/spec/units/gandi_v5/organization_spec.rb +30 -0
  107. data/spec/units/gandi_v5_spec.rb +204 -0
  108. metadata +406 -0
@@ -0,0 +1,451 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GandiV5::Domain do
4
+ subject { described_class.new fqdn: 'example.com' }
5
+
6
+ describe '.list' do
7
+ let(:body_fixture) { File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'list.yaml')) }
8
+
9
+ describe 'With default values' do
10
+ subject { described_class.list }
11
+
12
+ before :each do
13
+ headers = { params: { page: 1, per_page: 100 } }
14
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers)
15
+ .and_return(YAML.load_file(body_fixture))
16
+ end
17
+
18
+ its('count') { should eq 1 }
19
+ its('first.uuid') { should eq 'domain-uuid' }
20
+ its('first.fqdn') { should eq 'example.com' }
21
+ its('first.fqdn_unicode') { should eq 'example.com' }
22
+ its('first.name_servers') { should be_nil }
23
+ its('first.services') { should be_nil }
24
+ its('first.status') { should eq [] }
25
+ its('first.tld') { should eq 'com' }
26
+ its('first.can_tld_lock') { should be_nil }
27
+ its('first.auth_info') { should be_nil }
28
+ its('first.sharing_uuid') { should be_nil }
29
+ its('first.tags') { should match_array ['Tag'] }
30
+ its('first.trustee_roles') { should be_nil }
31
+ its('first.owner') { should eq 'Example Owner' }
32
+ its('first.organisation_owner') { should eq 'Example Organisation' }
33
+ its('first.domain_owner') { should eq 'Example Owner' }
34
+ its('first.name_server') { should be :livedns }
35
+ its('first.sharing_space') { should be_nil }
36
+ its('first.dates.created_at') { should eq Time.new(2011, 2, 21, 10, 39, 0) }
37
+ its('first.dates.registry_created_at') { should eq Time.new(2003, 3, 12, 12, 2, 11) }
38
+ its('first.dates.registry_ends_at') { should eq Time.new(2020, 3, 12, 12, 2, 11) }
39
+ its('first.dates.updated_at') { should eq Time.new(2019, 2, 6, 9, 49, 37) }
40
+ its('first.auto_renew.dates') { should be_nil }
41
+ its('first.auto_renew.duration') { should be_nil }
42
+ its('first.auto_renew.enabled') { should eq false }
43
+ its('first.auto_renew.org_id') { should be_nil }
44
+ its('first.contacts?') { should be false }
45
+ end
46
+
47
+ it 'Keeps fetching until no more to get' do
48
+ headers1 = { params: { page: 1, per_page: 1 } }
49
+ headers2 = { params: { page: 2, per_page: 1 } }
50
+ # rubocop:disable Layout/MultilineMethodCallIndentation
51
+ # https://github.com/rubocop-hq/rubocop/issues/7088
52
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers1)
53
+ .ordered
54
+ .and_return(YAML.load_file(body_fixture))
55
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers2)
56
+ .ordered
57
+ .and_return([])
58
+ # rubocop:enable Layout/MultilineMethodCallIndentation
59
+
60
+ expect(described_class.list(per_page: 1).count).to eq 1
61
+ end
62
+
63
+ it 'Given a range as page number' do
64
+ headers1 = { params: { page: 1, per_page: 1 } }
65
+ headers2 = { params: { page: 2, per_page: 1 } }
66
+ # rubocop:disable Layout/MultilineMethodCallIndentation
67
+ # https://github.com/rubocop-hq/rubocop/issues/7088
68
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers1)
69
+ .ordered
70
+ .and_return(YAML.load_file(body_fixture))
71
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers2)
72
+ .ordered
73
+ .and_return([])
74
+ # rubocop:enable Layout/MultilineMethodCallIndentation
75
+
76
+ expect(described_class.list(page: (1..2), per_page: 1).count).to eq 1
77
+ end
78
+
79
+ describe 'Passes optional query params' do
80
+ %i[fqdn page per_page sort_by tld].each do |param|
81
+ it param.to_s do
82
+ param = { param => 5 }
83
+ headers = { params: { page: 1, per_page: 100 }.merge(param) }
84
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains', headers)
85
+ .and_return([])
86
+ expect(described_class.list(**param)).to eq []
87
+ end
88
+ end
89
+ end
90
+ end
91
+
92
+ describe '.fetch' do
93
+ subject { described_class.fetch 'example.com' }
94
+
95
+ before :each do
96
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'get.yaml'))
97
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com')
98
+ .and_return(YAML.load_file(body_fixture))
99
+ end
100
+
101
+ its('uuid') { should eq 'domain-uuid' }
102
+ its('fqdn') { should eq 'example.com' }
103
+ its('fqdn_unicode') { should eq 'example.com' }
104
+ its('status') { should eq [] }
105
+ its('tld') { should eq 'com' }
106
+ its('auth_info') { should be_nil }
107
+ its('sharing_uuid') { should be_nil }
108
+ its('tags') { should match_array ['Tag'] }
109
+ its('trustee_roles') { should be_nil }
110
+ its('owner') { should be_nil }
111
+ its('organisation_owner') { should be_nil }
112
+ its('domain_owner') { should be_nil }
113
+ its('name_servers') { should match_array %w[192.168.0.1 192.168.0.2] }
114
+ its('services') { should match_array %i[gandilivedns dnssec] }
115
+ its('sharing_space') { should be_nil }
116
+ its('dates.created_at') { should eq Time.new(2011, 2, 21, 10, 39, 0) }
117
+ its('dates.registry_created_at') { should eq Time.new(2003, 3, 12, 12, 2, 11) }
118
+ its('dates.registry_ends_at') { should eq Time.new(2020, 3, 12, 12, 2, 11) }
119
+ its('dates.updated_at') { should eq Time.new(2019, 2, 6, 9, 49, 37) }
120
+ its('auto_renew.dates') { should match_array [Time.new(2021, 1, 13, 9, 4, 18), Time.new(2021, 1, 29, 10, 4, 18)] }
121
+ its('auto_renew.duration') { should eq 1 }
122
+ its('auto_renew.enabled') { should eq true }
123
+ its('auto_renew.org_id') { should eq 'org-uuid' }
124
+ its('contacts?') { should be true }
125
+ its('contacts.owner.country') { should eq 'GB' }
126
+ its('contacts.owner.email') { should eq 'owner@example.com' }
127
+ its('contacts.owner.family') { should eq 'Fam' }
128
+ its('contacts.owner.given') { should eq 'Giv' }
129
+ its('contacts.owner.address') { should eq 'Somestreet' }
130
+ its('contacts.owner.type') { should be :company }
131
+ end
132
+
133
+ describe '.create' do
134
+ let(:url) { 'https://api.gandi.net/v5/domain/domains' }
135
+
136
+ describe 'Sets dry-run header' do
137
+ let(:body) { '{"owner":{},"fqdn":"example.com"}' }
138
+
139
+ it 'False by default' do
140
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
141
+ described_class.create 'example.com', owner: {}
142
+ end
143
+
144
+ it 'True' do
145
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
146
+ described_class.create 'example.com', owner: {}, dry_run: true
147
+ end
148
+
149
+ it 'False' do
150
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
151
+ described_class.create 'example.com', owner: {}, dry_run: false
152
+ end
153
+
154
+ it 'Dry run was successful' do
155
+ returns = { 'status' => 'success' }
156
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
157
+ .and_return(returns)
158
+ expect(described_class.create('example.com', owner: {}, dry_run: true)).to be returns
159
+ end
160
+
161
+ it 'Dry run has errors' do
162
+ returns = {
163
+ 'status' => 'error',
164
+ 'errors' => [{ 'description' => 'd', 'location' => 'l', 'name' => 'n' }]
165
+ }
166
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 1)
167
+ .and_return(returns)
168
+ expect(described_class.create('example.com', owner: {}, dry_run: true)).to be returns
169
+ end
170
+ end
171
+
172
+ it 'Success' do
173
+ returns = { 'message' => 'Confirmation message.' }
174
+ body = '{"owner":{},"fqdn":"example.com"}'
175
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
176
+ .and_return(returns)
177
+ expect(described_class.create('example.com', owner: {})).to be returns
178
+ end
179
+
180
+ it 'Errors on missing owner' do
181
+ expect { described_class.create 'example.com' }.to raise_error ArgumentError, 'missing keyword: owner'
182
+ end
183
+
184
+ it 'Given contact as hash' do
185
+ body = '{"owner":{"email":"owner@example.com"},"fqdn":"example.com"}'
186
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
187
+ described_class.create 'example.com', owner: { email: 'owner@example.com' }
188
+ end
189
+
190
+ it 'Given contact as GandiV5::Domain::Contact' do
191
+ body = '{"owner":{"email":"owner@example.com"},"fqdn":"example.com"}'
192
+ expect(GandiV5).to receive(:post).with(url, body, 'Dry-Run': 0)
193
+ owner = double GandiV5::Domain::Contact, to_gandi: { 'email' => 'owner@example.com' }
194
+ described_class.create 'example.com', owner: owner
195
+ end
196
+ end
197
+
198
+ describe '.availability' do
199
+ it 'With default values' do
200
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'availability.yaml'))
201
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/check', params: { name: 'example.com' })
202
+ .and_return(YAML.load_file(body_fixture))
203
+ expect(described_class.availability('example.com')).to eq(
204
+ 'currency' => 'GBP',
205
+ 'grid' => 'A',
206
+ 'products' => [
207
+ {
208
+ 'status' => 'unavailable',
209
+ 'name' => 'example.com',
210
+ 'process' => 'create',
211
+ 'taxes' => [{ 'type' => 'service', 'rate' => 0, 'name' => 'vat' }]
212
+ }
213
+ ],
214
+ 'taxes' => [{ 'type' => 'service', 'rate' => 0, 'name' => 'vat' }]
215
+ )
216
+ end
217
+
218
+ describe 'Passes optional query params' do
219
+ %i[country currency duration_unit extension grid lang max_duration period processes sharing_uuid].each do |param|
220
+ it param.to_s do
221
+ url = 'https://api.gandi.net/v5/domain/check'
222
+ expect(GandiV5).to receive(:get).with(url, params: { name: 'example.com', param => 5 }).and_return([])
223
+ expect(described_class.availability('example.com', param => 5)).to eq []
224
+ end
225
+ end
226
+ end
227
+ end
228
+
229
+ it '.tlds' do
230
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'tlds.yaml'))
231
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/tlds')
232
+ .and_return(YAML.load_file(body_fixture))
233
+ expect(described_class.tlds).to match_array %w[a b c]
234
+ end
235
+
236
+ it '.tld' do
237
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'tld.yaml'))
238
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/tlds/name')
239
+ .and_return(YAML.load_file(body_fixture))
240
+ expect(described_class.tld('name')).to eq(
241
+ category: 'ccTLD',
242
+ name: 'eu',
243
+ lock: false,
244
+ change_owner: true,
245
+ authinfo_for_transfer: true,
246
+ full_tld: 'eu',
247
+ corporate: false,
248
+ ext_trade: true,
249
+ href: 'https://api.test/v5/domain/tlds/eu'
250
+ )
251
+ end
252
+
253
+ describe '#to_s' do
254
+ it 'Has identical fqdn and fqdn_unicode' do
255
+ domain = described_class.new fqdn: 'example.com', fqdn_unicode: 'example.com'
256
+ expect(domain.to_s).to eq 'example.com'
257
+ end
258
+
259
+ it 'Has differing fqdn and fqdn_unicode' do
260
+ domain = described_class.new fqdn: 'example.com', fqdn_unicode: 'unicode.example.com'
261
+ expect(domain.to_s).to eq 'unicode.example.com (example.com)'
262
+ end
263
+ end
264
+
265
+ describe '#refresh' do
266
+ before :each do
267
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'get.yaml'))
268
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com')
269
+ .and_return(YAML.load_file(body_fixture))
270
+ subject.refresh
271
+ end
272
+
273
+ its('uuid') { should eq 'domain-uuid' }
274
+ its('fqdn') { should eq 'example.com' }
275
+ its('fqdn_unicode') { should eq 'example.com' }
276
+ its('status') { should eq [] }
277
+ its('tld') { should eq 'com' }
278
+ its('auth_info') { should be_nil }
279
+ its('sharing_uuid') { should be_nil }
280
+ its('tags') { should match_array ['Tag'] }
281
+ its('trustee_roles') { should be_nil }
282
+ its('owner') { should be_nil }
283
+ its('organisation_owner') { should be_nil }
284
+ its('domain_owner') { should be_nil }
285
+ its('name_servers') { should match_array %w[192.168.0.1 192.168.0.2] }
286
+ its('services') { should match_array %i[gandilivedns dnssec] }
287
+ its('sharing_space') { should be_nil }
288
+ its('dates.created_at') { should eq Time.new(2011, 2, 21, 10, 39, 0) }
289
+ its('dates.registry_created_at') { should eq Time.new(2003, 3, 12, 12, 2, 11) }
290
+ its('dates.registry_ends_at') { should eq Time.new(2020, 3, 12, 12, 2, 11) }
291
+ its('dates.updated_at') { should eq Time.new(2019, 2, 6, 9, 49, 37) }
292
+ its('auto_renew.dates') { should match_array [Time.new(2021, 1, 13, 9, 4, 18), Time.new(2021, 1, 29, 10, 4, 18)] }
293
+ its('auto_renew.duration') { should eq 1 }
294
+ its('auto_renew.enabled') { should eq true }
295
+ its('auto_renew.org_id') { should eq 'org-uuid' }
296
+ its('contacts.owner.country') { should eq 'GB' }
297
+ its('contacts.owner.email') { should eq 'owner@example.com' }
298
+ its('contacts.owner.family') { should eq 'Fam' }
299
+ its('contacts.owner.given') { should eq 'Giv' }
300
+ its('contacts.owner.address') { should eq 'Somestreet' }
301
+ its('contacts.owner.type') { should be :company }
302
+ end
303
+
304
+ describe 'Domain contacts' do
305
+ describe '#contacts' do
306
+ it 'Already fetched' do
307
+ domain = described_class.new fqdn: 'example.com', contacts: {}
308
+ expect(domain).to_not receive(:fetch_contacts)
309
+ expect(domain.contacts).to eq({})
310
+ end
311
+
312
+ it 'Not already fetched' do
313
+ contacts = {}
314
+ expect(subject).to receive(:fetch_contacts).and_return(contacts)
315
+ expect(subject.contacts).to be contacts
316
+ end
317
+ end
318
+
319
+ describe '#fetch_contacts' do
320
+ subject { described_class.new(fqdn: 'example.com').fetch_contacts }
321
+
322
+ before(:each) do
323
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'fetch_contacts.yaml'))
324
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com/contacts')
325
+ .and_return(YAML.load_file(body_fixture))
326
+ end
327
+
328
+ its('owner.country') { should eq 'GB' }
329
+ its('owner.email') { should eq 'owner@example.com' }
330
+ its('owner.family') { should eq 'Fam' }
331
+ its('owner.given') { should eq 'Giv' }
332
+ its('owner.address') { should eq 'Somestreet' }
333
+ its('owner.type') { should be :company }
334
+ end
335
+
336
+ describe '#update_contacts' do
337
+ let(:fetched_contacts) { { admin: double(GandiV5::Domain::Contact) } }
338
+
339
+ before(:each) do
340
+ url = 'https://api.gandi.net/v5/domain/domains/example.com/contacts'
341
+ body = '{"admin":{"email":"admin@example.com"}}'
342
+ expect(GandiV5).to receive(:patch).with(url, body)
343
+ .and_return('message' => 'Confirmation message.')
344
+
345
+ expect(subject).to receive(:fetch_contacts).and_return(fetched_contacts)
346
+ end
347
+
348
+ it 'Given a Hash' do
349
+ new_contacts = { admin: { email: 'admin@example.com' } }
350
+ expect(subject.update_contacts(**new_contacts)).to be fetched_contacts
351
+ end
352
+
353
+ it 'Given a GandiV5::Domain::Contact' do
354
+ new_contacts = { admin: double(GandiV5::Domain::Contact, to_gandi: { 'email' => 'admin@example.com' }) }
355
+ expect(subject.update_contacts(**new_contacts)).to be fetched_contacts
356
+ end
357
+ end
358
+ end
359
+
360
+ describe 'Domain renewal' do
361
+ describe '#renewal_information' do
362
+ let(:renewal_info) { double GandiV5::Domain::RenewalInformation }
363
+
364
+ it 'Already fetched' do
365
+ subject.instance_exec(renewal_info) { |renewal_info| @renewal_information = renewal_info }
366
+ expect(subject).to_not receive(:fetch_renewal_information)
367
+ expect(subject.renewal_information).to be renewal_info
368
+ end
369
+
370
+ it 'Not already fetched' do
371
+ expect(subject).to receive(:fetch_renewal_information).and_return(renewal_info)
372
+ expect(subject.renewal_information).to be renewal_info
373
+ end
374
+ end
375
+
376
+ describe '#fetch_renewal_information' do
377
+ subject { described_class.new(fqdn: 'example.com').fetch_renewal_information }
378
+
379
+ before(:each) do
380
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'renewal_info.yaml'))
381
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com/renew')
382
+ .and_return(YAML.load_file(body_fixture))
383
+ end
384
+
385
+ its('begins_at') { should eq Time.new(2012, 1, 1, 0, 0, 0) }
386
+ its('prohibited') { should be false }
387
+ its('minimum') { should eq 1 }
388
+ its('maximum') { should eq 2 }
389
+ its('durations') { should match_array [1, 2] }
390
+ its('contracts.count') { should eq 1 }
391
+ its('contracts.first.id') { should eq 'uuid' }
392
+ its('contracts.first.name') { should eq 'Name' }
393
+ end
394
+
395
+ it '#renew_for' do
396
+ expect(GandiV5).to receive(:post).with('https://api.gandi.net/v5/domain/domains/example.com/renew', '{"duration":2}')
397
+ .and_return('message' => 'Confirmation message.')
398
+ expect(subject.renew_for(2)).to eq 'Confirmation message.'
399
+ end
400
+ end
401
+
402
+ describe 'Domain restoration' do
403
+ describe '#restore_information' do
404
+ let(:restore_info) { double GandiV5::Domain::RestoreInformation }
405
+
406
+ it 'Already fetched' do
407
+ subject.instance_exec(restore_info) { |restore_info| @restore_information = restore_info }
408
+ expect(subject).to_not receive(:fetch_restore_information)
409
+ expect(subject.restore_information).to be restore_info
410
+ end
411
+
412
+ it 'Not already fetched' do
413
+ expect(subject).to receive(:fetch_restore_information).and_return(restore_info)
414
+ expect(subject.restore_information).to be restore_info
415
+ end
416
+ end
417
+
418
+ describe '#fetch_restore_information' do
419
+ subject { described_class.new(fqdn: 'example.com').fetch_restore_information }
420
+
421
+ describe 'Information is available' do
422
+ before(:each) do
423
+ body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Domain', 'restore_info.yaml'))
424
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com/restore')
425
+ .and_return(YAML.load_file(body_fixture))
426
+ end
427
+
428
+ its('restorable') { should be true }
429
+ its('contracts.count') { should eq 1 }
430
+ its('contracts.first.id') { should eq 'uuid' }
431
+ its('contracts.first.name') { should eq 'Name' }
432
+ end
433
+
434
+ describe 'Information is unavailable' do
435
+ before(:each) do
436
+ expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/domain/domains/example.com/restore')
437
+ .and_raise(RestClient::NotFound)
438
+ end
439
+
440
+ its('restorable') { should be false }
441
+ its('contracts') { should be_nil }
442
+ end
443
+ end
444
+
445
+ it '#restore' do
446
+ expect(GandiV5).to receive(:post).with('https://api.gandi.net/v5/domain/domains/example.com/restore', '{}')
447
+ .and_return('message' => 'Confirmation message.')
448
+ expect(subject.restore).to eq 'Confirmation message.'
449
+ end
450
+ end
451
+ end
@@ -0,0 +1,131 @@
1
+ # frozen_string_literal: true
2
+
3
+ describe GandiV5::Email::Mailbox::Responder do
4
+ describe '#active?' do
5
+ before(:each) { Timecop.travel Time.new(2000, 1, 2, 12, 0, 0) }
6
+ let(:future) { Time.new 2000, 1, 3, 0, 0, 0, 0 }
7
+ let(:past) { Time.new 2000, 1, 1, 0, 0, 0, 0 }
8
+
9
+ describe 'Is enabled' do
10
+ describe 'Starts at' do
11
+ describe 'Missing' do
12
+ describe 'Ends at' do
13
+ it 'Missing' do
14
+ responder = described_class.new enabled: true
15
+ expect(responder.active?).to be true
16
+ end
17
+
18
+ it 'In the past' do
19
+ responder = described_class.new enabled: true, ends_at: past
20
+ expect(responder.active?).to be false
21
+ end
22
+
23
+ it 'In the future' do
24
+ responder = described_class.new enabled: true, ends_at: future
25
+ expect(responder.active?).to be true
26
+ end
27
+ end
28
+ end
29
+
30
+ describe 'In the past' do
31
+ describe 'Ends at' do
32
+ it 'Missing' do
33
+ responder = described_class.new enabled: true, starts_at: past
34
+ expect(responder.active?).to be true
35
+ end
36
+
37
+ it 'In the past' do
38
+ responder = described_class.new enabled: true, starts_at: past, ends_at: past
39
+ expect(responder.active?).to be false
40
+ end
41
+
42
+ it 'In the future' do
43
+ responder = described_class.new enabled: true, starts_at: past, ends_at: future
44
+ expect(responder.active?).to be true
45
+ end
46
+ end
47
+ end
48
+
49
+ describe 'In the future' do
50
+ describe 'Ends at' do
51
+ it 'Missing' do
52
+ responder = described_class.new enabled: true, starts_at: future
53
+ expect(responder.active?).to be false
54
+ end
55
+
56
+ it 'In the past' do
57
+ responder = described_class.new enabled: true, starts_at: future, ends_at: past
58
+ expect(responder.active?).to be false
59
+ end
60
+
61
+ it 'In the future' do
62
+ responder = described_class.new enabled: true, starts_at: future, ends_at: future
63
+ expect(responder.active?).to be false
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+
70
+ describe 'Is disabled' do
71
+ describe 'Starts at' do
72
+ describe 'Missing' do
73
+ describe 'Ends at' do
74
+ it 'Missing' do
75
+ responder = described_class.new enabled: false
76
+ expect(responder.active?).to be false
77
+ end
78
+
79
+ it 'In the past' do
80
+ responder = described_class.new enabled: false, ends_at: past
81
+ expect(responder.active?).to be false
82
+ end
83
+
84
+ it 'In the future' do
85
+ responder = described_class.new enabled: false, ends_at: future
86
+ expect(responder.active?).to be false
87
+ end
88
+ end
89
+ end
90
+
91
+ describe 'In the past' do
92
+ describe 'Ends at' do
93
+ it 'Missing' do
94
+ responder = described_class.new enabled: false, starts_at: past
95
+ expect(responder.active?).to be false
96
+ end
97
+
98
+ it 'In the past' do
99
+ responder = described_class.new enabled: false, starts_at: past, ends_at: past
100
+ expect(responder.active?).to be false
101
+ end
102
+
103
+ it 'In the future' do
104
+ responder = described_class.new enabled: false, starts_at: past, ends_at: future
105
+ expect(responder.active?).to be false
106
+ end
107
+ end
108
+ end
109
+
110
+ describe 'In the future' do
111
+ describe 'Ends at' do
112
+ it 'Missing' do
113
+ responder = described_class.new enabled: false, starts_at: future
114
+ expect(responder.active?).to be false
115
+ end
116
+
117
+ it 'In the past' do
118
+ responder = described_class.new enabled: false, starts_at: future, ends_at: past
119
+ expect(responder.active?).to be false
120
+ end
121
+
122
+ it 'In the future' do
123
+ responder = described_class.new enabled: false, starts_at: future, ends_at: future
124
+ expect(responder.active?).to be false
125
+ end
126
+ end
127
+ end
128
+ end
129
+ end
130
+ end
131
+ end