devdnsd 3.1.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (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