gandi_v5 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
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