esgob 0.0.1 → 0.0.2

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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: c771929d5f34833c2a7b647e05c11686e0ecd9db
4
- data.tar.gz: c0c648e1341855edd956c83d29b373e107e8db8e
3
+ metadata.gz: f029cb699d12ea2f9ebc3d62538b301ac22c4ce2
4
+ data.tar.gz: 878e694007c2d41a71ed940fc5f7cf9215a4ad23
5
5
  SHA512:
6
- metadata.gz: 6650464bd90d58172139131df815d59f7b8601c9f75cd5a2b214ed9bded0b393e81ff4252e782f03ee10cfce2679a927bcfeba9dd655acb81740269c976a556b
7
- data.tar.gz: 35b9700a1ec0f86df74720e404ea5ebb5ee08e33ecb0a7885d1f8cb5874d369d68a7af7029dd3e8d4e263259af0b2941c900a862be3e4f2edb3e62b8f484c07e
6
+ metadata.gz: 48559b9d9ac0b9a5def0e60cd6ed4242d90e28a2ec617d71fb673c0fedadd4e6aee7a32a81c6db88d649d539a59df04ab8e83e8317c5bfe65f442a13929159f5
7
+ data.tar.gz: 5ff773471a48fc33e975ae314aec3519f9d7422b8526301bebf66f5328955f886bf9c9a8d0fb03838766d2321df230988108810aca80091a00a9d17079945202
data/.gitignore CHANGED
@@ -11,4 +11,5 @@
11
11
  *.so
12
12
  *.o
13
13
  *.a
14
+ .ruby-version
14
15
  mkmf.log
data/README.md CHANGED
@@ -52,12 +52,12 @@ Here is an example of what can be done in an IRB session:
52
52
 
53
53
  $ irb -resgob
54
54
  irb(main):001:0> esgob = Esgob::Client.new
55
- => #<Esgob::Client:0x007fd2e3b13420>
55
+ => #<Esgob::Client account=myacct>
56
56
  irb(main):002:0> esgob.domains_slaves_list
57
57
  => {"example.com"=>"192.168.0.1", "example.uk"=>"192.168.0.1"}
58
58
  irb(main):003:0> esgob.domains_slaves_list.keys
59
59
  => ["example.com", "example.uk"]
60
- irb(main):004:0>
60
+ irb(main):004:0>
61
61
 
62
62
  See the [API documentation] for full details.
63
63
 
data/bin/esgob ADDED
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ $:.unshift File.expand_path("../../lib", __FILE__)
4
+
5
+ require "rubygems"
6
+ require "esgob"
7
+
8
+ Esgob::CLI.start
data/esgob.gemspec CHANGED
@@ -4,35 +4,37 @@ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
4
  require 'esgob/version'
5
5
 
6
6
  Gem::Specification.new do |spec|
7
- spec.name = "esgob"
7
+ spec.name = 'esgob'
8
8
  spec.version = Esgob::VERSION
9
- spec.authors = ["Nicholas Humfrey"]
10
- spec.email = ["njh@aelius.com"]
11
- spec.summary = %q{Client library for talking to the Esgob anycast DNS API.}
12
- #spec.description = %q{TODO: Write a longer description. Optional.}
13
- spec.homepage = ""
14
- spec.license = "MIT"
9
+ spec.authors = ['Nicholas Humfrey']
10
+ spec.email = ['njh@aelius.com']
11
+ spec.summary = 'Client library for talking to the Esgob anycast DNS API.'
12
+ # spec.description = 'TODO: Write a longer description. Optional.'
13
+ spec.homepage = 'http://github.com/njh/ruby-esgob'
14
+ spec.license = 'MIT'
15
15
 
16
16
  spec.files = `git ls-files -z`.split("\x0")
17
17
  spec.executables = spec.files.grep(%r{^bin/}) { |f| File.basename(f) }
18
18
  spec.test_files = spec.files.grep(%r{^(test|spec|features)/})
19
- spec.require_paths = ["lib"]
19
+ spec.require_paths = ['lib']
20
20
 
21
-
22
- spec.add_dependency "json", "~> 1.8"
21
+ spec.add_dependency 'json', '~> 1.8'
22
+ spec.add_dependency 'thor', '~> 0.19.1'
23
23
 
24
24
  if Gem.ruby_version > Gem::Version.new('1.9')
25
25
  spec.add_development_dependency 'bundler', '>= 1.5.0'
26
26
  spec.add_development_dependency 'rake', '>= 0.10.0'
27
27
  spec.add_development_dependency 'yard', '>= 0.8.0'
28
28
  spec.add_development_dependency 'fakeweb', '~> 1.3.0'
29
+ spec.add_development_dependency 'mocha', '~> 1.1.0'
29
30
  spec.add_development_dependency 'simplecov'
30
31
  elsif Gem.ruby_version > Gem::Version.new('1.8')
31
32
  spec.add_development_dependency 'bundler', '>= 1.1.0'
32
33
  spec.add_development_dependency 'rake', '~> 0.9.0'
33
34
  spec.add_development_dependency 'yard', '~> 0.8.0'
34
- spec.add_development_dependency 'minitest', '~> 5.5.0'
35
35
  spec.add_development_dependency 'fakeweb', '~> 1.3.0'
36
+ spec.add_development_dependency 'minitest', '~> 5.5.0'
37
+ spec.add_development_dependency 'mocha', '~> 1.1.0'
36
38
  else
37
39
  raise "#{Gem.ruby_version} is an unsupported version of ruby"
38
40
  end
data/lib/esgob/cli.rb ADDED
@@ -0,0 +1,134 @@
1
+ require "thor"
2
+
3
+ class Esgob::CLI < Thor
4
+ class_option :account,
5
+ :type => :string,
6
+ :aliases => '-a',
7
+ :banner => 'Account Name'
8
+
9
+ class_option :key,
10
+ :type => :string,
11
+ :aliases => '-k',
12
+ :banner => 'API Key'
13
+
14
+ class_option :verbose,
15
+ :type => :boolean,
16
+ :default => false,
17
+ :aliases => '-v'
18
+
19
+ def self.start(args = ARGV, config = {})
20
+ config[:shell] ||= Thor::Base.shell.new
21
+ begin
22
+ super(args, config)
23
+ rescue Esgob::ServerError => err
24
+ $stderr.puts config[:shell].set_color("=> Error: #{err.message} [#{err.code}]", :red, :bold)
25
+ end
26
+ end
27
+
28
+ desc "account", "Display account info"
29
+ def account
30
+ client.accounts_get.each_pair do |k, v|
31
+ say sprintf("%8s: %s\n", k, v)
32
+ end
33
+ end
34
+
35
+ desc "domains", "List all domains"
36
+ def domains
37
+ print_table(
38
+ [['Domain', 'Type']] +
39
+ [['------', '----']] +
40
+ client.domains_list.map { |h| [h[:domain], h[:type]] }
41
+ )
42
+ end
43
+
44
+ desc "slaves", "List slave domains"
45
+ def slaves
46
+ print_table(
47
+ [['Domain', 'Master IP']] +
48
+ [['------', '---------']] +
49
+ client.domains_slaves_list.to_a
50
+ )
51
+ end
52
+
53
+ desc "slaves-add DOMAIN MASTERIP", "Add new slave domain"
54
+ def slaves_add(domain, masterip)
55
+ check_action do
56
+ client.domains_slaves_add(domain, masterip)
57
+ end
58
+ end
59
+
60
+ desc "slaves-delete DOMAIN", "Delete a slave domain"
61
+ def slaves_delete(domain)
62
+ check_action do
63
+ client.domains_slaves_delete(domain)
64
+ end
65
+ end
66
+
67
+ desc "slaves-transfer DOMAIN",
68
+ "Force transfer from master of a slave domain"
69
+ def slaves_transfer(domain)
70
+ check_action do
71
+ client.domains_slaves_forcetransfer(domain)
72
+ end
73
+ end
74
+
75
+ desc "slaves-update DOMAIN MASTERIP",
76
+ "Updates the master IP of a slave domain"
77
+ def slaves_update(domain, masterip)
78
+ check_action do
79
+ client.domains_slaves_updatemasterip(domain, masterip)
80
+ end
81
+ end
82
+
83
+ desc "slaves-sync FILE MASTERIP",
84
+ "Synronises list of slave domains in a file"
85
+ def slaves_sync(filename, masterip)
86
+ domains = []
87
+ File.foreach(filename) do |line|
88
+ domains << line.strip.split(/\s+/).first
89
+ end
90
+
91
+ check_action do
92
+ client.domains_slaves_sync(domains, masterip)
93
+ end
94
+ end
95
+
96
+ desc "soacheck DOMAIN",
97
+ "Fetch domain SOA serial number for all nodes"
98
+ def soacheck(domain)
99
+ response = client.domains_tools_soacheck(domain)
100
+ print_table(
101
+ [['Identifier', 'Type', 'Country', 'SOA', 'Response']] +
102
+ [['----------', '----', '-------', '---', '--------']] +
103
+ response[:responses][:masters].map do |node|
104
+ [node[:ip], "master", '', node[:soa], node[:response]]
105
+ end +
106
+ response[:responses][:anycastnodes].map do |node|
107
+ [node[:ref], 'anycast', node[:country], node[:soa], node[:response]]
108
+ end
109
+ )
110
+ end
111
+
112
+ desc "version", "Show Esgob Ruby Client version"
113
+ def version
114
+ say "Esgob Ruby Client version #{Esgob::VERSION}"
115
+ end
116
+ map "--version" => "version"
117
+
118
+ private ######################################################################
119
+
120
+ def client
121
+ @client ||= Esgob::Client.new(options[:account], options[:key])
122
+ end
123
+
124
+ def check_action
125
+ results = yield
126
+ results = [results] unless results.is_a?(Array)
127
+ results.each do |result|
128
+ unless result[:action].nil?
129
+ say "#{result[:domain]} " + set_color("=> #{result[:action]}", :green, :bold)
130
+ end
131
+ end
132
+ end
133
+
134
+ end
data/lib/esgob/client.rb CHANGED
@@ -10,19 +10,27 @@ class Esgob::Client
10
10
  DEFAULT_API_ENDPOINT = "https://api.esgob.com/1.0/".freeze
11
11
 
12
12
  def initialize(*args)
13
- if args.first.kind_of?(Hash)
14
- args.first.each_pair { |k,v| send("#{k}=", v) }
13
+ if args.first.is_a?(Hash)
14
+ args.first.each_pair { |k, v| send("#{k}=", v) }
15
15
  else
16
16
  self.account = args[0]
17
17
  self.api_key = args[1]
18
18
  end
19
19
 
20
+ self.account ||= ENV['ESGOB_ACCOUNT']
21
+ self.api_key ||= ENV['ESGOB_API_KEY']
20
22
  self.endpoint ||= DEFAULT_API_ENDPOINT
21
- self.account ||= ENV['ESGOB_ACCOUNT']
22
- self.api_key ||= ENV['ESGOB_API_KEY']
23
+
24
+ if account.nil? or account.empty?
25
+ raise(ArgumentError, "No account name configured for Esgob")
26
+ end
27
+
28
+ if api_key.nil? or api_key.empty?
29
+ raise(ArgumentError, "No API key configured for Esgob")
30
+ end
23
31
  end
24
32
 
25
- def call(function_name, arguments={})
33
+ def call(function_name, arguments = {})
26
34
  uri = URI(endpoint + function_name)
27
35
  uri.query = build_query(default_arguments.merge(arguments))
28
36
 
@@ -32,22 +40,28 @@ class Esgob::Client
32
40
  http.request(req)
33
41
  end
34
42
 
35
- if res.code =~ /^2/
36
- if res.content_type == 'application/json'
37
- symbolize_keys! JSON.parse(res.body)
43
+ if res.content_type == 'application/json'
44
+ data = symbolize_keys! JSON.parse(res.body)
45
+ if data.key?(:error)
46
+ raise Esgob::ServerError.new(
47
+ data[:error][:message],
48
+ data[:error][:code].to_s
49
+ )
50
+ elsif res.code !~ /^2/
51
+ raise Esgob::ServerError.new(res.message, res.code)
38
52
  else
39
- raise "HTTP response from ESGOB is not of type JSON"
53
+ return data
40
54
  end
41
55
  else
42
- # The badly named method throws an Net::HTTP exception
43
- res.value
56
+ raise "HTTP response from ESGOB is not of type JSON"
44
57
  end
45
-
46
58
  end
47
59
 
48
60
  # Return account status; credit balance, etc
49
61
  def accounts_get
50
- call('accounts.get')
62
+ account = call('accounts.get')
63
+ account[:added] = Time.at(account[:added]) if account[:added].is_a?(Fixnum)
64
+ account
51
65
  end
52
66
 
53
67
  # Returns all hosted domains
@@ -56,7 +70,7 @@ class Esgob::Client
56
70
  end
57
71
 
58
72
  # Returns all hosted slave domains as a hash
59
- #
73
+ #
60
74
  def domains_slaves_list
61
75
  Hash[
62
76
  call('domains.slaves.list')[:domains].map do |item|
@@ -67,32 +81,44 @@ class Esgob::Client
67
81
 
68
82
  # Adds a new slave domain
69
83
  def domains_slaves_add(domain, masterip)
70
- call('domains.slaves.add', :domain => domain, :masterip => masterip)
84
+ result = call('domains.slaves.add', :domain => domain, :masterip => masterip)
85
+ result[:domain] ||= domain
86
+ result
71
87
  end
72
88
 
73
89
  # Deletes a slave domain
74
90
  def domains_slaves_delete(domain)
75
- call('domains.slaves.delete', :domain => domain)
91
+ result = call('domains.slaves.delete', :domain => domain)
92
+ result[:domain] ||= domain
93
+ result
76
94
  end
77
95
 
78
96
  # Force AXFR / transfer from master of a slave domain
79
97
  def domains_slaves_forcetransfer(domain)
80
- call('domains.slaves.forcetransfer', :domain => domain)
98
+ result = call('domains.slaves.forcetransfer', :domain => domain)
99
+ result[:domain] ||= domain
100
+ result
81
101
  end
82
102
 
83
103
  # Updates the master IP of a slave domain
84
104
  def domains_slaves_updatemasterip(domain, masterip)
85
- call('domains.slaves.updatemasterip', :domain => domain, :masterip => masterip)
105
+ result = call('domains.slaves.updatemasterip', :domain => domain, :masterip => masterip)
106
+ result[:domain] ||= domain
107
+ result
86
108
  end
87
109
 
88
110
  # Add a host allowed to AXFR out
89
111
  def domains_slaves_axfrout_add(domain, axfrip)
90
- call('domains.slaves.axfrout.add', :domain => domain, :axfrip => axfrip)
112
+ result = call('domains.slaves.axfrout.add', :domain => domain, :axfrip => axfrip)
113
+ result[:domain] ||= domain
114
+ result
91
115
  end
92
116
 
93
117
  # Account Delete a host allowed to AXFR out
94
118
  def domains_slaves_axfrout_delete(domain, axfrip)
95
- call('domains.slaves.axfrout.delete', :domain => domain, :axfrip => axfrip)
119
+ result = call('domains.slaves.axfrout.delete', :domain => domain, :axfrip => axfrip)
120
+ result[:domain] ||= domain
121
+ result
96
122
  end
97
123
 
98
124
  # Retrieve the domain SOA serial number from the master and each anycast node
@@ -100,6 +126,44 @@ class Esgob::Client
100
126
  call('domains.tools.soacheck', :domain => domain)
101
127
  end
102
128
 
129
+ # Given a list of domains and a master IP, add and delete domains
130
+ # so that the Esgob account matches the local list
131
+ def domains_slaves_sync(domains, masterip)
132
+ existing_domains = domains_slaves_list
133
+
134
+ # Add any missing domains
135
+ responses = []
136
+ domains.each do |domain|
137
+ unless existing_domains.include?(domain)
138
+ response = domains_slaves_add(domain, masterip)
139
+ response[:domain] ||= domain
140
+ responses << response
141
+ end
142
+ end
143
+
144
+ # Now check the existing domains
145
+ existing_domains.keys.sort.each do |domain|
146
+ if domains.include?(domain)
147
+ # Update the masterip if it isn't correct
148
+ if existing_domains[domain] != masterip
149
+ response = domains_slaves_updatemasterip(domain, masterip)
150
+ response[:domain] ||= domain
151
+ responses << response
152
+ end
153
+ else
154
+ # Delete domain; not on list
155
+ response = domains_slaves_delete(domain)
156
+ response[:domain] ||= domain
157
+ responses << response
158
+ end
159
+ end
160
+
161
+ responses
162
+ end
163
+
164
+ def inspect
165
+ "\#<#{self.class} account=#{@account}>"
166
+ end
103
167
 
104
168
  protected
105
169
 
@@ -111,10 +175,10 @@ class Esgob::Client
111
175
  when Hash
112
176
  symbolize_keys!(hash[ks])
113
177
  when Array
114
- hash[ks].each {|item| symbolize_keys!(item) if item.kind_of?(Hash)}
178
+ hash[ks].each { |item| symbolize_keys!(item) if item.is_a?(Hash) }
115
179
  end
116
180
  end
117
- return hash
181
+ hash
118
182
  end
119
183
 
120
184
  def default_arguments
@@ -126,8 +190,8 @@ class Esgob::Client
126
190
  end
127
191
 
128
192
  def build_query(hash)
129
- hash.keys.sort{|a,b| a.to_s <=> b.to_s}.map { |key|
130
- URI::escape(key.to_s) + '=' + URI::escape(hash[key].to_s)
131
- }.join('&')
193
+ hash.keys.sort { |a, b| a.to_s <=> b.to_s }.map do |key|
194
+ URI.escape(key.to_s) + '=' + URI.escape(hash[key].to_s)
195
+ end.join('&')
132
196
  end
133
197
  end
data/lib/esgob/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module Esgob
2
- VERSION = "0.0.1"
2
+ VERSION = "0.0.2"
3
3
  end
data/lib/esgob.rb CHANGED
@@ -1,4 +1,14 @@
1
1
  module Esgob
2
2
  autoload :Client, 'esgob/client'
3
- autoload :Version, 'esgob/version'
3
+ autoload :CLI, 'esgob/cli'
4
+ autoload :VERSION, 'esgob/version'
5
+
6
+ class ServerError < StandardError
7
+ attr_reader :code
8
+
9
+ def initialize(message, code = nil)
10
+ super message
11
+ @code = code
12
+ end
13
+ end
4
14
  end
@@ -0,0 +1,129 @@
1
+ $:.unshift(File.dirname(__FILE__))
2
+
3
+ require 'test_helper'
4
+ require 'esgob'
5
+
6
+ class TestCLI < MiniTest::Unit::TestCase
7
+ def setup
8
+ # Run before each test
9
+ FakeWeb.clean_registry
10
+
11
+ @client = Esgob::Client.new('acct', 'xxxx')
12
+ Esgob::Client.stubs(:new).returns(@client)
13
+
14
+ ENV['THOR_SHELL'] = 'Basic'
15
+ end
16
+
17
+ def teardown
18
+ # Reset environment variables after each test
19
+ ENV.delete('ESGOB_ACCOUNT')
20
+ ENV.delete('ESGOB_API_KEY')
21
+ end
22
+
23
+ def test_account
24
+ register_fixture('accounts.get')
25
+
26
+ output = capture(:stdout) { Esgob::CLI.start(%w(account)) }
27
+ assert_match " id: xyz\n", output
28
+ assert_match " name: Person Name\n", output
29
+ assert_match " credits: 48\n", output
30
+ end
31
+
32
+ def test_account_error
33
+ FakeWeb.register_uri(
34
+ :get, %r{^https?://api\.esgob\.com(:443)?/},
35
+ :status => ['401', 'UNAUTHORIZED'],
36
+ :content_type => 'application/json',
37
+ :body => read_fixture(:code_1003)
38
+ )
39
+
40
+ output = capture(:stderr) { Esgob::CLI.start(%w(account)) }
41
+ assert_equal "=> Error: Account and API key combination not valid [1003]\n", output
42
+ end
43
+
44
+ def test_domains
45
+ register_fixture('domains.list')
46
+
47
+ output = capture(:stdout) { Esgob::CLI.start(%w(domains)) }
48
+ assert_match "Domain Type\n", output
49
+ assert_match "------ ----\n", output
50
+ assert_match "example.com slave\n", output
51
+ assert_match "example.uk slave\n", output
52
+ end
53
+
54
+ def test_slaves
55
+ register_fixture('domains.slaves.list')
56
+
57
+ output = capture(:stdout) { Esgob::CLI.start(%w(slaves)) }
58
+ assert_match "Domain Master IP\n", output
59
+ assert_match "------ ---------\n", output
60
+ assert_match "example.com 195.177.253.166\n", output
61
+ assert_match "example.uk 195.177.253.166\n", output
62
+ end
63
+
64
+ def test_slaves_add
65
+ register_fixture('domains.slaves.add')
66
+
67
+ output = capture(:stdout) { Esgob::CLI.start(%w(slaves-add example.org 195.177.253.166)) }
68
+ assert_equal "example.org => domain added\n", output
69
+ end
70
+
71
+ def test_slaves_delete
72
+ register_fixture('domains.slaves.delete')
73
+
74
+ output = capture(:stdout) { Esgob::CLI.start(%w(slaves-delete example.org)) }
75
+ assert_equal "example.org => domain deleted\n", output
76
+ end
77
+
78
+ def test_slaves_delete_error
79
+ FakeWeb.register_uri(
80
+ :get, %r{^https?://api\.esgob\.com(:443)?/},
81
+ :status => ['403', 'FORBIDDEN'],
82
+ :content_type => 'application/json',
83
+ :body => read_fixture(:code_2007)
84
+ )
85
+
86
+ output = capture(:stderr) { Esgob::CLI.start(%w(slaves-delete example.com)) }
87
+ assert_equal "=> Error: Domain is not present in your account [2007]\n", output
88
+ end
89
+
90
+ def test_slaves_transfer
91
+ register_fixture('domains.slaves.forcetransfer')
92
+
93
+ output = capture(:stdout) { Esgob::CLI.start(%w(slaves-transfer example.org)) }
94
+ assert_equal "example.org => Domain AXFR requested from master\n", output
95
+ end
96
+
97
+ def test_slaves_update
98
+ register_fixture('domains.slaves.updatemasterip')
99
+
100
+ output = capture(:stdout) { Esgob::CLI.start(%w(slaves-update example.org 195.177.253.167)) }
101
+ assert_equal "example.org => domain master IP updated\n", output
102
+ end
103
+
104
+ def test_slaves_sync
105
+ @client.expects(:domains_slaves_list).with().returns('a.com' => '195.177.253.169', 'b.com' => '195.177.253.169')
106
+ @client.expects(:domains_slaves_delete).with('a.com').returns(:action => 'domain deleted')
107
+ @client.expects(:domains_slaves_add).with('c.com', '195.177.253.169').returns(:action => 'domain added')
108
+
109
+ output = capture(:stdout) { Esgob::CLI.start(['slaves-sync', fixture_path('sync-domain-list.txt'), '195.177.253.169']) }
110
+ assert_match "a.com => domain deleted\n", output
111
+ assert_match "c.com => domain added\n", output
112
+ end
113
+
114
+ def test_soacheck
115
+ register_fixture('domains.tools.soacheck')
116
+
117
+ output = capture(:stdout) { Esgob::CLI.start(%w(soacheck example.org)) }
118
+ assert_match "Identifier Type Country SOA Response\n", output
119
+ assert_match "---------- ---- ------- --- --------\n", output
120
+ assert_match "195.177.253.167 master fail\n", output
121
+ assert_match "4f31ad80 anycast gb fail\n", output
122
+ assert_match "fgej72a1 anycast us fail\n", output
123
+ end
124
+
125
+ def test_version
126
+ assert_match /Esgob Ruby Client version \d+.\d+\.\d+/,
127
+ capture(:stdout) { Esgob::CLI.start(%w(version)) }
128
+ end
129
+ end
@@ -44,6 +44,20 @@ class TestClient < MiniTest::Unit::TestCase
44
44
  assert_equal 'http://api.example.com/', client.endpoint
45
45
  end
46
46
 
47
+ def test_new_client_with_no_account
48
+ ENV.delete('ESGOB_ACCOUNT')
49
+ assert_raises(ArgumentError) do
50
+ Esgob::Client.new(nil, 'mykey')
51
+ end
52
+ end
53
+
54
+ def test_new_client_with_no_api_key
55
+ ENV.delete('ESGOB_API_KEY')
56
+ assert_raises(ArgumentError) do
57
+ Esgob::Client.new('acct', nil)
58
+ end
59
+ end
60
+
47
61
  def test_call_with_no_parameters
48
62
  register_fixture('accounts.get')
49
63
  response = @client.call('accounts.get')
@@ -53,7 +67,13 @@ class TestClient < MiniTest::Unit::TestCase
53
67
  FakeWeb.last_request.path
54
68
  )
55
69
  assert_equal(
56
- {:credits=>48, :users=>[], :added=>1422792434, :id=>"xyz", :name=>"Person Name"},
70
+ {
71
+ :credits => 48,
72
+ :users => [],
73
+ :added => 1422792434,
74
+ :id => 'xyz',
75
+ :name => 'Person Name'
76
+ },
57
77
  response
58
78
  )
59
79
  end
@@ -79,27 +99,38 @@ class TestClient < MiniTest::Unit::TestCase
79
99
  end
80
100
 
81
101
  def test_call_with_404_error
82
- assert_raises(Net::HTTPServerException) do
83
- FakeWeb.register_uri(
84
- :get, %r[^https?://api\.esgob\.com(:443)?/],
85
- :status => ["404", "Not Found"],
86
- :content_type => "application/json",
87
- :body => '{}'
88
- )
89
- response = @client.call('accounts.get')
90
- end
102
+ FakeWeb.register_uri(
103
+ :get, %r{^https?://api\.esgob\.com(:443)?/},
104
+ :status => ['404', 'Not Found'],
105
+ :content_type => 'application/json',
106
+ :body => '{}'
107
+ )
108
+ err = assert_raises(Esgob::ServerError) { @client.call('accounts.get') }
109
+ assert_equal 'Not Found', err.message
110
+ assert_equal '404', err.code
91
111
  end
92
112
 
93
113
  def test_call_with_non_json_reponse
94
- assert_raises(RuntimeError) do
95
- FakeWeb.register_uri(
96
- :get, %r[^https?://api\.esgob\.com(:443)?/],
97
- :status => ["200", "OK"],
98
- :content_type => "text/plain",
99
- :body => 'This is plain text'
100
- )
101
- response = @client.call('accounts.get')
102
- end
114
+ FakeWeb.register_uri(
115
+ :get, %r{^https?://api\.esgob\.com(:443)?/},
116
+ :status => ['200', 'OK'],
117
+ :content_type => 'text/plain',
118
+ :body => 'This is plain text'
119
+ )
120
+ err = assert_raises(RuntimeError) { @client.call('accounts.get') }
121
+ assert_equal 'HTTP response from ESGOB is not of type JSON', err.message
122
+ end
123
+
124
+ def test_call_domain_not_present
125
+ FakeWeb.register_uri(
126
+ :get, %r{^https?://api\.esgob\.com(:443)?/},
127
+ :status => ['403', 'FORBIDDEN'],
128
+ :content_type => 'application/json',
129
+ :body => read_fixture(:code_2007)
130
+ )
131
+ err = assert_raises(Esgob::ServerError) { @client.call('domains.slaves.delete', :domain => 'example.org') }
132
+ assert_equal 'Domain is not present in your account', err.message
133
+ assert_equal '2007', err.code
103
134
  end
104
135
 
105
136
  def test_accounts_get
@@ -111,7 +142,13 @@ class TestClient < MiniTest::Unit::TestCase
111
142
  FakeWeb.last_request.path
112
143
  )
113
144
  assert_equal(
114
- {:credits=>48, :users=>[], :added=>1422792434, :id=>"xyz", :name=>"Person Name"},
145
+ {
146
+ :credits => 48,
147
+ :users => [],
148
+ :added => Time.parse('2015-02-01 12:07:14 +0000'),
149
+ :id => 'xyz',
150
+ :name => 'Person Name'
151
+ },
115
152
  response
116
153
  )
117
154
  end
@@ -126,8 +163,8 @@ class TestClient < MiniTest::Unit::TestCase
126
163
  )
127
164
  assert_equal(
128
165
  [
129
- {:domain => "example.com", :type => "slave"},
130
- {:domain => "example.uk", :type => "slave"}
166
+ { :domain => 'example.com', :type => 'slave' },
167
+ { :domain => 'example.uk', :type => 'slave' }
131
168
  ],
132
169
  response
133
170
  )
@@ -142,7 +179,7 @@ class TestClient < MiniTest::Unit::TestCase
142
179
  FakeWeb.last_request.path
143
180
  )
144
181
  assert_equal(
145
- {"example.com"=>"195.177.253.166", "example.uk"=>"195.177.253.166"},
182
+ { 'example.com' => '195.177.253.166', 'example.uk' => '195.177.253.166' },
146
183
  response
147
184
  )
148
185
  end
@@ -155,7 +192,7 @@ class TestClient < MiniTest::Unit::TestCase
155
192
  '/1.0/domains.slaves.add?account=acct&domain=example.org&f=json&key=xxxx&masterip=195.177.253.166',
156
193
  FakeWeb.last_request.path
157
194
  )
158
- assert_equal({:action=>"domain added"}, response)
195
+ assert_equal({ :action => 'domain added', :domain => 'example.org' }, response)
159
196
  end
160
197
 
161
198
  def test_domains_slaves_delete
@@ -166,7 +203,7 @@ class TestClient < MiniTest::Unit::TestCase
166
203
  '/1.0/domains.slaves.delete?account=acct&domain=example.org&f=json&key=xxxx',
167
204
  FakeWeb.last_request.path
168
205
  )
169
- assert_equal({:action=>"domain deleted"}, response)
206
+ assert_equal({ :action => 'domain deleted', :domain => 'example.org' }, response)
170
207
  end
171
208
 
172
209
  def test_domains_slaves_forcetransfer
@@ -177,7 +214,7 @@ class TestClient < MiniTest::Unit::TestCase
177
214
  '/1.0/domains.slaves.forcetransfer?account=acct&domain=example.org&f=json&key=xxxx',
178
215
  FakeWeb.last_request.path
179
216
  )
180
- assert_equal({:action=>"Domain AXFR requested from master"}, response)
217
+ assert_equal({ :action => 'Domain AXFR requested from master', :domain => 'example.org' }, response)
181
218
  end
182
219
 
183
220
  def test_domains_slaves_updatemasterip
@@ -188,7 +225,7 @@ class TestClient < MiniTest::Unit::TestCase
188
225
  '/1.0/domains.slaves.updatemasterip?account=acct&domain=example.org&f=json&key=xxxx&masterip=195.177.253.167',
189
226
  FakeWeb.last_request.path
190
227
  )
191
- assert_equal({:action=>"domain master IP updated"}, response)
228
+ assert_equal({ :action => 'domain master IP updated', :domain => 'example.org' }, response)
192
229
  end
193
230
 
194
231
  def test_domains_slaves_axfrout_add
@@ -199,7 +236,7 @@ class TestClient < MiniTest::Unit::TestCase
199
236
  '/1.0/domains.slaves.axfrout.add?account=acct&axfrip=195.177.253.1&domain=example.org&f=json&key=xxxx',
200
237
  FakeWeb.last_request.path
201
238
  )
202
- assert_equal({:action=>"domain AXFR out IPs updated"}, response)
239
+ assert_equal({ :action => 'domain AXFR out IPs updated', :domain => 'example.org' }, response)
203
240
  end
204
241
 
205
242
  def test_domains_slaves_axfrout_delete
@@ -210,7 +247,7 @@ class TestClient < MiniTest::Unit::TestCase
210
247
  '/1.0/domains.slaves.axfrout.delete?account=acct&axfrip=195.177.253.1&domain=example.org&f=json&key=xxxx',
211
248
  FakeWeb.last_request.path
212
249
  )
213
- assert_equal({:action=>"domain AXFR out IPs updated"}, response)
250
+ assert_equal({ :action => 'domain AXFR out IPs updated', :domain => 'example.org' }, response)
214
251
  end
215
252
 
216
253
  def test_domains_tools_soacheck
@@ -225,4 +262,56 @@ class TestClient < MiniTest::Unit::TestCase
225
262
  refute_empty(response[:responses])
226
263
  end
227
264
 
265
+ def test_domains_slaves_sync_noop
266
+ @client.expects(:domains_slaves_list).with().returns(
267
+ 'a.com' => '195.177.253.1', 'b.com' => '195.177.253.1'
268
+ )
269
+
270
+ responses = @client.domains_slaves_sync(['a.com', 'b.com'], '195.177.253.1')
271
+ assert_equal [], responses
272
+ end
273
+
274
+ def test_domains_slaves_sync_add_only
275
+ @client.expects(:domains_slaves_list).with().returns({})
276
+ @client.expects(:domains_slaves_add).with('a.com', '195.177.253.1').returns(:action => 'domain added')
277
+ @client.expects(:domains_slaves_add).with('b.com', '195.177.253.1').returns(:action => 'domain added')
278
+
279
+ responses = @client.domains_slaves_sync(['a.com', 'b.com'], '195.177.253.1')
280
+ assert_equal [
281
+ { :action => 'domain added', :domain => 'a.com' },
282
+ { :action => 'domain added', :domain => 'b.com' }
283
+ ], responses
284
+ end
285
+
286
+ def test_domains_slaves_sync_add_and_delete
287
+ @client.expects(:domains_slaves_list).with().returns({'a.com' => '195.177.253.1'})
288
+ @client.expects(:domains_slaves_delete).with('a.com').returns({:action => 'domain deleted'})
289
+ @client.expects(:domains_slaves_add).with('b.com', '195.177.253.1').returns(:action => 'domain added')
290
+
291
+ responses = @client.domains_slaves_sync(['b.com'], '195.177.253.1')
292
+ assert_equal [
293
+ { :action => 'domain added', :domain => 'b.com' },
294
+ { :action => 'domain deleted', :domain => 'a.com' }
295
+ ], responses
296
+ end
297
+
298
+ def test_domains_slaves_sync_add_and_delete_and_change_masterip
299
+ @client.expects(:domains_slaves_list).with().returns(
300
+ 'a.com' => '195.177.253.1', 'c.com' => '127.0.0.1'
301
+ )
302
+ @client.expects(:domains_slaves_delete).with('a.com').returns(:action => 'domain deleted')
303
+ @client.expects(:domains_slaves_add).with('b.com', '195.177.253.1').returns(:action => 'domain added')
304
+ @client.expects(:domains_slaves_updatemasterip).with('c.com', '195.177.253.1').returns(:action => 'domain master IP updated')
305
+
306
+ responses = @client.domains_slaves_sync(['b.com', 'c.com'], '195.177.253.1')
307
+ assert_equal [
308
+ { :action => 'domain added', :domain => 'b.com' },
309
+ { :action => 'domain deleted', :domain => 'a.com' },
310
+ { :action => 'domain master IP updated', :domain => 'c.com' }
311
+ ], responses
312
+ end
313
+
314
+ def test_inspect
315
+ assert_match('#<Esgob::Client account=acct>', @client.inspect)
316
+ end
228
317
  end
@@ -4,11 +4,9 @@ require 'test_helper'
4
4
  require 'esgob'
5
5
 
6
6
  class TestVersion < MiniTest::Unit::TestCase
7
-
8
7
  def test_version_number_looks_sensible
9
8
  assert_equal 'constant', defined?(Esgob::VERSION)
10
9
  assert_kind_of String, Esgob::VERSION
11
10
  assert_match /^\d{1,2}\.\d{1,2}\.\d{1,2}$/, Esgob::VERSION
12
11
  end
13
-
14
12
  end
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": {
3
+ "message": "Account and API key combination not valid",
4
+ "code": 1003
5
+ }
6
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "error": {
3
+ "message": "Domain is not present in your account",
4
+ "code": 2007
5
+ }
6
+ }
@@ -0,0 +1,2 @@
1
+ b.com
2
+ c.com
data/test/test_helper.rb CHANGED
@@ -4,6 +4,7 @@ require 'rubygems'
4
4
  require 'bundler'
5
5
  Bundler.require(:default, :development)
6
6
  require 'minitest/autorun'
7
+ require 'mocha/mini_test'
7
8
 
8
9
  unless RUBY_VERSION =~ /^1\.8/
9
10
  SimpleCov.start
@@ -11,18 +12,34 @@ end
11
12
 
12
13
  FakeWeb.allow_net_connect = false
13
14
 
15
+ def fixture_path(fixture_name)
16
+ fixture_name = fixture_name.to_s
17
+ fixture_name += '.json' unless fixture_name.match(/\.\w+$/)
18
+ File.join(File.dirname(__FILE__), 'fixtures', fixture_name)
19
+ end
20
+
21
+ def read_fixture(fixture_name)
22
+ File.read fixture_path(fixture_name)
23
+ end
14
24
 
15
- def register_fixture(api_call, fixture_name=nil)
25
+ def register_fixture(api_call, fixture_name = nil)
16
26
  if fixture_name.nil?
17
27
  fixture_name = api_call.gsub(/\W+/, '_')
18
28
  end
19
29
 
20
- fixture_file = File.join(File.dirname(__FILE__), 'fixtures', fixture_name + '.json')
21
-
22
30
  FakeWeb.register_uri(
23
31
  :get, %r[^https?://api\.esgob\.com(:443)?/1.0/#{api_call}],
24
32
  :status => ["200", "OK"],
25
33
  :content_type => "application/json",
26
- :body => File.read(fixture_file)
34
+ :body => read_fixture(fixture_name)
27
35
  )
28
36
  end
37
+
38
+ def capture(stream)
39
+ original = eval "$#{stream}"
40
+ eval "$#{stream} = StringIO.new"
41
+ yield
42
+ result = eval("$#{stream}").string
43
+ eval "$#{stream} = original"
44
+ result
45
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: esgob
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.0.1
4
+ version: 0.0.2
5
5
  platform: ruby
6
6
  authors:
7
7
  - Nicholas Humfrey
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2015-04-12 00:00:00.000000000 Z
11
+ date: 2015-05-03 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: json
@@ -24,6 +24,20 @@ dependencies:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
26
  version: '1.8'
27
+ - !ruby/object:Gem::Dependency
28
+ name: thor
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: 0.19.1
34
+ type: :runtime
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: 0.19.1
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: bundler
29
43
  requirement: !ruby/object:Gem::Requirement
@@ -80,6 +94,20 @@ dependencies:
80
94
  - - "~>"
81
95
  - !ruby/object:Gem::Version
82
96
  version: 1.3.0
97
+ - !ruby/object:Gem::Dependency
98
+ name: mocha
99
+ requirement: !ruby/object:Gem::Requirement
100
+ requirements:
101
+ - - "~>"
102
+ - !ruby/object:Gem::Version
103
+ version: 1.1.0
104
+ type: :development
105
+ prerelease: false
106
+ version_requirements: !ruby/object:Gem::Requirement
107
+ requirements:
108
+ - - "~>"
109
+ - !ruby/object:Gem::Version
110
+ version: 1.1.0
83
111
  - !ruby/object:Gem::Dependency
84
112
  name: simplecov
85
113
  requirement: !ruby/object:Gem::Requirement
@@ -97,7 +125,8 @@ dependencies:
97
125
  description:
98
126
  email:
99
127
  - njh@aelius.com
100
- executables: []
128
+ executables:
129
+ - esgob
101
130
  extensions: []
102
131
  extra_rdoc_files: []
103
132
  files:
@@ -107,13 +136,18 @@ files:
107
136
  - LICENSE.md
108
137
  - README.md
109
138
  - Rakefile
139
+ - bin/esgob
110
140
  - esgob.gemspec
111
141
  - lib/esgob.rb
142
+ - lib/esgob/cli.rb
112
143
  - lib/esgob/client.rb
113
144
  - lib/esgob/version.rb
145
+ - test/esgob_cli_test.rb
114
146
  - test/esgob_client_test.rb
115
147
  - test/esgob_version_test.rb
116
148
  - test/fixtures/accounts_get.json
149
+ - test/fixtures/code_1003.json
150
+ - test/fixtures/code_2007.json
117
151
  - test/fixtures/domains_list.json
118
152
  - test/fixtures/domains_slaves_add.json
119
153
  - test/fixtures/domains_slaves_axfrout_add.json
@@ -123,8 +157,9 @@ files:
123
157
  - test/fixtures/domains_slaves_list.json
124
158
  - test/fixtures/domains_slaves_updatemasterip.json
125
159
  - test/fixtures/domains_tools_soacheck.json
160
+ - test/fixtures/sync-domain-list.txt
126
161
  - test/test_helper.rb
127
- homepage: ''
162
+ homepage: http://github.com/njh/ruby-esgob
128
163
  licenses:
129
164
  - MIT
130
165
  metadata: {}
@@ -149,9 +184,12 @@ signing_key:
149
184
  specification_version: 4
150
185
  summary: Client library for talking to the Esgob anycast DNS API.
151
186
  test_files:
187
+ - test/esgob_cli_test.rb
152
188
  - test/esgob_client_test.rb
153
189
  - test/esgob_version_test.rb
154
190
  - test/fixtures/accounts_get.json
191
+ - test/fixtures/code_1003.json
192
+ - test/fixtures/code_2007.json
155
193
  - test/fixtures/domains_list.json
156
194
  - test/fixtures/domains_slaves_add.json
157
195
  - test/fixtures/domains_slaves_axfrout_add.json
@@ -161,5 +199,6 @@ test_files:
161
199
  - test/fixtures/domains_slaves_list.json
162
200
  - test/fixtures/domains_slaves_updatemasterip.json
163
201
  - test/fixtures/domains_tools_soacheck.json
202
+ - test/fixtures/sync-domain-list.txt
164
203
  - test/test_helper.rb
165
204
  has_rdoc: