devdnsd 3.1.2 → 4.0.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (53) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +2 -2
  3. data/.rubocop.yml +82 -0
  4. data/.travis-gemfile +4 -10
  5. data/.travis.yml +11 -5
  6. data/CHANGELOG.md +11 -0
  7. data/Gemfile +9 -8
  8. data/README.md +4 -5
  9. data/Rakefile +22 -6
  10. data/bin/devdnsd +42 -36
  11. data/config/devdnsd_config.sample +11 -11
  12. data/devdnsd.gemspec +7 -6
  13. data/doc/DevDNSd.html +6 -6
  14. data/doc/DevDNSd/{ApplicationMethods/Aliases.html → Aliases.html} +96 -100
  15. data/doc/DevDNSd/Application.html +2170 -1084
  16. data/doc/DevDNSd/Configuration.html +63 -33
  17. data/doc/DevDNSd/Errors.html +3 -3
  18. data/doc/DevDNSd/Errors/InvalidRule.html +3 -3
  19. data/doc/DevDNSd/{ApplicationMethods/System.html → OSX.html} +116 -489
  20. data/doc/DevDNSd/Rule.html +448 -749
  21. data/doc/DevDNSd/{ApplicationMethods/Server.html → Server.html} +77 -73
  22. data/doc/DevDNSd/System.html +895 -0
  23. data/doc/DevDNSd/Version.html +6 -6
  24. data/doc/_index.html +28 -27
  25. data/doc/class_list.html +6 -2
  26. data/doc/file.README.html +8 -9
  27. data/doc/file_list.html +5 -1
  28. data/doc/frames.html +1 -1
  29. data/doc/index.html +8 -9
  30. data/doc/js/full_list.js +4 -1
  31. data/doc/method_list.html +106 -84
  32. data/doc/top-level-namespace.html +3 -3
  33. data/lib/devdnsd.rb +10 -8
  34. data/lib/devdnsd/aliases.rb +171 -0
  35. data/lib/devdnsd/application.rb +93 -704
  36. data/lib/devdnsd/configuration.rb +20 -11
  37. data/lib/devdnsd/errors.rb +1 -1
  38. data/lib/devdnsd/osx.rb +217 -0
  39. data/lib/devdnsd/rule.rb +65 -94
  40. data/lib/devdnsd/server.rb +118 -0
  41. data/lib/devdnsd/system.rb +102 -0
  42. data/lib/devdnsd/version.rb +3 -3
  43. data/locales/en.yml +17 -16
  44. data/locales/it.yml +17 -16
  45. data/spec/devdnsd/application_spec.rb +188 -184
  46. data/spec/devdnsd/configuration_spec.rb +2 -2
  47. data/spec/devdnsd/rule_spec.rb +33 -34
  48. data/spec/resolver_helper.rb +10 -27
  49. data/spec/spec_helper.rb +21 -7
  50. metadata +36 -21
  51. data/doc/DevDNSd/ApplicationMethods.html +0 -125
  52. data/doc/DevDNSd/ApplicationMethods/System/ClassMethods.html +0 -538
  53. data/spec/coverage_helper.rb +0 -20
@@ -0,0 +1,118 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the devdnsd gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ # A small DNS server to enable local .dev domain resolution.
8
+ module DevDNSd
9
+ # Methods to process requests.
10
+ module Server
11
+ # Starts the DNS server.
12
+ #
13
+ # @return [Object] The result of stop callbacks.
14
+ def perform_server
15
+ application = self
16
+
17
+ @server = RubyDNS.run_server(server_options) do
18
+ self.logger = application.logger
19
+
20
+ match(/.+/, DevDNSd::Application::ANY_CLASSES) do |transaction, match_data|
21
+ # During debugging, wrap the inside of the block with a begin rescue and PRINT the exception because RubyDNS hides it.
22
+ application.config.rules.each { |rule| application.process_rule_in_classes(rule, match_data, transaction) }
23
+ end
24
+
25
+ # Default DNS handler and event handlers
26
+ otherwise { |transaction| transaction.failure!(:NXDomain) }
27
+ on(:start) { application.on_start }
28
+ on(:stop) { application.on_stop }
29
+ end
30
+ end
31
+
32
+ alias_method :startup, :perform_server
33
+
34
+ # Processes a DNS rule.
35
+ #
36
+ # @param rule [Rule] The rule to process.
37
+ # @param type [Symbol] The type of the query.
38
+ # @param match_data [MatchData|nil] If the rule pattern was a Regexp, then this holds the match data, otherwise `nil` is passed.
39
+ # @param transaction [RubyDNS::Transaction] The current DNS transaction (http://rubydoc.info/gems/rubydns/RubyDNS/Transaction).
40
+ def process_rule(rule, type, match_data, transaction)
41
+ reply, type = perform_process_rule(rule, type, match_data, transaction)
42
+ logger.debug(reply ? i18n.reply(reply, type) : i18n.no_reply)
43
+
44
+ if reply
45
+ transaction.respond!(*finalize_reply(reply, rule, type))
46
+ else
47
+ reply.is_a?(FalseClass) ? false : nil
48
+ end
49
+ end
50
+
51
+ # Processes a rule against a set of DNS resource classes.
52
+ #
53
+ # @param rule [Rule] The rule to process.
54
+ # @param match_data [MatchData|nil] If the rule pattern was a Regexp, then this holds the match data, otherwise `nil` is passed.
55
+ # @param transaction [RubyDNS::Transaction] The current DNS transaction (http://rubydoc.info/gems/rubydns/RubyDNS/Transaction).
56
+ def process_rule_in_classes(rule, match_data, transaction)
57
+ # Get the subset of handled class that is valid for the rule
58
+ resource_classes = DevDNSd::Application::ANY_CLASSES & rule.resource_class.ensure_array
59
+ resource_classes &= [transaction.resource_class] if transaction.resource_class != DevDNSd::Application::ANY_REQUEST
60
+
61
+ if resource_classes.present?
62
+ resource_classes.each do |resource_class| # Now for every class
63
+ matches = rule.match_host(match_data[0])
64
+ process_rule(rule, resource_class, rule.regexp? ? matches : nil, transaction) if matches
65
+ end
66
+ end
67
+ end
68
+
69
+ private
70
+
71
+ # :nodoc:
72
+ def server_options
73
+ {asynchronous: !@config.foreground, listen: build_listen_interfaces}
74
+ end
75
+
76
+ # :nodoc:
77
+ def build_listen_interfaces
78
+ port = @config.port.to_integer
79
+ @config.bind_addresses.ensure_array { |address| [:udp, address, port] } + @config.bind_addresses.ensure_array { |address| [:tcp, address, port] }
80
+ end
81
+
82
+ # :nodoc:
83
+ def perform_process_rule(rule, type, match_data, transaction)
84
+ type = DevDNSd::Rule.resource_class_to_symbol(type)
85
+ reply = execute_rule(transaction, rule, type, match_data)
86
+
87
+ logger.debug(i18n.match(rule.match, type))
88
+ [reply, type]
89
+ end
90
+
91
+ # :nodoc:
92
+ def execute_rule(transaction, rule, type, match_data)
93
+ reply = rule.block ? rule.block.call(match_data, type, transaction) : rule.reply
94
+ reply = match_data[0].gsub(rule.match, reply.gsub("$", "\\")) if rule.match.is_a?(::Regexp) && reply && match_data && match_data[0]
95
+ reply
96
+ end
97
+
98
+ # :nodoc:
99
+ def finalize_reply(reply, rule, type)
100
+ rv = []
101
+ rv << rule.options.delete(:priority).to_integer(10) if type == :MX
102
+ rv << ([:A, :AAAA].include?(type) ? reply : Resolv::DNS::Name.create(reply))
103
+ rv << prepare_reply_options(rule, type)
104
+ rv
105
+ end
106
+
107
+ # :nodoc:
108
+ def prepare_reply_options(rule, type)
109
+ rule.options.merge({resource_class: DevDNSd::Rule.symbol_to_resource_class(type, @locale), ttl: validate_ttl(rule.options.delete(:ttl))})
110
+ end
111
+
112
+ # :nodoc:
113
+ def validate_ttl(current, default = 300)
114
+ current = current.to_integer
115
+ current > 0 ? current : default
116
+ end
117
+ end
118
+ end
@@ -0,0 +1,102 @@
1
+ # encoding: utf-8
2
+ #
3
+ # This file is part of the devdnsd gem. Copyright (C) 2013 and above Shogun <shogun@cowtech.it>.
4
+ # Licensed under the MIT license, which can be found at http://www.opensource.org/licenses/mit-license.php.
5
+ #
6
+
7
+ # A small DNS server to enable local .dev domain resolution.
8
+ module DevDNSd
9
+ # System management methods.
10
+ module System
11
+ extend ActiveSupport::Concern
12
+
13
+ # Returns the name of the daemon.
14
+ #
15
+ # @return [String] The name of the daemon.
16
+ def daemon_name
17
+ config ? File.basename(config.pid_file, ".pid") : "devdnsd"
18
+ end
19
+
20
+ alias_method :name, :daemon_name
21
+
22
+ # Returns the standard location of the PID file.
23
+ #
24
+ # @return [String] The standard location of the PID file.
25
+ def working_directory
26
+ config ? File.dirname(config.pid_file) : Dir.pwd
27
+ end
28
+ alias_method :runtime_directory, :working_directory
29
+
30
+ # Returns the complete path of the PID file.
31
+ #
32
+ # @return [String] The complete path of the PID file.
33
+ def process_file_path
34
+ config ? config.pid_file : Dir.pwd + "devdnsd.pid"
35
+ end
36
+
37
+ # Returns the complete path of the log file.
38
+ #
39
+ # @return [String] The complete path of the log file.
40
+ def log_file_path
41
+ config.log_file
42
+ end
43
+
44
+ # Returns the standard location of the log file.
45
+ #
46
+ # @return [String] The standard location of the log file.
47
+ def log_directory
48
+ File.dirname(config.log_file)
49
+ end
50
+
51
+ # Starts the server in background.
52
+ #
53
+ # @return [Boolean] `true` if action succeeded, `false` otherwise.
54
+ def action_start
55
+ logger.info(i18n.starting)
56
+
57
+ prepare_start
58
+
59
+ @config.foreground ? perform_server : self.class.start
60
+ true
61
+ end
62
+
63
+ # Stops the server in background.
64
+ #
65
+ # @return [Boolean] `true` if action succeeded, `false` otherwise.
66
+ def action_stop
67
+ self.class.stop
68
+ true
69
+ end
70
+
71
+ # Restarts the server in background.
72
+ #
73
+ # @return [Boolean] `true` if action succeeded, `false` otherwise.
74
+ def action_restart
75
+ action_stop
76
+ action_start
77
+ true
78
+ end
79
+
80
+ # Shows the status of the server
81
+ #
82
+ # @return [Boolean] `true` if action succeeded, `false` otherwise.
83
+ def action_status
84
+ status = self.class.status
85
+ status = :crashed if status == :unknown && self.class.crashed?
86
+
87
+ log_status(self.class.controller.pid, status)
88
+ end
89
+
90
+ private
91
+
92
+ # :nodoc:
93
+ def prepare_start
94
+ if !Process.respond_to?(:fork)
95
+ logger.warn(i18n.no_fork)
96
+ @config.foreground = true
97
+ elsif @command.options[:foreground].value
98
+ @config.foreground = true
99
+ end
100
+ end
101
+ end
102
+ end
@@ -10,13 +10,13 @@ module DevDNSd
10
10
  # @see http://semver.org
11
11
  module Version
12
12
  # The major version.
13
- MAJOR = 3
13
+ MAJOR = 4
14
14
 
15
15
  # The minor version.
16
- MINOR = 1
16
+ MINOR = 0
17
17
 
18
18
  # The patch version.
19
- PATCH = 2
19
+ PATCH = 0
20
20
 
21
21
  # The current version number of DevDNSd.
22
22
  STRING = [MAJOR, MINOR, PATCH].compact.join(".")
@@ -5,33 +5,34 @@
5
5
  #
6
6
 
7
7
  ---
8
+ en:
8
9
  devdnsd:
9
10
  rule_invalid_call: "You must specify at least a rule and a host (also via a block). Optionally you can add a record type (default: A) and the options."
10
11
  rule_invalid_options: "You can only use hashs for options."
11
- rule_invalid_resource: "Invalid resource class %1."
12
+ rule_invalid_resource: "Invalid resource class %s."
12
13
  dns_update: "Flushing DNS cache and resolvers ..."
13
14
  no_jruby: "DevDNSd is not available on JRuby."
14
15
  no_fork: "Forking is not available for this platform. Running in foreground ..."
15
16
  starting: "Starting DevDNSd ..."
16
- match: "Found match on %1 with type %2."
17
- reply: "Reply is %1 with type %2."
17
+ match: "Found match on %s with type %s."
18
+ reply: "Reply is %s with type %s."
18
19
  no_reply: "No reply found."
19
20
  no_agent: "Install DevDNSd as a local resolver is only available on MacOSX."
20
21
  admin_privileges_warning: "Basing on your setup, the system might ask you up to twice to grant {mark=bright}osascript{/mark} application admin privileges."
21
- resolver_creating: "Creating the resolver in {mark=bright}%1{/mark} ..."
22
+ resolver_creating: "Creating the resolver in {mark=bright}%s{/mark} ..."
22
23
  resolver_creating_error: "Cannot create the resolver file."
23
- resolver_deleting: "Deleting the resolver %1 ..."
24
+ resolver_deleting: "Deleting the resolver %s ..."
24
25
  resolver_deleting_error: "Cannot delete the resolver file."
25
- agent_creating: "Creating the launch agent in {mark=bright}%1{/mark} ..."
26
+ agent_creating: "Creating the launch agent in {mark=bright}%s{/mark} ..."
26
27
  agent_creating_error: "Cannot create the launch agent."
27
- agent_deleting: "Deleting the launch agent %1 ..."
28
+ agent_deleting: "Deleting the launch agent %s ..."
28
29
  agent_deleting_error: "Cannot delete the launch agent."
29
- agent_loading: "Loading the launch agent %1 ..."
30
+ agent_loading: "Loading the launch agent %s ..."
30
31
  agent_loading_error: "Cannot load the launch agent."
31
- agent_unloading: "Unloading the launch agent %1 ..."
32
+ agent_unloading: "Unloading the launch agent %s ..."
32
33
  agent_unloading_error: "Cannot unload the launch agent."
33
- logging_failed: "Cannot log to {mark=bright}%1{/mark}. Logging to terminal..."
34
- invalid_directory: "Cannot write on directory {mark=bright}%1{/mark}. Exiting..."
34
+ logging_failed: "Cannot log to {mark=bright}%s{/mark}. Logging to terminal..."
35
+ invalid_directory: "Cannot write on directory {mark=bright}%s{/mark}. Exiting..."
35
36
  application_description: "A small DNS server to enable local domain resolution."
36
37
  application_help_configuration: "The configuration file to use. Default is \"~/.devdnsd_config\"."
37
38
  application_help_tld: "The TLD to handle. Default is \"dev\"."
@@ -56,7 +57,7 @@
56
57
  application_meta_addresses: "ADDRESSES"
57
58
  application_meta_aliases: "ALIASES"
58
59
  application_meta_command: "COMMAND"
59
- application_create_config: "To execute devdnsd, please create the file {mark=bright}%1{/mark}. An empty file is sufficient."
60
+ application_create_config: "To execute devdnsd, please create the file {mark=bright}%s{/mark}. An empty file is sufficient."
60
61
  command_start: "Starts the server."
61
62
  command_stop: "Stops the server."
62
63
  command_restart: "Restarts the server."
@@ -67,7 +68,7 @@
67
68
  command_aliases: "Adds or removes aliases to network interfaces."
68
69
  command_add: "Adds aliases."
69
70
  command_remove: "Removes aliases."
70
- status_running: "The server is running with process ID {mark=bright}%1{/mark}."
71
+ status_running: "The server is running with process ID {mark=bright}%s{/mark}."
71
72
  status_stopped: "The server is stopped."
72
73
  status_crashed: "The server crashed. See the log for more information."
73
74
  status_unknown: "The server status is unknown."
@@ -77,8 +78,8 @@
77
78
  add: "add"
78
79
  to: "to "
79
80
  from: "from "
80
- general_error: "Cannot {mark=bright}%1{/mark} address {mark=bright}%2{/mark} %3interface {mark=bright}%4{/mark}."
81
+ general_error: "Cannot {mark=bright}%s{/mark} address {mark=bright}%s{/mark} %sinterface {mark=bright}%s{/mark}."
81
82
  add_empty: "No valid addresses to add to the interface found."
82
83
  remove_empty: "No valid addresses to remove from the interface found."
83
- run: "%1 {mark=bright}%2{/mark} address {mark=bright}%3{/mark} %4interface {mark=bright}%5{/mark}..."
84
- dry_run: "%1 I will {mark=bright}%2{/mark} address {mark=bright}%3{/mark} %4interface {mark=bright}%5{/mark}..."
84
+ run: "%s {mark=bright}%s{/mark} address {mark=bright}%s{/mark} %sinterface {mark=bright}%s{/mark}..."
85
+ dry_run: "%s I will {mark=bright}%s{/mark} address {mark=bright}%s{/mark} %sinterface {mark=bright}%s{/mark}..."
@@ -5,33 +5,34 @@
5
5
  #
6
6
 
7
7
  ---
8
+ it:
8
9
  devdnsd:
9
10
  rule_invalid_call: "Devi specificare almeno una regola e un host (anche tramite un blocco). Opzionalmente puoi aggiungere un tipo di record (default: A) e le opzioni."
10
11
  rule_invalid_options: "Puoi usare solo hash per le opzioni."
11
- rule_invalid_resource: "Classe di risorsa %1 non valida."
12
+ rule_invalid_resource: "Classe di risorsa %s non valida."
12
13
  no_jruby: "DevDNSd non è disponibile per JRuby."
13
14
  no_fork: "Il forking non è disponibile per questa piattaforma. Eseguo foreground ..."
14
15
  dns_update: "Cancello la cache dei DNS e dei resolver ..."
15
16
  starting: "Avvio DevDNSd ..."
16
- match: "Trovata corrispondenza per %1 con tipo %2."
17
- reply: "La risposta è %1 con tipo %2."
17
+ match: "Trovata corrispondenza per %s con tipo %s."
18
+ reply: "La risposta è %s con tipo %s."
18
19
  no_reply: "Nessuna risposta trovata."
19
20
  no_agent: "Installare DevDNSd come resolver locale è disponibile solo su MacOSX."
20
21
  admin_privileges_warning: "In base alla tua configurazione, il sistema potrebbe chiederti fino a due volte di garantire all'applicazione {mark=bright}osascript{/mark} i privilegi di amministratore."
21
- resolver_creating: "Creo il resolver in {mark=bright}%1{/mark} ..."
22
+ resolver_creating: "Creo il resolver in {mark=bright}%s{/mark} ..."
22
23
  resolver_creating_error: "Impossible creare il file del resolver."
23
- resolver_deleting: "Cancello resolver %1 ..."
24
+ resolver_deleting: "Cancello resolver %s ..."
24
25
  resolver_deleting_error: "Impossibile cancellare il file del resolver."
25
- agent_creating: "Creo il launch agent in {mark=bright}%1{/mark} ..."
26
+ agent_creating: "Creo il launch agent in {mark=bright}%s{/mark} ..."
26
27
  agent_creating_error: "Impossibile creare il launch agent."
27
- agent_deleting: "Cancello il launch agent %1 ..."
28
+ agent_deleting: "Cancello il launch agent %s ..."
28
29
  agent_deleting_error: "Impossibile cancellare launch agent."
29
- agent_loading: "Avvio il launch agent %1 ..."
30
+ agent_loading: "Avvio il launch agent %s ..."
30
31
  agent_loading_error: "Impossibile avviare il launch agent."
31
- agent_unloading: "Fermo il launch agent %1 ..."
32
+ agent_unloading: "Fermo il launch agent %s ..."
32
33
  agent_unloading_error: "Impossible fermare il launch agent."
33
- logging_failed: "Impossibile eseguire il logging in {mark=bright}%1{/mark}. Eseguo il logging nel terminale..."
34
- invalid_directory: "Impossibile scrivere sulla directory {mark=bright}%1{/mark}. Esco..."
34
+ logging_failed: "Impossibile eseguire il logging in {mark=bright}%s{/mark}. Eseguo il logging nel terminale..."
35
+ invalid_directory: "Impossibile scrivere sulla directory {mark=bright}%s{/mark}. Esco..."
35
36
  application_description: "Un piccolo server DNS per abilitare la risoluzione di domini locali."
36
37
  application_help_configuration: "Il file di configurazione da usare. Il valore predefinito è \"~/.devdnsd_config\"."
37
38
  application_help_tld: "Il TLD da gestiere. Il valore predefinito è \"dev\"."
@@ -57,7 +58,7 @@
57
58
  application_meta_addresses: "INDIRIZZI"
58
59
  application_meta_aliases: "ALIAS"
59
60
  application_meta_command: "COMANDO"
60
- application_create_config: "Per eseguire devdnsd, per favore crea il file {mark=bright}%1{/mark}. Un file vuoto è sufficiente."
61
+ application_create_config: "Per eseguire devdnsd, per favore crea il file {mark=bright}%s{/mark}. Un file vuoto è sufficiente."
61
62
  command_start: "Avvia server."
62
63
  command_stop: "Ferma il server."
63
64
  command_restart: "Riavvia server."
@@ -68,7 +69,7 @@
68
69
  command_aliases: "Aggiunge or rimuove indirizzi dalle interfacce di rete."
69
70
  command_add: "Aggiungi indirizzi"
70
71
  command_remove: "Rimuovi indirizzi."
71
- status_running: "Il server è in esecuzione con ID processo {mark=bright}%1{/mark}."
72
+ status_running: "Il server è in esecuzione con ID processo {mark=bright}%s{/mark}."
72
73
  status_stopped: "Il server è stato fermato."
73
74
  status_crashed: "Il server è terminato con errori. Guarda il log per maggiori informazioni."
74
75
  status_unknown: "Lo status del server è sconosciuto."
@@ -78,8 +79,8 @@
78
79
  add: "aggiungere"
79
80
  to: "all'"
80
81
  from: "dall'"
81
- general_error: "Impossibile {mark=bright}%1{/mark} l'indirizzo {mark=bright}%2{/mark} %3interfaccia {mark=bright}%4{/mark}."
82
+ general_error: "Impossibile {mark=bright}%s{/mark} l'indirizzo {mark=bright}%s{/mark} %sinterfaccia {mark=bright}%s{/mark}."
82
83
  add_empty: "Nessun indirizzo valido da aggiungere all'interfaccia trovato."
83
84
  remove_empty: "Nessun indirizzo valido da rimuovere dall'interfaccia trovato."
84
- run: "%1 {mark=bright}%2{/mark} l'indirizzo {mark=bright}%3{/mark} %4interfaccia {mark=bright}%5{/mark}..."
85
- dry_run: "%1 Sto per {mark=bright}%2{/mark} l'indirizzo {mark=bright}%3{/mark} %4interfaccia {mark=bright}%5{/mark}..."
85
+ run: "%s {mark=bright}%s{/mark} l'indirizzo {mark=bright}%s{/mark} %sinterfaccia {mark=bright}%s{/mark}..."
86
+ dry_run: "%s Sto per {mark=bright}%s{/mark} l'indirizzo {mark=bright}%s{/mark} %sinterfaccia {mark=bright}%s{/mark}..."
@@ -10,6 +10,7 @@ describe DevDNSd::Application do
10
10
  before(:each) do
11
11
  allow(Bovem::Logger).to receive(:default_file).and_return("/dev/null")
12
12
  allow(DevDNSd::Application).to receive(:instance).and_return(application)
13
+ allow(Kernel).to receive(:exit)
13
14
  end
14
15
 
15
16
  def create_application(overrides = {})
@@ -24,7 +25,7 @@ describe DevDNSd::Application do
24
25
  end
25
26
 
26
27
  let(:log_file) { "/tmp/devdnsd-test-log-#{Time.now.strftime("%Y%m%d-%H%M%S")}" }
27
- let(:application){ create_application({"log_file" => log_file}) }
28
+ let(:application){ create_application({"log_file" => log_file, "configuration" => "/dev/null"}) }
28
29
  let(:executable) { ::Pathname.new(::File.dirname((__FILE__))) + "../../bin/devdnsd" }
29
30
  let(:sample_config) { ::Pathname.new(::File.dirname((__FILE__))) + "../../config/devdnsd_config.sample" }
30
31
  let(:resolver_path) { "/tmp/devdnsd-test-resolver-#{Time.now.strftime("%Y%m%d-%H%M%S")}" }
@@ -37,7 +38,7 @@ describe DevDNSd::Application do
37
38
 
38
39
  it "should fallback logger to STDOUT" do
39
40
  allow_any_instance_of(DevDNSd::Application).to receive(:read_configuration)
40
- expect(Bovem::Logger).to receive(:create).with($stdout, Logger::INFO)
41
+ expect(Bovem::Logger).to receive(:create).with($stdout, level: Logger::INFO)
41
42
  create_application({"log_file" => "/invalid/logger"})
42
43
  end
43
44
 
@@ -53,14 +54,16 @@ describe DevDNSd::Application do
53
54
  file.write("config.port = ")
54
55
  file.close
55
56
 
56
- expect { create_application({"configuration" => file.path, "log_file" => log_file}) }.to raise_error(::SystemExit)
57
+ expect_any_instance_of(DevDNSd::Application).to receive(:shutdown).and_call_original
58
+ create_application({"configuration" => file.path, "log_file" => log_file})
57
59
  ::File.unlink(path)
58
60
  end
59
61
 
60
62
  it "should abort when the log file is invalid" do
61
63
  allow_any_instance_of(Bovem::Logger).to receive(:fatal)
62
64
  allow_any_instance_of(Bovem::Logger).to receive(:warn)
63
- expect { create_application({"pid_file" => "/invalid/pid", "log_file" => log_file}) }.to raise_error(::SystemExit)
65
+ expect_any_instance_of(DevDNSd::Application).to receive(:shutdown).and_call_original
66
+ create_application({"pid_file" => "/invalid/pid", "log_file" => "/dev/null"})
64
67
  end
65
68
  end
66
69
 
@@ -73,13 +76,13 @@ describe DevDNSd::Application do
73
76
 
74
77
  describe ".quit" do
75
78
  it "should quit the application" do
76
- allow(EM).to receive(:add_timer).and_yield
77
- expect(EM).to receive(:stop)
79
+ allow(application).to receive(:instance).and_call_original
78
80
  DevDNSd::Application.quit
79
81
  end
80
82
 
81
- it "should not blow up in case of errors" do
82
- allow(EM).to receive(:add_timer).and_raise(RuntimeError)
83
+ it "should return with error code 1 in case of errors" do
84
+ allow(application).to receive(:shutdown).and_raise(RuntimeError)
85
+ expect(Kernel).to receive(:exit).with(1)
83
86
  expect { DevDNSd::Application.quit }.not_to raise_error
84
87
  end
85
88
  end
@@ -126,153 +129,138 @@ describe DevDNSd::Application do
126
129
  end
127
130
  end
128
131
 
129
- describe ".process_file_path" do
132
+ describe "#process_file_path" do
130
133
  let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config}) }
131
134
 
132
135
  it "returns the default file" do
133
- expect(DevDNSd::Application.process_file_path).to eq("/var/run/devdnsd.pid")
136
+ expect(DevDNSd::Application.instance.process_file_path).to eq("/var/run/devdnsd.pid")
134
137
  end
135
138
 
136
139
  it "return the set file" do
137
140
  DevDNSd::Application.instance.config.pid_file = "/this/is/a/daemon.pid"
138
- expect(DevDNSd::Application.process_file_path).to eq("/this/is/a/daemon.pid")
141
+ expect(DevDNSd::Application.instance.process_file_path).to eq("/this/is/a/daemon.pid")
139
142
  end
140
143
  end
141
144
 
142
- describe ".log_file_path" do
145
+ describe "#log_file_path" do
143
146
  let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config}) }
144
147
 
145
148
  it "returns the default file" do
146
- expect(DevDNSd::Application.log_file_path).to eq(log_file)
149
+ expect(DevDNSd::Application.instance.log_file_path).to eq(log_file)
147
150
  end
148
151
 
149
152
  it "return the set file" do
150
153
  DevDNSd::Application.instance.config.log_file = "/this/is/a/daemon.log"
151
- expect(DevDNSd::Application.log_file_path).to eq("/this/is/a/daemon.log")
154
+ expect(DevDNSd::Application.instance.log_file_path).to eq("/this/is/a/daemon.log")
152
155
  end
153
156
  end
154
157
 
155
- describe ".working_directory" do
158
+ describe "#working_directory" do
156
159
  let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config}) }
157
160
 
158
161
  it "returns the default path" do
159
- expect(DevDNSd::Application.working_directory).to eq("/var/run")
162
+ expect(DevDNSd::Application.instance.working_directory).to eq("/var/run")
160
163
  end
161
164
 
162
165
  it "return the set path basing on the PID file" do
163
166
  DevDNSd::Application.instance.config.pid_file = "/this/is/a/daemon.pid"
164
- expect(DevDNSd::Application.working_directory).to eq("/this/is/a")
167
+ expect(DevDNSd::Application.instance.working_directory).to eq("/this/is/a")
165
168
  end
166
169
  end
167
170
 
168
- describe ".log_directory" do
171
+ describe "#log_directory" do
169
172
  let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config}) }
170
173
 
171
174
  it "returns the default path" do
172
- expect(DevDNSd::Application.log_directory).to eq(File.dirname(log_file))
175
+ expect(DevDNSd::Application.instance.log_directory).to eq(File.dirname(log_file))
173
176
  end
174
177
 
175
178
  it "return the set path basing on the PID file" do
176
179
  DevDNSd::Application.instance.config.log_file = "/this/is/a/daemon.log"
177
- expect(DevDNSd::Application.log_directory).to eq("/this/is/a")
180
+ expect(DevDNSd::Application.instance.log_directory).to eq("/this/is/a")
178
181
  end
179
182
  end
180
183
 
181
- describe ".daemon_name" do
184
+ describe "#daemon_name" do
182
185
  let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config}) }
183
186
 
184
187
  it "returns the default name" do
185
- expect(DevDNSd::Application.daemon_name).to eq("devdnsd")
188
+ expect(DevDNSd::Application.instance.daemon_name).to eq("devdnsd")
186
189
  end
187
190
 
188
191
  it "return the set name basing on the PID file" do
189
192
  DevDNSd::Application.instance.config.pid_file = "/this/is/a/daemon.pid"
190
- expect(DevDNSd::Application.daemon_name).to eq("daemon")
193
+ expect(DevDNSd::Application.instance.daemon_name).to eq("daemon")
191
194
  end
192
195
  end
193
196
 
194
197
  describe "#perform_server" do
195
- let(:application){ create_application({"log_file" => log_file, "configuration" => sample_config, "port" => 60771}) }
196
-
197
- def test_resolve(host = "match_1.dev", type = "ANY", nameserver = "127.0.0.1", port = 60771, logger = nil)
198
- result = nil
199
-
200
- EM.run do
201
- EM.add_timer(0.01) { application.perform_server }
202
- EM.add_timer(0.1) {
203
- Fiber.new {
204
- result = devdnsd_resolv(host, type, nameserver, port, logger)
205
- EM.stop
206
- }.resume
207
- }
208
- end
209
-
210
- result
211
- end
198
+ let(:application) { create_application({"log_file" => log_file, "configuration" => sample_config, "port" => 60771}) }
212
199
 
213
- it "should run the server" do
214
- expect(RubyDNS).to receive(:run_server)
200
+ it "should free resources correctly" do
215
201
  application.perform_server
202
+ application.shutdown
203
+ application.perform_server
204
+ application.shutdown
216
205
  end
217
206
 
218
207
  it "should setup callbacks" do
219
208
  expect_any_instance_of(RubyDNS::RuleBasedServer).to receive(:on).with(:start)
220
209
  expect_any_instance_of(RubyDNS::RuleBasedServer).to receive(:on).with(:stop)
221
-
222
- EM.run do
223
- EM.add_timer(0.01) { application.perform_server }
224
- EM.add_timer(0.2) { DevDNSd::Application.quit }
225
- end
226
- end
227
-
228
- it "should iterate the rules" do
229
- test_resolve do
230
- expect(application.config.rules).to receive(:each).at_least(1)
231
- application.perform_server
232
- end
233
- end
234
-
235
- it "should call process_rule" do
236
- test_resolve do
237
- expect(application).to receive(:process_rule).at_least(1)
238
- application.perform_server
239
- end
210
+ application.perform_server
211
+ application.shutdown
240
212
  end
241
213
 
242
- it "should complain about wrong rules" do
243
- test_resolve do
244
- allow(application).to receive(:process_rule).and_raise(::Exception)
245
- expect { application.perform_server }.to raise_exception
214
+ describe "using rules" do
215
+ def test_resolve(host = "match_1.dev", type = "ANY", nameserver = "127.0.0.1", port = 60771, logger = nil)
216
+ devdnsd_resolv(host, type, nameserver, port, logger)
246
217
  end
247
- end
248
218
 
249
- describe "should correctly resolve hostnames" do
250
- it "basing on a exact pattern" do
251
- expect(test_resolve("match_1.dev")).to eq(["10.0.1.1", :A])
252
- expect(test_resolve("match_2.dev")).to eq(["10.0.2.1", :MX])
253
- expect(test_resolve("match_3.dev")).to eq(["10.0.3.1", :A])
254
- expect(test_resolve("match_4.dev")).to eq(["cowtech.it", :CNAME])
219
+ around(:each) do |example|
220
+ app = application
221
+ app.perform_server
222
+ example.call
223
+ app.shutdown
255
224
  end
256
225
 
257
- it "basing on a regexp pattern" do
258
- expect(test_resolve("match_5_11.dev")).to eq(["ns.cowtech.it", :NS])
259
- expect(test_resolve("match_5_22.dev")).to eq(["ns.cowtech.it", :NS])
260
- expect(test_resolve("match_6_33.dev")).to eq(["10.0.6.33", :PTR])
261
- expect(test_resolve("match_6_44.dev")).to eq(["10.0.6.44", :PTR])
262
- expect(test_resolve("match_7_55.dev")).to eq(["10.0.7.55", :A])
263
- expect(test_resolve("match_7_66.dev")).to eq(["10.0.7.66", :A])
264
- expect(test_resolve("match_8_77.dev")).to eq(["10.0.8.77", :PTR])
265
- expect(test_resolve("match_8_88.dev")).to eq(["10.0.8.88", :PTR])
226
+ it "should iterate the rules" do
227
+ expect(application.config.rules).to receive(:each).at_least(1)
228
+ test_resolve
266
229
  end
267
230
 
268
- it "and return multiple or only relevant answsers" do
269
- expect(test_resolve("match_10.dev")).to eq([["10.0.10.1", :A], ["10.0.10.2", :MX]])
270
- expect(test_resolve("match_10.dev", "MX")).to eq(["10.0.10.2", :MX])
231
+ it "should call process_rule" do
232
+ expect_any_instance_of(DevDNSd::Application).to receive(:process_rule).at_least(1)
233
+ test_resolve
271
234
  end
272
235
 
273
- it "and reject invalid matches (with or without rules)" do
274
- expect(test_resolve("match_9.dev")).to eq([])
275
- expect(test_resolve("invalid.dev")).to eq([])
236
+ describe "should correctly resolve hostnames" do
237
+ it "basing on a exact pattern" do
238
+ expect(test_resolve("match_1.dev")).to eq(["10.0.1.1", :A])
239
+ expect(test_resolve("match_2.dev")).to eq(["10.0.2.1", :MX])
240
+ expect(test_resolve("match_3.dev")).to eq(["10.0.3.1", :A])
241
+ expect(test_resolve("match_4.dev")).to eq(["cowtech.it", :CNAME])
242
+ end
243
+
244
+ it "basing on a regexp pattern" do
245
+ expect(test_resolve("match_5_11.dev")).to eq(["ns.cowtech.it", :NS])
246
+ expect(test_resolve("match_5_22.dev")).to eq(["ns.cowtech.it", :NS])
247
+ expect(test_resolve("match_6_33.dev")).to eq(["10.0.6.33", :PTR])
248
+ expect(test_resolve("match_6_44.dev")).to eq(["10.0.6.44", :PTR])
249
+ expect(test_resolve("match_7_55.dev")).to eq(["10.0.7.55", :A])
250
+ expect(test_resolve("match_7_66.dev")).to eq(["10.0.7.66", :A])
251
+ expect(test_resolve("match_8_77.dev")).to eq(["10.0.8.77", :PTR])
252
+ expect(test_resolve("match_8_88.dev")).to eq(["10.0.8.88", :PTR])
253
+ end
254
+
255
+ it "and return multiple or only relevant answsers" do
256
+ expect(test_resolve("match_10.dev")).to eq([["10.0.10.1", :A], ["10.0.10.2", :MX]])
257
+ expect(test_resolve("match_10.dev", "MX")).to eq(["10.0.10.2", :MX])
258
+ end
259
+
260
+ it "and reject invalid matches (with or without rules)" do
261
+ expect(test_resolve("match_9.dev")).to eq([])
262
+ expect(test_resolve("invalid.dev")).to eq([])
263
+ end
276
264
  end
277
265
  end
278
266
  end
@@ -295,51 +283,51 @@ describe DevDNSd::Application do
295
283
 
296
284
  it "should match a valid string request" do
297
285
  rule = application.config.rules[0]
298
- expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_true
286
+ expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_truthy
299
287
  end
300
288
 
301
289
  it "should match a valid string request with specific type" do
302
290
  rule = application.config.rules[1]
303
- expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_true
291
+ expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_truthy
304
292
  end
305
293
 
306
294
  it "should match a valid string request with a block" do
307
295
  rule = application.config.rules[2]
308
- expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_true
296
+ expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_truthy
309
297
  end
310
298
 
311
299
  it "should match a valid string request with a block" do
312
300
  rule = application.config.rules[3]
313
- expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_true
301
+ expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_truthy
314
302
  end
315
303
 
316
304
  it "should match a valid regexp request" do
317
305
  rule = application.config.rules[4]
318
306
  mo = rule.match_host("match_5_12.dev")
319
- expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_true
307
+ expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_truthy
320
308
  end
321
309
 
322
310
  it "should match a valid regexp request with specific type" do
323
311
  rule = application.config.rules[5]
324
312
  mo = rule.match_host("match_6_34.dev")
325
- expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_true
313
+ expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_truthy
326
314
  end
327
315
 
328
316
  it "should match a valid regexp request with a block" do
329
317
  rule = application.config.rules[6]
330
318
  mo = rule.match_host("match_7_56.dev")
331
- expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_true
319
+ expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_truthy
332
320
  end
333
321
 
334
322
  it "should match a valid regexp request with a block and specific type" do
335
323
  rule = application.config.rules[7]
336
324
  mo = rule.match_host("match_8_78.dev")
337
- expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_true
325
+ expect(application.process_rule(rule, rule.resource_class, mo, transaction)).to be_truthy
338
326
  end
339
327
 
340
328
  it "should return false for a false block" do
341
329
  rule = application.config.rules[8]
342
- expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_false
330
+ expect(application.process_rule(rule, rule.resource_class, nil, transaction)).to be_falsey
343
331
  end
344
332
 
345
333
  it "should return nil for a nil reply" do
@@ -356,12 +344,12 @@ describe DevDNSd::Application do
356
344
  end
357
345
  end
358
346
 
359
- describe "#is_osx?" do
347
+ describe "#osx?" do
360
348
  it "should return the correct information" do
361
349
  stub_const("RbConfig::CONFIG", {"host_os" => "darwin foo"})
362
- expect(application.is_osx?).to be_true
350
+ expect(application.osx?).to be_truthy
363
351
  stub_const("RbConfig::CONFIG", {"host_os" => "another"})
364
- expect(application.is_osx?).to be_false
352
+ expect(application.osx?).to be_falsey
365
353
  end
366
354
  end
367
355
 
@@ -387,22 +375,22 @@ describe DevDNSd::Application do
387
375
 
388
376
  describe "#manage_aliases" do
389
377
  it "should override configuration" do
390
- allow(application).to receive(:manage_address)
378
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_address)
391
379
  application.manage_aliases(:add, "MESSAGE", {aliases: 10})
392
380
  expect(application.config.aliases).to eq(10)
393
381
  end
394
382
 
395
383
  it "should log an error if no interfaces are found" do
396
- allow(application).to receive(:compute_addresses).and_return([])
384
+ expect_any_instance_of(DevDNSd::Application).to receive(:compute_addresses).and_return([])
397
385
  expect(application.logger).to receive(:error).with("MESSAGE")
398
- expect(application.manage_aliases(:add, "MESSAGE", {aliases: 10})).to be_false
386
+ expect(application.manage_aliases(:add, "MESSAGE", {aliases: 10})).to be_falsey
399
387
  end
400
388
 
401
389
  it "should call #manage_address for each address" do
402
- expect(application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.1"), "DRY_RUN").and_return(true)
403
- expect(application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.2"), "DRY_RUN").and_return(true)
404
- expect(application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.3"), "DRY_RUN").and_return(true)
405
- expect(application.manage_aliases("OPERATION", "MESSAGE", {aliases: 3, dry_run: "DRY_RUN"})).to be_true
390
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.1"), "DRY_RUN").and_return(true)
391
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.2"), "DRY_RUN").and_return(true)
392
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_address).with("OPERATION", IPAddr.new("10.0.0.3"), "DRY_RUN").and_return(true)
393
+ expect(application.manage_aliases("OPERATION", "MESSAGE", {aliases: 3, dry_run: "DRY_RUN"})).to be_truthy
406
394
  end
407
395
  end
408
396
 
@@ -416,24 +404,24 @@ describe DevDNSd::Application do
416
404
  end
417
405
 
418
406
  it "should call the right system command" do
419
- expect(application).to receive(:execute_command).with("sudo ifconfig lo0 alias 10.0.0.3 > /dev/null 2>&1")
407
+ expect_any_instance_of(DevDNSd::Application).to receive(:execute_command).with("sudo ifconfig lo0 alias 10.0.0.3 > /dev/null 2>&1")
420
408
  application.manage_address(:add, "10.0.0.3")
421
409
 
422
- expect(application).to receive(:execute_command).with("sudo ifconfig lo0 -alias 10.0.0.3 > /dev/null 2>&1")
410
+ expect_any_instance_of(DevDNSd::Application).to receive(:execute_command).with("sudo ifconfig lo0 -alias 10.0.0.3 > /dev/null 2>&1")
423
411
  application.manage_address(:remove, "10.0.0.3")
424
412
  end
425
413
 
426
414
  it "should return true if the command succeded" do
427
415
  application.config.add_command = "echo {{interface}}"
428
- expect(application.manage_address(:add, "10.0.0.3")).to be_true
416
+ expect(application.manage_address(:add, "10.0.0.3")).to be_truthy
429
417
  end
430
418
 
431
419
  it "should return false if the command failed" do
432
- expect(application.manage_address(:add, "10.0.0.256")).to be_false
420
+ expect(application.manage_address(:add, "10.0.0.256")).to be_falsey
433
421
  end
434
422
 
435
423
  it "should respect dry-run mode" do
436
- expect(application).not_to receive(:execute_command)
424
+ expect_any_instance_of(DevDNSd::Application).not_to receive(:execute_command)
437
425
  expect(application.logger).to receive(:info).with(/.+.*3.*\/.*5.*.+ I will .*add.* address .*10.0.0.3.* to interface .*lo0.*/)
438
426
  expect(application.logger).to receive(:info).with(/.+.*3.*\/.*5.*.+ I will .*remove.* address .*10.0.0.3.* from interface .*lo0.*/)
439
427
 
@@ -491,39 +479,39 @@ describe DevDNSd::Application do
491
479
  end
492
480
  end
493
481
 
494
- describe "#is_ipv4?" do
482
+ describe "#ipv4?" do
495
483
  it "correctly detects valid IPv4 address" do
496
- expect(application.is_ipv4?("10.0.0.1")).to be_true
497
- expect(application.is_ipv4?("255.0.0.1")).to be_true
498
- expect(application.is_ipv4?("192.168.0.1")).to be_true
484
+ expect(application.ipv4?("10.0.0.1")).to be_truthy
485
+ expect(application.ipv4?("255.0.0.1")).to be_truthy
486
+ expect(application.ipv4?("192.168.0.1")).to be_truthy
499
487
  end
500
488
 
501
489
  it "rejects other values" do
502
- expect(application.is_ipv4?("10.0.0.256")).to be_false
503
- expect(application.is_ipv4?("10.0.0.-1")).to be_false
504
- expect(application.is_ipv4?("::1")).to be_false
505
- expect(application.is_ipv4?("INVALID")).to be_false
506
- expect(application.is_ipv4?(nil)).to be_false
490
+ expect(application.ipv4?("10.0.0.256")).to be_falsey
491
+ expect(application.ipv4?("10.0.0.-1")).to be_falsey
492
+ expect(application.ipv4?("::1")).to be_falsey
493
+ expect(application.ipv4?("INVALID")).to be_falsey
494
+ expect(application.ipv4?(nil)).to be_falsey
507
495
  end
508
496
  end
509
497
 
510
- describe "#is_ipv6?" do
498
+ describe "#ipv6?" do
511
499
  it "correctly detects valid IPv4 address" do
512
- expect(application.is_ipv6?("2001:0db8:0000:0000:0000:1428:57ab")).to be_true
513
- expect(application.is_ipv6?("2001:0db8:0:000:00:1428:57ab")).to be_true
514
- expect(application.is_ipv6?("2001:0db8:0::1428:57ab")).to be_true
515
- expect(application.is_ipv6?("2001::")).to be_true
516
- expect(application.is_ipv6?("::1")).to be_true
517
- expect(application.is_ipv6?("::2:1")).to be_true
518
- expect(application.is_ipv6?("2011::10.0.0.1")).to be_true
519
- expect(application.is_ipv6?("2011::0:10.0.0.1")).to be_true
500
+ expect(application.ipv6?("2001:0db8:0000:0000:0000:1428:57ab")).to be_truthy
501
+ expect(application.ipv6?("2001:0db8:0:000:00:1428:57ab")).to be_truthy
502
+ expect(application.ipv6?("2001:0db8:0::1428:57ab")).to be_truthy
503
+ expect(application.ipv6?("2001::")).to be_truthy
504
+ expect(application.ipv6?("::1")).to be_truthy
505
+ expect(application.ipv6?("::2:1")).to be_truthy
506
+ expect(application.ipv6?("2011::10.0.0.1")).to be_truthy
507
+ expect(application.ipv6?("2011::0:10.0.0.1")).to be_truthy
520
508
  end
521
509
 
522
510
  it "rejects other values" do
523
- expect(application.is_ipv6?("::H")).to be_false
524
- expect(application.is_ipv6?("192.168.0.256")).to be_false
525
- expect(application.is_ipv6?("INVALID")).to be_false
526
- expect(application.is_ipv6?(nil)).to be_false
511
+ expect(application.ipv6?("::H")).to be_falsey
512
+ expect(application.ipv6?("192.168.0.256")).to be_falsey
513
+ expect(application.ipv6?("INVALID")).to be_falsey
514
+ expect(application.ipv6?(nil)).to be_falsey
527
515
  end
528
516
  end
529
517
 
@@ -534,7 +522,7 @@ describe DevDNSd::Application do
534
522
  option :foreground, [:n, "foreground"], {default: true}
535
523
  })
536
524
 
537
- expect(application).to receive(:perform_server)
525
+ allow_any_instance_of(DevDNSd::Application).to receive(:perform_server)
538
526
  application.action_start
539
527
  end
540
528
 
@@ -544,7 +532,7 @@ describe DevDNSd::Application do
544
532
  option :foreground, [:n, "foreground"], {default: false}
545
533
  })
546
534
 
547
- expect(::RExec::Daemon::Controller).to receive(:start)
535
+ expect(::DevDNSd::Application).to receive(:start)
548
536
  application.action_start
549
537
  end
550
538
 
@@ -552,48 +540,48 @@ describe DevDNSd::Application do
552
540
  application.config.foreground = false
553
541
 
554
542
  allow(Process).to receive(:respond_to?).and_return(false)
555
- expect(application).to receive(:perform_server)
543
+ allow_any_instance_of(DevDNSd::Application).to receive(:perform_server)
556
544
  expect(application.logger).to receive(:warn)
557
545
 
558
546
  application.action_start
559
- expect(application.config.foreground).to be_true
547
+ expect(application.config.foreground).to be_truthy
560
548
  end
561
549
  end
562
550
 
563
551
  describe "#action_stop" do
564
552
  it "should stop the daemon" do
565
- expect(::RExec::Daemon::Controller).to receive(:stop)
553
+ expect(::DevDNSd::Application).to receive(:stop)
566
554
  application.action_stop
567
555
  end
568
556
  end
569
557
 
570
558
  describe "#action_restart" do
571
559
  it "should stop and restart the server" do
572
- expect(application).to receive(:action_stop)
573
- expect(application).to receive(:action_start)
560
+ expect_any_instance_of(DevDNSd::Application).to receive(:action_stop)
561
+ expect_any_instance_of(DevDNSd::Application).to receive(:action_start)
574
562
  application.action_restart
575
563
  end
576
564
  end
577
565
 
578
566
  describe "#action_status" do
579
567
  it "should get the status of the daemon when running" do
580
- expect(RExec::Daemon::ProcessFile).to receive(:status).and_return(:running)
581
- expect(RExec::Daemon::ProcessFile).to receive(:recall).and_return(123)
568
+ expect(Process::Daemon::ProcessFile).to receive(:status).and_return(:running)
569
+ expect(DevDNSd::Application.controller).to receive(:pid).and_return(123)
582
570
 
583
- expect(application.logger).to receive(:info).with("The server is running with process ID 123.")
571
+ expect(application.logger).to receive(:info).with("The server is running with process ID \e[1m123\e[0m.")
584
572
  application.action_status
585
573
  end
586
574
 
587
575
  it "should get the status of the daemon when stopped" do
588
- expect(RExec::Daemon::ProcessFile).to receive(:status).and_return(:stopped)
589
- expect(RExec::Daemon::ProcessFile).to receive(:recall).and_return(123)
576
+ expect(Process::Daemon::ProcessFile).to receive(:status).and_return(:stopped)
577
+ expect(DevDNSd::Application.controller).to receive(:pid).and_return(123)
590
578
 
591
579
  expect(application.logger).to receive(:info).with("The server is stopped.")
592
580
  application.action_status
593
581
  end
594
582
 
595
583
  it "should get the status of the daemon when crashed" do
596
- expect(RExec::Daemon::ProcessFile).to receive(:status).and_return(:unknown)
584
+ expect(Process::Daemon::ProcessFile).to receive(:status).and_return(:unknown)
597
585
  expect(application.class).to receive(:crashed?).and_return(true)
598
586
 
599
587
  expect(application.logger).to receive(:info).with("The server crashed. See the log for more information.")
@@ -601,7 +589,7 @@ describe DevDNSd::Application do
601
589
  end
602
590
 
603
591
  it "should get the status of the daemon when unknown" do
604
- expect(RExec::Daemon::ProcessFile).to receive(:status).and_return(:unknown)
592
+ expect(Process::Daemon::ProcessFile).to receive(:status).and_return(:unknown)
605
593
  expect(application.class).to receive(:crashed?).and_return(false)
606
594
 
607
595
  expect(application.logger).to receive(:info).with("The server status is unknown.")
@@ -611,46 +599,46 @@ describe DevDNSd::Application do
611
599
 
612
600
  describe "#action_install" do
613
601
  before(:each) do
614
- allow(application).to receive(:is_osx?).and_return(true)
602
+ allow(application).to receive(:osx?).and_return(true)
615
603
  allow(application).to receive(:execute_command)
616
604
  expect(Kernel).to receive(:system).at_least(1)
617
605
  end
618
606
 
619
607
  it "should create the resolver" do
620
- allow(application).to receive(:resolver_path).and_return(resolver_path)
621
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
608
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
609
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
622
610
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
623
611
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
624
612
 
625
- allow(application).to receive(:create_resolver) {|_, path| FileUtils.touch(path) }
613
+ allow_any_instance_of(DevDNSd::Application).to receive(:create_resolver) {|_, path| FileUtils.touch(path) }
626
614
  application.action_install
627
- expect(::File.exists?(resolver_path)).to be_true
615
+ expect(::File.exists?(resolver_path)).to be_truthy
628
616
 
629
617
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
630
618
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
631
619
  end
632
620
 
633
621
  it "should create the agent" do
634
- allow(application).to receive(:resolver_path).and_return(resolver_path)
635
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
622
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
623
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
636
624
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
637
625
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
638
626
 
639
- allow(application).to receive(:resolver_path).and_return(resolver_path)
627
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
640
628
  application.action_install
641
- expect(::File.exists?(application.launch_agent_path)).to be_true
629
+ expect(::File.exists?(application.launch_agent_path)).to be_truthy
642
630
 
643
631
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
644
632
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
645
633
  end
646
634
 
647
635
  it "should update the DNS cache" do
648
- allow(application).to receive(:resolver_path).and_return(resolver_path)
649
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
636
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
637
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
650
638
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
651
639
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
652
640
 
653
- expect(application).to receive(:dns_update)
641
+ expect_any_instance_of(DevDNSd::Application).to receive(:dns_update)
654
642
  application.action_install
655
643
 
656
644
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
@@ -658,13 +646,13 @@ describe DevDNSd::Application do
658
646
  end
659
647
 
660
648
  it "should not create an invalid resolver" do
661
- allow(application).to receive(:resolver_path).and_return("/invalid/resolver")
662
- allow(application).to receive(:launch_agent_path).and_return("/invalid/agent")
649
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return("/invalid/resolver")
650
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return("/invalid/agent")
663
651
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
664
652
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
665
653
 
666
- allow(application).to receive(:create_agent).and_return(true)
667
- expect_any_instance_of(R18n::Translation).to receive(:resolver_creating).and_raise(ArgumentError)
654
+ allow_any_instance_of(DevDNSd::Application).to receive(:create_agent).and_return(true)
655
+ expect_any_instance_of(Bovem::I18n).to receive(:resolver_creating).and_raise(ArgumentError)
668
656
  expect(application.logger).to receive(:error).with("Cannot create the resolver file.")
669
657
  application.action_install
670
658
 
@@ -673,8 +661,8 @@ describe DevDNSd::Application do
673
661
  end
674
662
 
675
663
  it "should not create an invalid agent" do
676
- allow(application).to receive(:resolver_path).and_return(resolver_path)
677
- allow(application).to receive(:launch_agent_path).and_return("/invalid/agent")
664
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
665
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return("/invalid/agent")
678
666
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
679
667
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
680
668
 
@@ -690,11 +678,12 @@ describe DevDNSd::Application do
690
678
  command =~ /^launchctl/ ? raise(StandardError) : true
691
679
  end
692
680
 
693
- allow(application).to receive(:resolver_path).and_return(resolver_path)
694
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
681
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
682
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
695
683
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
696
684
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
697
685
 
686
+ allow_any_instance_of(DevDNSd::Application).to receive(:create_agent).and_return(true)
698
687
  expect(application.logger).to receive(:error).with("Cannot load the launch agent.")
699
688
  application.action_install
700
689
 
@@ -703,41 +692,41 @@ describe DevDNSd::Application do
703
692
  end
704
693
 
705
694
  it "should raise an exception if not running on OSX" do
706
- allow(application).to receive(:is_osx?).and_return(false)
695
+ allow_any_instance_of(DevDNSd::Application).to receive(:osx?).and_return(false)
707
696
  expect(application.logger).to receive(:fatal).with("Install DevDNSd as a local resolver is only available on MacOSX.")
708
- expect(application.action_install).to be_false
697
+ expect(application.action_install).to be_falsey
709
698
  end
710
699
  end
711
700
 
712
701
  describe "#action_uninstall" do
713
702
  before(:each) do
714
- allow(application).to receive(:is_osx?).and_return(true)
703
+ allow(application).to receive(:osx?).and_return(true)
715
704
  allow(application).to receive(:execute_command)
716
705
  expect(Kernel).to receive(:system).at_least(1)
717
706
  end
718
707
 
719
708
  it "should remove the resolver" do
720
- allow(application).to receive(:resolver_path).and_return(resolver_path)
721
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
709
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
710
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
722
711
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
723
712
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
724
713
 
725
714
  application.action_install
726
715
  application.action_uninstall
727
- expect(::File.exists?(resolver_path)).to be_false
716
+ expect(::File.exists?(resolver_path)).to be_falsey
728
717
 
729
718
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
730
719
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
731
720
  end
732
721
 
733
722
  it "should not remove an invalid resolver" do
734
- allow(application).to receive(:resolver_path).and_return("/invalid/resolver")
735
- allow(application).to receive(:launch_agent_path).and_return("/invalid/agent")
723
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return("/invalid/resolver")
724
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return("/invalid/agent")
736
725
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
737
726
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
738
727
 
739
728
  allow(application).to receive(:unload_agent).and_return(true)
740
- expect_any_instance_of(R18n::Translation).to receive(:resolver_deleting).and_raise(ArgumentError)
729
+ expect_any_instance_of(Bovem::I18n).to receive(:resolver_deleting).and_raise(ArgumentError)
741
730
  expect(application.logger).to receive(:warn)
742
731
  expect(application.logger).to receive(:warn).with("Cannot delete the resolver file.")
743
732
 
@@ -748,15 +737,30 @@ describe DevDNSd::Application do
748
737
  end
749
738
 
750
739
  it "should remove the agent" do
751
- allow(application).to receive(:resolver_path).and_return(resolver_path)
752
- allow(application).to receive(:launch_agent_path).and_return(launch_agent_path)
740
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
741
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
742
+ ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
743
+ ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
744
+
745
+ allow(Bovem::Logger).to receive(:default_file).and_return($stdout)
746
+ application.action_install
747
+ application.action_uninstall
748
+ expect(::File.exists?(application.launch_agent_path)).to be_falsey
749
+
750
+ ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
751
+ ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
752
+ end
753
+
754
+ it "should not fail if the agent cannot be removed" do
755
+ allow_any_instance_of(DevDNSd::Application).to receive(:resolver_path).and_return(resolver_path)
756
+ allow_any_instance_of(DevDNSd::Application).to receive(:launch_agent_path).and_return(launch_agent_path)
753
757
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
754
758
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
755
759
 
760
+ allow(File).to receive(:delete).and_raise(RuntimeError)
756
761
  allow(Bovem::Logger).to receive(:default_file).and_return($stdout)
757
762
  application.action_install
758
763
  application.action_uninstall
759
- expect(::File.exists?(application.launch_agent_path)).to be_false
760
764
 
761
765
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
762
766
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
@@ -807,7 +811,7 @@ describe DevDNSd::Application do
807
811
  ::File.unlink(application.launch_agent_path) if ::File.exists?(application.launch_agent_path)
808
812
 
809
813
  application.action_install
810
- expect(application).to receive(:dns_update)
814
+ expect_any_instance_of(DevDNSd::Application).to receive(:dns_update)
811
815
  application.action_uninstall
812
816
 
813
817
  ::File.unlink(application.resolver_path) if ::File.exists?(application.resolver_path)
@@ -815,22 +819,22 @@ describe DevDNSd::Application do
815
819
  end
816
820
 
817
821
  it "should raise an exception if not running on OSX" do
818
- allow(application).to receive(:is_osx?).and_return(false)
822
+ allow_any_instance_of(DevDNSd::Application).to receive(:osx?).and_return(false)
819
823
  expect(application.logger).to receive(:fatal).with("Install DevDNSd as a local resolver is only available on MacOSX.")
820
- expect(application.action_uninstall).to be_false
824
+ expect(application.action_uninstall).to be_falsey
821
825
  end
822
826
  end
823
827
 
824
828
  describe "#action_add" do
825
829
  it "should #manage_aliases" do
826
- expect(application).to receive(:manage_aliases).with(:add, "No valid addresses to add to the interface found.", {a: 1})
830
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_aliases).with(:add, "No valid addresses to add to the interface found.", {a: 1})
827
831
  application.action_add({a: 1})
828
832
  end
829
833
  end
830
834
 
831
835
  describe "#action_remove" do
832
836
  it "should #manage_aliases" do
833
- expect(application).to receive(:manage_aliases).with(:remove, "No valid addresses to remove from the interface found.", {a: 1})
837
+ expect_any_instance_of(DevDNSd::Application).to receive(:manage_aliases).with(:remove, "No valid addresses to remove from the interface found.", {a: 1})
834
838
  application.action_remove({a: 1})
835
839
  end
836
840
  end