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.
- checksums.yaml +7 -0
- data/.gitignore +24 -0
- data/.rspec +3 -0
- data/.rubocop.yml +20 -0
- data/.travis.yml +23 -0
- data/CHANGELOG.md +3 -0
- data/Gemfile +6 -0
- data/Guardfile +40 -0
- data/LICENSE.md +32 -0
- data/README.md +94 -0
- data/Rakefile +3 -0
- data/TODO.md +29 -0
- data/bin/console +13 -0
- data/gandi_v5.gemspec +41 -0
- data/lib/gandi_v5/billing/info/prepaid.rb +33 -0
- data/lib/gandi_v5/billing/info.rb +26 -0
- data/lib/gandi_v5/billing.rb +28 -0
- data/lib/gandi_v5/data/converter/array_of.rb +35 -0
- data/lib/gandi_v5/data/converter/symbol.rb +26 -0
- data/lib/gandi_v5/data/converter/time.rb +28 -0
- data/lib/gandi_v5/data/converter.rb +41 -0
- data/lib/gandi_v5/data.rb +244 -0
- data/lib/gandi_v5/domain/auto_renew.rb +64 -0
- data/lib/gandi_v5/domain/contact.rb +102 -0
- data/lib/gandi_v5/domain/contract.rb +22 -0
- data/lib/gandi_v5/domain/dates.rb +44 -0
- data/lib/gandi_v5/domain/renewal_information.rb +41 -0
- data/lib/gandi_v5/domain/restore_information.rb +18 -0
- data/lib/gandi_v5/domain/sharing_space.rb +21 -0
- data/lib/gandi_v5/domain.rb +431 -0
- data/lib/gandi_v5/email/mailbox/responder.rb +36 -0
- data/lib/gandi_v5/email/mailbox.rb +236 -0
- data/lib/gandi_v5/email/offer.rb +27 -0
- data/lib/gandi_v5/email/slot.rb +134 -0
- data/lib/gandi_v5/email.rb +11 -0
- data/lib/gandi_v5/error/gandi_error.rb +21 -0
- data/lib/gandi_v5/error.rb +9 -0
- data/lib/gandi_v5/live_dns/domain.rb +211 -0
- data/lib/gandi_v5/live_dns/record_set.rb +79 -0
- data/lib/gandi_v5/live_dns/zone/snapshot.rb +62 -0
- data/lib/gandi_v5/live_dns/zone.rb +301 -0
- data/lib/gandi_v5/live_dns.rb +30 -0
- data/lib/gandi_v5/organization.rb +66 -0
- data/lib/gandi_v5/version.rb +5 -0
- data/lib/gandi_v5.rb +178 -0
- data/spec/.rubocop.yml +4 -0
- data/spec/features/domain_spec.rb +45 -0
- data/spec/features/livedns_domain_spec.rb +8 -0
- data/spec/features/livedns_zone_spec.rb +45 -0
- data/spec/features/mailbox_spec.rb +18 -0
- data/spec/fixtures/bodies/GandiV5_Billing/info.yaml +10 -0
- data/spec/fixtures/bodies/GandiV5_Domain/availability.yaml +15 -0
- data/spec/fixtures/bodies/GandiV5_Domain/fetch_contacts.yaml +8 -0
- data/spec/fixtures/bodies/GandiV5_Domain/get.yaml +37 -0
- data/spec/fixtures/bodies/GandiV5_Domain/list.yaml +20 -0
- data/spec/fixtures/bodies/GandiV5_Domain/renewal_info.yaml +12 -0
- data/spec/fixtures/bodies/GandiV5_Domain/restore_info.yaml +5 -0
- data/spec/fixtures/bodies/GandiV5_Domain/tld.yaml +10 -0
- data/spec/fixtures/bodies/GandiV5_Domain/tlds.yaml +7 -0
- data/spec/fixtures/bodies/GandiV5_Email_Mailbox/get.yaml +16 -0
- data/spec/fixtures/bodies/GandiV5_Email_Mailbox/list.yaml +8 -0
- data/spec/fixtures/bodies/GandiV5_Email_Slot/get.yaml +10 -0
- data/spec/fixtures/bodies/GandiV5_Email_Slot/list.yaml +8 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/get.yaml +4 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Domain/list.yaml +2 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/get.yaml +11 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone/list.yaml +11 -0
- data/spec/fixtures/bodies/GandiV5_LiveDNS_Zone_Snapshot/get.yaml +9 -0
- data/spec/fixtures/bodies/GandiV5_Organization/get.yaml +17 -0
- data/spec/fixtures/vcr/Domain_features/List_domains.yml +54 -0
- data/spec/fixtures/vcr/Domain_features/Renew_domain.yml +133 -0
- data/spec/fixtures/vcr/LiveDNS_Domain_features/List_domains.yml +32 -0
- data/spec/fixtures/vcr/LiveDNS_Zone_features/List_zones.yml +42 -0
- data/spec/fixtures/vcr/LiveDNS_Zone_features/Make_and_save_snapshot.yml +72 -0
- data/spec/fixtures/vcr/LiveDNS_Zone_features/Save_zone_to_file.yml +28 -0
- data/spec/fixtures/vcr/Mailbox_features/List_mailboxes.yml +39 -0
- data/spec/spec_helper.rb +60 -0
- data/spec/test.env +1 -0
- data/spec/units/gandi_v5/billing/info/prepaid_spec.rb +20 -0
- data/spec/units/gandi_v5/billing/info_spec.rb +4 -0
- data/spec/units/gandi_v5/billing_spec.rb +41 -0
- data/spec/units/gandi_v5/data/converter/array_of_spec.rb +18 -0
- data/spec/units/gandi_v5/data/converter/symbol_spec.rb +16 -0
- data/spec/units/gandi_v5/data/converter/time_spec.rb +16 -0
- data/spec/units/gandi_v5/data/converter_spec.rb +31 -0
- data/spec/units/gandi_v5/data_spec.rb +340 -0
- data/spec/units/gandi_v5/domain/auto_renew_spec.rb +70 -0
- data/spec/units/gandi_v5/domain/contact_spec.rb +36 -0
- data/spec/units/gandi_v5/domain/contract_spec.rb +4 -0
- data/spec/units/gandi_v5/domain/dates_spec.rb +4 -0
- data/spec/units/gandi_v5/domain/renewal_information_spec.rb +81 -0
- data/spec/units/gandi_v5/domain/restore_information_spec.rb +4 -0
- data/spec/units/gandi_v5/domain/sharing_space_spec.rb +4 -0
- data/spec/units/gandi_v5/domain_spec.rb +451 -0
- data/spec/units/gandi_v5/email/mailbox/responder_spec.rb +131 -0
- data/spec/units/gandi_v5/email/mailbox_spec.rb +384 -0
- data/spec/units/gandi_v5/email/offer_spec.rb +17 -0
- data/spec/units/gandi_v5/email/slot_spec.rb +102 -0
- data/spec/units/gandi_v5/error/gandi_error_spec.rb +30 -0
- data/spec/units/gandi_v5/error_spec.rb +4 -0
- data/spec/units/gandi_v5/live_dns/domain_spec.rb +247 -0
- data/spec/units/gandi_v5/live_dns/record_set_spec.rb +74 -0
- data/spec/units/gandi_v5/live_dns/zone/snapshot_spec.rb +37 -0
- data/spec/units/gandi_v5/live_dns/zone_spec.rb +329 -0
- data/spec/units/gandi_v5/live_dns_spec.rb +17 -0
- data/spec/units/gandi_v5/organization_spec.rb +30 -0
- data/spec/units/gandi_v5_spec.rb +204 -0
- metadata +406 -0
@@ -0,0 +1,329 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe GandiV5::LiveDNS::Zone do
|
4
|
+
subject do
|
5
|
+
described_class.new(
|
6
|
+
name: 'Zone Name',
|
7
|
+
uuid: 'zone-uuid',
|
8
|
+
soa_retry: 1,
|
9
|
+
soa_minimum: 2,
|
10
|
+
soa_refresh: 3,
|
11
|
+
soa_expire: 4,
|
12
|
+
soa_serial: 5,
|
13
|
+
soa_email: 'admin.example.com',
|
14
|
+
soa_primary_ns: '192.168.0.1'
|
15
|
+
)
|
16
|
+
end
|
17
|
+
|
18
|
+
it '#to_s' do
|
19
|
+
expect(subject.to_s).to eq [
|
20
|
+
'@ IN SOA 192.168.0.1 admin.example.com (',
|
21
|
+
"\t5\t;Serial",
|
22
|
+
"\t3\t\t;Refresh",
|
23
|
+
"\t1\t\t;Retry",
|
24
|
+
"\t4\t\t;Expire",
|
25
|
+
"\t2\t\t;Minimum & Negative TTL",
|
26
|
+
')'
|
27
|
+
].join("\n")
|
28
|
+
end
|
29
|
+
|
30
|
+
describe '#fetch_records' do
|
31
|
+
it 'All of them' do
|
32
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/records')
|
33
|
+
.and_return([])
|
34
|
+
|
35
|
+
expect(subject.fetch_records).to eq []
|
36
|
+
end
|
37
|
+
|
38
|
+
it 'All for a name' do
|
39
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name')
|
40
|
+
.and_return([])
|
41
|
+
|
42
|
+
expect(subject.fetch_records('name')).to eq []
|
43
|
+
end
|
44
|
+
|
45
|
+
it 'A type for a name' do
|
46
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name/TXT')
|
47
|
+
.and_return(
|
48
|
+
[
|
49
|
+
{
|
50
|
+
'rrset_type' => 'TXT',
|
51
|
+
'rrset_name' => 'name',
|
52
|
+
'rrset_ttl' => 600,
|
53
|
+
'rrset_values' => %w[a b]
|
54
|
+
}
|
55
|
+
]
|
56
|
+
)
|
57
|
+
|
58
|
+
records = subject.fetch_records('name', 'TXT')
|
59
|
+
expect(records.count).to eq 1
|
60
|
+
expect(records.first.type).to eq 'TXT'
|
61
|
+
expect(records.first.ttl).to eq 600
|
62
|
+
expect(records.first.name).to eq 'name'
|
63
|
+
expect(records.first.values).to match_array %w[a b]
|
64
|
+
end
|
65
|
+
|
66
|
+
it 'Invalid type' do
|
67
|
+
expect { subject.fetch_records 'name', 'INVALID-TYPE' }.to raise_error ArgumentError
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
describe '#fetch_zone_lines' do
|
72
|
+
it 'All of them' do
|
73
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records'
|
74
|
+
expect(GandiV5).to receive(:get).with(url, accept: 'text/plain').and_return('returned')
|
75
|
+
expect(subject.fetch_zone_lines).to eq 'returned'
|
76
|
+
end
|
77
|
+
|
78
|
+
it 'All for a name' do
|
79
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name'
|
80
|
+
expect(GandiV5).to receive(:get).with(url, accept: 'text/plain').and_return('returned')
|
81
|
+
expect(subject.fetch_zone_lines('name')).to eq 'returned'
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'A type for a name' do
|
85
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name/TXT'
|
86
|
+
expect(GandiV5).to receive(:get).with(url, accept: 'text/plain').and_return('returned')
|
87
|
+
expect(subject.fetch_zone_lines('name', 'TXT')).to eq 'returned'
|
88
|
+
end
|
89
|
+
|
90
|
+
it 'Invalid type' do
|
91
|
+
expect { subject.fetch_zone_lines 'name', 'INVALID-TYPE' }.to raise_error ArgumentError
|
92
|
+
end
|
93
|
+
end
|
94
|
+
|
95
|
+
describe '#add_record' do
|
96
|
+
it 'Success' do
|
97
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records'
|
98
|
+
body = '{"rrset_name":"name","rrset_type":"TXT","rrset_ttl":900,"rrset_values":["a","b"]}'
|
99
|
+
expect(GandiV5).to receive(:post).with(url, body).and_return('message' => 'Confirmation message.')
|
100
|
+
expect(subject.add_record('name', 'TXT', 900, 'a', 'b')).to eq 'Confirmation message.'
|
101
|
+
end
|
102
|
+
|
103
|
+
it 'Bad type' do
|
104
|
+
expect { subject.add_record 'name', 'INVALID-TYPE', 900, 'a' }.to raise_error ArgumentError
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'Bad TTL' do
|
108
|
+
expect { subject.add_record 'name', 'TXT', -900, 'a' }.to raise_error(
|
109
|
+
ArgumentError,
|
110
|
+
'ttl must be positive and non-zero'
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
it 'No values' do
|
115
|
+
expect { subject.add_record 'name', 'TXT', 900 }.to raise_error(
|
116
|
+
ArgumentError,
|
117
|
+
'there must be at least one value'
|
118
|
+
)
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
describe '#delete_records' do
|
123
|
+
it 'All of them' do
|
124
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records'
|
125
|
+
expect(GandiV5).to receive(:delete).with(url)
|
126
|
+
subject.delete_records
|
127
|
+
end
|
128
|
+
|
129
|
+
it 'All for a name' do
|
130
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name'
|
131
|
+
expect(GandiV5).to receive(:delete).with(url)
|
132
|
+
subject.delete_records 'name'
|
133
|
+
end
|
134
|
+
|
135
|
+
it 'A type for a name' do
|
136
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name/TXT'
|
137
|
+
expect(GandiV5).to receive(:delete).with(url)
|
138
|
+
subject.delete_records 'name', 'TXT'
|
139
|
+
end
|
140
|
+
|
141
|
+
it 'Invalid type' do
|
142
|
+
expect { subject.delete_records 'name', 'INVALID-TYPE' }.to raise_error ArgumentError
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
describe '#replace_records' do
|
147
|
+
it 'Given array of GandiV5::LiveDNS::RecordSet' do
|
148
|
+
records = [
|
149
|
+
{ name: 'name', ttl: 600, type: 'TXT', values: ['a'] }
|
150
|
+
]
|
151
|
+
|
152
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records'
|
153
|
+
body = '{"items":[{"rrset_name":"name","rrset_ttl":600,"rrset_type":"TXT","rrset_values":["a"]}]}'
|
154
|
+
expect(GandiV5).to receive(:put).with(url, body)
|
155
|
+
.and_return('message' => 'Confirmation message.')
|
156
|
+
expect(subject.replace_records(records: records)).to eq 'Confirmation message.'
|
157
|
+
end
|
158
|
+
|
159
|
+
it 'Given string' do
|
160
|
+
records = [
|
161
|
+
'@ 86400 IN A 192.168.0.1',
|
162
|
+
'* 86400 IN A 192.168.0.1'
|
163
|
+
].join("\n")
|
164
|
+
|
165
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records'
|
166
|
+
expect(GandiV5).to receive(:put).with(url, records, 'content-type': 'text/plain')
|
167
|
+
.and_return('message' => 'Confirmation message.')
|
168
|
+
expect(subject.replace_records(text: records)).to eq 'Confirmation message.'
|
169
|
+
end
|
170
|
+
|
171
|
+
it 'Given both' do
|
172
|
+
expect { subject.replace_records text: '', records: [] }.to raise_error(
|
173
|
+
ArgumentError,
|
174
|
+
'you must pass ONE of records: or text:'
|
175
|
+
)
|
176
|
+
end
|
177
|
+
|
178
|
+
it 'Given nothing' do
|
179
|
+
expect { subject.replace_records }.to raise_error ArgumentError, 'you must pass ONE of records: or text:'
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
it '#replace_records_for' do
|
184
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name'
|
185
|
+
body = '{"items":[{"rrset_type":"TXT","rrset_values":["a"]}]}'
|
186
|
+
expect(GandiV5).to receive(:put).with(url, body)
|
187
|
+
.and_return('message' => 'Confirmation message.')
|
188
|
+
records = { type: 'TXT', values: ['a'] }
|
189
|
+
expect(subject.replace_records_for('name', records)).to eq 'Confirmation message.'
|
190
|
+
end
|
191
|
+
|
192
|
+
describe '#replace_??_records_for' do
|
193
|
+
it '#replace_a_records_for' do
|
194
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name/A'
|
195
|
+
body = '{"rrset_ttl":600,"rrset_values":["192.168.0.1","192.168.0.2"]}'
|
196
|
+
expect(GandiV5).to receive(:put).with(url, body)
|
197
|
+
.and_return('message' => 'Confirmation message.')
|
198
|
+
expect(subject.replace_a_records_for('name', 600, '192.168.0.1', '192.168.0.2')).to eq 'Confirmation message.'
|
199
|
+
end
|
200
|
+
|
201
|
+
it '#replace_txt_records_for' do
|
202
|
+
url = 'https://dns.api.gandi.net/api/v5/zones/zone-uuid/records/name/TXT'
|
203
|
+
body = '{"rrset_ttl":600,"rrset_values":["a","b"]}'
|
204
|
+
expect(GandiV5).to receive(:put).with(url, body)
|
205
|
+
.and_return('message' => 'Confirmation message.')
|
206
|
+
expect(subject.replace_txt_records_for('name', 600, 'a', 'b')).to eq 'Confirmation message.'
|
207
|
+
end
|
208
|
+
end
|
209
|
+
|
210
|
+
it '#list_domains' do
|
211
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/domains')
|
212
|
+
.and_return([{ 'fqdn' => 'example.com' }])
|
213
|
+
expect(subject.list_domains).to match_array ['example.com']
|
214
|
+
end
|
215
|
+
|
216
|
+
describe '#attach_domain' do
|
217
|
+
it 'Given a fqdn' do
|
218
|
+
url = 'https://dns.api.gandi.net/api/v5/domains/example.com'
|
219
|
+
body = '{"zone_uuid":"zone-uuid"}'
|
220
|
+
expect(GandiV5).to receive(:patch).with(url, body)
|
221
|
+
.and_return('message' => 'Confirmation message.')
|
222
|
+
expect(subject.attach_domain('example.com')).to eq 'Confirmation message.'
|
223
|
+
end
|
224
|
+
|
225
|
+
it 'Given something with a fqdn method' do
|
226
|
+
url = 'https://dns.api.gandi.net/api/v5/domains/example.com'
|
227
|
+
body = '{"zone_uuid":"zone-uuid"}'
|
228
|
+
expect(GandiV5).to receive(:patch).with(url, body)
|
229
|
+
.and_return('message' => 'Confirmation message.')
|
230
|
+
domain = double GandiV5::LiveDNS::Domain, fqdn: 'example.com'
|
231
|
+
expect(subject.attach_domain(domain)).to eq 'Confirmation message.'
|
232
|
+
end
|
233
|
+
end
|
234
|
+
|
235
|
+
it '#snapshots' do
|
236
|
+
returns = [{ 'uuid' => 'snapshot-uuid', 'date_created' => '2016-12-16T16:51:26Z' }]
|
237
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/snapshots')
|
238
|
+
.and_return(returns)
|
239
|
+
expect(subject.snapshots).to eq('snapshot-uuid' => Time.new(2016, 12, 16, 16, 51, 26, 0))
|
240
|
+
end
|
241
|
+
|
242
|
+
it '#snapshot' do
|
243
|
+
returns = double GandiV5::LiveDNS::Zone::Snapshot
|
244
|
+
expect(GandiV5::LiveDNS::Zone::Snapshot).to receive(:fetch).with('zone-uuid', 'snapshot-uuid')
|
245
|
+
.and_return(returns)
|
246
|
+
expect(subject.snapshot('snapshot-uuid')).to be returns
|
247
|
+
end
|
248
|
+
|
249
|
+
it '#take_snapshot' do
|
250
|
+
returns = double GandiV5::LiveDNS::Zone::Snapshot
|
251
|
+
expect(GandiV5).to receive(:post).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid/snapshots')
|
252
|
+
.and_return('message' => 'Confirmation message.', 'uuid' => 'snapshot-uuid')
|
253
|
+
expect(GandiV5::LiveDNS::Zone::Snapshot).to receive(:fetch).with('zone-uuid', 'snapshot-uuid')
|
254
|
+
.and_return(returns)
|
255
|
+
expect(subject.take_snapshot).to be returns
|
256
|
+
end
|
257
|
+
|
258
|
+
it '#update' do
|
259
|
+
body = '{"name":"new-name"}'
|
260
|
+
expect(GandiV5).to receive(:patch).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid', body)
|
261
|
+
.and_return('message' => 'Confirmation message.')
|
262
|
+
expect(subject.update(name: 'new-name')).to eq 'Confirmation message.'
|
263
|
+
end
|
264
|
+
|
265
|
+
it '#delete' do
|
266
|
+
expect(GandiV5).to receive(:delete).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid')
|
267
|
+
subject.delete
|
268
|
+
end
|
269
|
+
|
270
|
+
describe '.create' do
|
271
|
+
it 'With sharing-id' do
|
272
|
+
body = '{"name":"Name"}'
|
273
|
+
params = { sharing_id: 'sharing-id' }
|
274
|
+
expect(GandiV5).to receive(:post).with('https://dns.api.gandi.net/api/v5/zones', body, params: params)
|
275
|
+
.and_return('message' => 'Confirmation message.')
|
276
|
+
expect(described_class.create('Name', sharing_id: 'sharing-id')).to eq 'Confirmation message.'
|
277
|
+
end
|
278
|
+
|
279
|
+
it 'Without sharing-id' do
|
280
|
+
body = '{"name":"Name"}'
|
281
|
+
expect(GandiV5).to receive(:post).with('https://dns.api.gandi.net/api/v5/zones', body, params: {})
|
282
|
+
.and_return('message' => 'Confirmation message.')
|
283
|
+
expect(described_class.create('Name')).to eq 'Confirmation message.'
|
284
|
+
end
|
285
|
+
end
|
286
|
+
|
287
|
+
describe '.list' do
|
288
|
+
subject { described_class.list }
|
289
|
+
|
290
|
+
before :each do
|
291
|
+
body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_LiveDNS_Zone', 'list.yaml'))
|
292
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones')
|
293
|
+
.and_return(YAML.load_file(body_fixture))
|
294
|
+
end
|
295
|
+
|
296
|
+
its('count') { should eq 1 }
|
297
|
+
its('first.uuid') { should eq 'zone-uuid' }
|
298
|
+
its('first.name') { should eq 'Name' }
|
299
|
+
its('first.sharing_uuid') { should be nil }
|
300
|
+
its('first.soa_retry') { should eq 3_600 }
|
301
|
+
its('first.soa_minimum') { should eq 900 }
|
302
|
+
its('first.soa_refresh') { should eq 10_800 }
|
303
|
+
its('first.soa_expire') { should eq 604_800 }
|
304
|
+
its('first.soa_serial') { should eq 1_432_798_405 }
|
305
|
+
its('first.soa_email') { should eq 'hostmaster.gandi.net.' }
|
306
|
+
its('first.soa_primary_ns') { should eq 'a.dns.gandi.net.' }
|
307
|
+
end
|
308
|
+
|
309
|
+
describe '.fetch' do
|
310
|
+
subject { described_class.fetch 'zone-uuid' }
|
311
|
+
|
312
|
+
before :each do
|
313
|
+
body_fixture = File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_LiveDNS_Zone', 'get.yaml'))
|
314
|
+
expect(GandiV5).to receive(:get).with('https://dns.api.gandi.net/api/v5/zones/zone-uuid')
|
315
|
+
.and_return(YAML.load_file(body_fixture))
|
316
|
+
end
|
317
|
+
|
318
|
+
its('uuid') { should eq 'zone-uuid' }
|
319
|
+
its('name') { should eq 'Name' }
|
320
|
+
its('sharing_uuid') { should be nil }
|
321
|
+
its('soa_retry') { should eq 3_600 }
|
322
|
+
its('soa_minimum') { should eq 900 }
|
323
|
+
its('soa_refresh') { should eq 10_800 }
|
324
|
+
its('soa_expire') { should eq 604_800 }
|
325
|
+
its('soa_serial') { should eq 1_432_798_405 }
|
326
|
+
its('soa_email') { should eq 'hostmaster.gandi.net.' }
|
327
|
+
its('soa_primary_ns') { should eq 'a.dns.gandi.net.' }
|
328
|
+
end
|
329
|
+
end
|
@@ -0,0 +1,17 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe GandiV5::LiveDNS do
|
4
|
+
describe '.require_valid_record_type' do
|
5
|
+
it 'Does nothing for valid type' do
|
6
|
+
expect { described_class.require_valid_record_type 'A' }.to_not raise_error
|
7
|
+
end
|
8
|
+
|
9
|
+
it 'Errors on invalid type' do
|
10
|
+
expect { described_class.require_valid_record_type 'invalid' }.to raise_error(
|
11
|
+
ArgumentError,
|
12
|
+
'type must be one of A, AAAA, CNAME, MX, NS, TXT, ALIAS, WKS, ' \
|
13
|
+
'SRV, LOC, SPF, CAA, DS, SSHFP, PTR, KEY, DNAME, TLSA, OPENPGPKEY, CDS'
|
14
|
+
)
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
@@ -0,0 +1,30 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe GandiV5::Organization do
|
4
|
+
let(:body_fixtures) { File.expand_path(File.join('spec', 'fixtures', 'bodies', 'GandiV5_Organization')) }
|
5
|
+
|
6
|
+
describe '.fetch' do
|
7
|
+
subject { described_class.fetch }
|
8
|
+
before :each do
|
9
|
+
expect(GandiV5).to receive(:get).with('https://api.gandi.net/v5/organization/user-info')
|
10
|
+
.and_return(YAML.load_file(File.join(body_fixtures, 'get.yaml')))
|
11
|
+
end
|
12
|
+
|
13
|
+
its('uuid') { should eq 'organization-uuid' }
|
14
|
+
its('username') { should eq 'UserName' }
|
15
|
+
its('name') { should eq 'FirstLast' }
|
16
|
+
its('first_name') { should eq 'First' }
|
17
|
+
its('last_name') { should eq 'Last' }
|
18
|
+
its('lang') { should eq 'en' }
|
19
|
+
its('street_address') { should eq 'Street Address' }
|
20
|
+
its('city') { should eq 'City' }
|
21
|
+
its('zip') { should eq 'Post Code' }
|
22
|
+
its('country') { should eq 'GB' }
|
23
|
+
its('email') { should eq 'username@example.com' }
|
24
|
+
its('phone') { should eq '+12.34567890' }
|
25
|
+
its('security_email') { should eq 'security@example.com' }
|
26
|
+
its('security_phone') { should eq '+23.45678901' }
|
27
|
+
its('security_email_validated') { should eq true }
|
28
|
+
its('security_email_validation_deadline') { should eq Time.new(2017, 11, 22, 17, 13, 33) }
|
29
|
+
end
|
30
|
+
end
|
@@ -0,0 +1,204 @@
|
|
1
|
+
# frozen_string_literal: true
|
2
|
+
|
3
|
+
describe GandiV5 do
|
4
|
+
let(:api_key) { ENV['GANDI_API_KEY'] }
|
5
|
+
|
6
|
+
it 'Has a version' do
|
7
|
+
expect(defined?(GandiV5::VERSION)).to eq 'constant'
|
8
|
+
expect(GandiV5::VERSION).to_not be_empty
|
9
|
+
end
|
10
|
+
|
11
|
+
describe 'Attributes' do
|
12
|
+
describe 'api_key' do
|
13
|
+
it '.api_key=' do
|
14
|
+
described_class.api_key = '1a'
|
15
|
+
expect(described_class.send(:api_key)).to eq '1a'
|
16
|
+
described_class.api_key = api_key
|
17
|
+
end
|
18
|
+
|
19
|
+
it 'is write only' do
|
20
|
+
expect { described_class.api_key }.to raise_error NoMethodError
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
describe 'Uses RestClient' do
|
26
|
+
%i[get delete].each do |method|
|
27
|
+
describe ":#{method}" do
|
28
|
+
it 'As JSON' do
|
29
|
+
response_data = { 'hello' => 'world' }
|
30
|
+
response = double RestClient::Response, body: response_data.to_json, headers: { content_type: 'application/json' }
|
31
|
+
expect(described_class).to receive(:prepare_headers)
|
32
|
+
expect(RestClient).to receive(method).with('url', hash_including(accept: 'application/json')).and_return(response)
|
33
|
+
expect(described_class.send(method, 'url', accept: 'application/json')).to eq response_data
|
34
|
+
end
|
35
|
+
|
36
|
+
it 'As text' do
|
37
|
+
response_data = 'Hello world!'
|
38
|
+
response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
|
39
|
+
expect(described_class).to receive(:prepare_headers)
|
40
|
+
expect(RestClient).to receive(method).with('url', hash_including(accept: 'text/plain')).and_return(response)
|
41
|
+
expect(described_class.send(method, 'url', accept: 'text/plain')).to eq response_data
|
42
|
+
end
|
43
|
+
|
44
|
+
it 'Passes request headers' do
|
45
|
+
expect(described_class).to receive(:prepare_headers)
|
46
|
+
expect(described_class).to receive(:parse_response)
|
47
|
+
expect(RestClient).to receive(method).with(anything, header: 'value')
|
48
|
+
expect(described_class.send(method, 'url', header: 'value')).to be_nil
|
49
|
+
end
|
50
|
+
|
51
|
+
it 'Adds authentication header' do
|
52
|
+
expect(RestClient).to receive(method).with(anything, hash_including(Authorization: 'Apikey abdce12345'))
|
53
|
+
expect(described_class).to receive(:parse_response)
|
54
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to be_nil
|
55
|
+
end
|
56
|
+
|
57
|
+
it 'Default accept header' do
|
58
|
+
expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
|
59
|
+
expect(described_class).to receive(:parse_response)
|
60
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/')).to be_nil
|
61
|
+
end
|
62
|
+
|
63
|
+
it 'Converts a 406 (bad request) exception' do
|
64
|
+
expect(RestClient).to receive(method).and_raise(RestClient::BadRequest)
|
65
|
+
expect(described_class).to receive(:handle_bad_request)
|
66
|
+
described_class.send(method, 'https://api.gandi.net/v5/')
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
70
|
+
|
71
|
+
%i[patch post put].each do |method|
|
72
|
+
describe ":#{method}" do
|
73
|
+
let(:payload) { '{"say":"hello world"}' }
|
74
|
+
|
75
|
+
it 'As JSON' do
|
76
|
+
response_data = { 'said' => 'hello world' }
|
77
|
+
response = double RestClient::Response, body: response_data.to_json, headers: { content_type: 'application/json' }
|
78
|
+
expect(described_class).to receive(:prepare_headers)
|
79
|
+
expect(RestClient).to receive(method).with('url', payload, hash_including(accept: 'application/json'))
|
80
|
+
.and_return(response)
|
81
|
+
expect(described_class.send(method, 'url', payload, accept: 'application/json')).to eq response_data
|
82
|
+
end
|
83
|
+
|
84
|
+
it 'As text' do
|
85
|
+
response_data = 'hello world'
|
86
|
+
response = double RestClient::Response, body: response_data, headers: { content_type: 'text/plain' }
|
87
|
+
expect(described_class).to receive(:prepare_headers)
|
88
|
+
expect(RestClient).to receive(method).with('url', payload, hash_including(accept: 'text/plain'))
|
89
|
+
.and_return(response)
|
90
|
+
expect(described_class.send(method, 'url', payload, accept: 'text/plain')).to eq response_data
|
91
|
+
end
|
92
|
+
|
93
|
+
it 'Passes payload' do
|
94
|
+
expect(described_class).to receive(:prepare_headers)
|
95
|
+
expect(described_class).to receive(:parse_response)
|
96
|
+
expect(RestClient).to receive(method).with(anything, payload, any_args)
|
97
|
+
expect(described_class.send(method, 'url', payload)).to be_nil
|
98
|
+
end
|
99
|
+
|
100
|
+
it 'Passes request headers' do
|
101
|
+
expect(described_class).to receive(:prepare_headers)
|
102
|
+
expect(described_class).to receive(:parse_response)
|
103
|
+
expect(RestClient).to receive(method).with(any_args, hash_including(header: 'value'))
|
104
|
+
expect(described_class.send(method, 'url', payload, header: 'value')).to be_nil
|
105
|
+
end
|
106
|
+
|
107
|
+
it 'Adds content type header' do
|
108
|
+
expect(RestClient).to receive(method).with(any_args, hash_including('content-type': 'application/json'))
|
109
|
+
expect(described_class).to receive(:parse_response)
|
110
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to be_nil
|
111
|
+
end
|
112
|
+
|
113
|
+
it 'Adds authentication header' do
|
114
|
+
expect(RestClient).to receive(method).with(any_args, hash_including(Authorization: 'Apikey abdce12345'))
|
115
|
+
expect(described_class).to receive(:parse_response)
|
116
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to be_nil
|
117
|
+
end
|
118
|
+
|
119
|
+
it 'Default accept header' do
|
120
|
+
expect(RestClient).to receive(method).with(any_args, hash_including(accept: 'application/json'))
|
121
|
+
expect(described_class).to receive(:parse_response)
|
122
|
+
expect(described_class.send(method, 'https://api.gandi.net/v5/', payload)).to be_nil
|
123
|
+
end
|
124
|
+
|
125
|
+
it 'Converts a 406 (bad request) exception' do
|
126
|
+
expect(RestClient).to receive(method).and_raise(RestClient::BadRequest)
|
127
|
+
expect(described_class).to receive(:handle_bad_request)
|
128
|
+
described_class.send(method, 'https://api.gandi.net/v5/', payload)
|
129
|
+
end
|
130
|
+
end
|
131
|
+
end
|
132
|
+
end
|
133
|
+
|
134
|
+
describe 'Generates correct authorisation header' do
|
135
|
+
it 'When requesting from main V5 API' do
|
136
|
+
expect(described_class.send(:authorisation_header, 'https://api.gandi.net/v5/example'))
|
137
|
+
.to eq(Authorization: "Apikey #{api_key}")
|
138
|
+
end
|
139
|
+
|
140
|
+
it 'When requesting from main LiveDNS V5 API' do
|
141
|
+
expect(described_class.send(:authorisation_header, 'https://dns.api.gandi.net/api/v5/example'))
|
142
|
+
.to eq('X-Api-Key': api_key)
|
143
|
+
end
|
144
|
+
|
145
|
+
it 'Raises ArgumentError when requesting an unknown url' do
|
146
|
+
expect { described_class.send(:authorisation_header, 'https://unknown.example.com') }
|
147
|
+
.to raise_error ArgumentError, 'Don\'t know how to authorise for url: https://unknown.example.com'
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
describe 'Parses response' do
|
152
|
+
it 'Text' do
|
153
|
+
response = double RestClient::Response, body: 'Hello World', headers: { content_type: 'text/plain' }
|
154
|
+
expect(described_class.send(:parse_response, response)).to eq 'Hello World'
|
155
|
+
end
|
156
|
+
|
157
|
+
describe 'JSON' do
|
158
|
+
it 'Response is parsable' do
|
159
|
+
response = double RestClient::Response, body: '{"hello":"world"}', headers: { content_type: 'application/json' }
|
160
|
+
expect(described_class.send(:parse_response, response)).to eq('hello' => 'world')
|
161
|
+
end
|
162
|
+
|
163
|
+
it 'Response is an error message' do
|
164
|
+
response = double RestClient::Response, body: '{"status":"error"}', headers: { content_type: 'application/json' }
|
165
|
+
expect { described_class.send(:parse_response, response) }.to raise_error GandiV5::Error::GandiError
|
166
|
+
end
|
167
|
+
end
|
168
|
+
|
169
|
+
it 'Raises ArgumentError when requesting an unknown parser' do
|
170
|
+
response = double RestClient::Response, headers: { content_type: 'unknown/unknown' }
|
171
|
+
expect { described_class.send(:parse_response, response) }
|
172
|
+
.to raise_error ArgumentError, 'Don\'t know how to parse a unknown/unknown response'
|
173
|
+
end
|
174
|
+
end
|
175
|
+
|
176
|
+
describe 'Handles HTTP error 406 (Bad Request)' do
|
177
|
+
it 'Passes on exception if body is not JSON' do
|
178
|
+
response = double RestClient::Response,
|
179
|
+
code: '406',
|
180
|
+
body: 'Something went wrong!'
|
181
|
+
exception = RestClient::BadRequest.new response
|
182
|
+
expect { described_class.send(:handle_bad_request, exception) }
|
183
|
+
.to raise_error exception
|
184
|
+
end
|
185
|
+
|
186
|
+
it 'Passes on exception if body is JSON but not an error hash' do
|
187
|
+
response = double RestClient::Response,
|
188
|
+
code: '406',
|
189
|
+
body: '{"status":"not error"}'
|
190
|
+
exception = RestClient::BadRequest.new response
|
191
|
+
expect { described_class.send(:handle_bad_request, exception) }
|
192
|
+
.to raise_error RestClient::BadRequest
|
193
|
+
end
|
194
|
+
|
195
|
+
it 'Raises GandiV5::Error::GandiError if response is an error hash' do
|
196
|
+
response = double RestClient::Response,
|
197
|
+
code: '406',
|
198
|
+
body: '{"status":"error","errors":[{"name":"field","description":"message"}]}'
|
199
|
+
exception = RestClient::BadRequest.new response
|
200
|
+
expect { described_class.send(:handle_bad_request, exception) }
|
201
|
+
.to raise_error GandiV5::Error::GandiError, 'field: message'
|
202
|
+
end
|
203
|
+
end
|
204
|
+
end
|