ronin-db 0.1.0.beta1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (74) hide show
  1. checksums.yaml +7 -0
  2. data/.document +5 -0
  3. data/.github/workflows/ruby.yml +31 -0
  4. data/.gitignore +13 -0
  5. data/.rspec +1 -0
  6. data/.ruby-version +1 -0
  7. data/.yardopts +1 -0
  8. data/COPYING.txt +165 -0
  9. data/ChangeLog.md +12 -0
  10. data/Gemfile +39 -0
  11. data/README.md +272 -0
  12. data/Rakefile +76 -0
  13. data/bin/ronin-db +35 -0
  14. data/gemspec.yml +46 -0
  15. data/lib/ronin/db/cli/command.rb +37 -0
  16. data/lib/ronin/db/cli/commands/add.rb +206 -0
  17. data/lib/ronin/db/cli/commands/asn.rb +218 -0
  18. data/lib/ronin/db/cli/commands/creds.rb +80 -0
  19. data/lib/ronin/db/cli/commands/edit.rb +58 -0
  20. data/lib/ronin/db/cli/commands/emails.rb +90 -0
  21. data/lib/ronin/db/cli/commands/hosts.rb +100 -0
  22. data/lib/ronin/db/cli/commands/ips.rb +100 -0
  23. data/lib/ronin/db/cli/commands/irb.rb +81 -0
  24. data/lib/ronin/db/cli/commands/list.rb +124 -0
  25. data/lib/ronin/db/cli/commands/migrate.rb +75 -0
  26. data/lib/ronin/db/cli/commands/remove.rb +69 -0
  27. data/lib/ronin/db/cli/commands/urls.rb +170 -0
  28. data/lib/ronin/db/cli/database_command.rb +71 -0
  29. data/lib/ronin/db/cli/model_command.rb +202 -0
  30. data/lib/ronin/db/cli/modifiable.rb +141 -0
  31. data/lib/ronin/db/cli/resources_command.rb +120 -0
  32. data/lib/ronin/db/cli/ruby_shell.rb +51 -0
  33. data/lib/ronin/db/cli/uri_methods.rb +97 -0
  34. data/lib/ronin/db/cli.rb +38 -0
  35. data/lib/ronin/db/config_file.rb +132 -0
  36. data/lib/ronin/db/exceptions.rb +26 -0
  37. data/lib/ronin/db/home.rb +36 -0
  38. data/lib/ronin/db/root.rb +28 -0
  39. data/lib/ronin/db/version.rb +26 -0
  40. data/lib/ronin/db.rb +123 -0
  41. data/man/ronin-db-add.1 +99 -0
  42. data/man/ronin-db-add.1.md +75 -0
  43. data/man/ronin-db-asn.1 +79 -0
  44. data/man/ronin-db-asn.1.md +59 -0
  45. data/man/ronin-db-creds.1 +78 -0
  46. data/man/ronin-db-creds.1.md +58 -0
  47. data/man/ronin-db-edit.1 +48 -0
  48. data/man/ronin-db-edit.1.md +36 -0
  49. data/man/ronin-db-emails.1 +82 -0
  50. data/man/ronin-db-emails.1.md +61 -0
  51. data/man/ronin-db-hosts.1 +86 -0
  52. data/man/ronin-db-hosts.1.md +64 -0
  53. data/man/ronin-db-ips.1 +90 -0
  54. data/man/ronin-db-ips.1.md +67 -0
  55. data/man/ronin-db-irb.1 +61 -0
  56. data/man/ronin-db-irb.1.md +46 -0
  57. data/man/ronin-db-list.1 +58 -0
  58. data/man/ronin-db-list.1.md +44 -0
  59. data/man/ronin-db-migrate.1 +44 -0
  60. data/man/ronin-db-migrate.1.md +32 -0
  61. data/man/ronin-db-remove.1 +55 -0
  62. data/man/ronin-db-remove.1.md +42 -0
  63. data/man/ronin-db-urls.1 +98 -0
  64. data/man/ronin-db-urls.1.md +73 -0
  65. data/ronin-db.gemspec +78 -0
  66. data/spec/cli/commands/add_spec.rb +220 -0
  67. data/spec/cli/commands/edit_spec.rb +12 -0
  68. data/spec/cli/commands/irb_spec.rb +26 -0
  69. data/spec/cli/database_command_spec.rb +53 -0
  70. data/spec/cli/model_command_spec.rb +237 -0
  71. data/spec/cli/ruby_shell_spec.rb +14 -0
  72. data/spec/cli/uri_methods_spec.rb +190 -0
  73. data/spec/spec_helper.rb +15 -0
  74. metadata +200 -0
@@ -0,0 +1,73 @@
1
+ # ronin-db-urls 1 "April 2012" Ronin "User Manuals"
2
+
3
+ ## SYNOPSIS
4
+
5
+ `ronin-db urls` [*options*]
6
+
7
+ ## DESCRIPTION
8
+
9
+ Manages URLs.
10
+
11
+ ## OPTIONS
12
+
13
+ `--db` *NAME*
14
+ The database to connect to. Defaults to `default` if not given.
15
+
16
+ `--db-uri` *URI*
17
+ The explicit database URI to connect to
18
+ (ex: `mysql://user:password@host/ronin`).
19
+
20
+ `-v`, `--verbose`
21
+ Enable verbose output.
22
+
23
+ `--add` *USER*:*PASSWORD*
24
+ Adds the *USER* and *PASSWORD* to the database.
25
+
26
+ `--import` *FILE*
27
+ Imports the credentials from the given *FILE*.
28
+
29
+ `--delete` *VALUE*
30
+ Deletes a value from the database.
31
+
32
+ `--delete-all`
33
+ Deletes every value from the database.
34
+
35
+ `--http`
36
+ Searches for `http://` URLs.
37
+
38
+ `--https`
39
+ Searches for `https://` URLs.
40
+
41
+ `-H`, `--host` *HOST*
42
+ Searches for URLs with the given *HOST*.
43
+
44
+ `-p`, `--with-port` *PORT*
45
+ Searches for URLs associated with the *PORT*.
46
+
47
+ `-d`, `--directory` *DIRECTORY*
48
+ Searches for URLs sharing the DIRECTORY.
49
+
50
+ `-q`, `--with-query-param` *NAME* [...]
51
+ Searches for URLs containing the query-param NAME.
52
+
53
+ `-Q`, `--with-query-value` *VALUE* [...]
54
+ Searches for URLs containing the query-param VALUE.
55
+
56
+ ## FILES
57
+
58
+ *~/.ronin/*
59
+ Ronin configuration directory.
60
+
61
+ *~/.ronin/database.log*
62
+ Database log.
63
+
64
+ *~/.ronin/database.sqlite3*
65
+ The default sqlite3 Database file.
66
+
67
+ *~/.ronin/database.yml*
68
+ Optional Database configuration.
69
+
70
+ ## AUTHOR
71
+
72
+ Postmodern <postmodern.mod3@gmail.com>
73
+
data/ronin-db.gemspec ADDED
@@ -0,0 +1,78 @@
1
+ # encoding: utf-8
2
+
3
+ require 'yaml'
4
+
5
+ Gem::Specification.new do |gem|
6
+ gemspec = YAML.load_file('gemspec.yml')
7
+
8
+ gem.name = gemspec.fetch('name')
9
+ gem.version = gemspec.fetch('version') do
10
+ lib_dir = File.join(File.dirname(__FILE__),'lib')
11
+ $LOAD_PATH << lib_dir unless $LOAD_PATH.include?(lib_dir)
12
+
13
+ require 'ronin/db/version'
14
+ Ronin::DB::VERSION
15
+ end
16
+
17
+ gem.summary = gemspec['summary']
18
+ gem.description = gemspec['description']
19
+ gem.licenses = Array(gemspec['license'])
20
+ gem.authors = Array(gemspec['authors'])
21
+ gem.email = gemspec['email']
22
+ gem.homepage = gemspec['homepage']
23
+ gem.metadata = gemspec['metadata'] if gemspec['metadata']
24
+
25
+ glob = lambda { |patterns| gem.files & Dir[*patterns] }
26
+
27
+ gem.files = `git ls-files`.split($/)
28
+ gem.files = glob[gemspec['files']] if gemspec['files']
29
+ gem.files += Array(gemspec['generated_files'])
30
+
31
+ gem.executables = gemspec.fetch('executables') do
32
+ glob['bin/*'].map { |path| File.basename(path) }
33
+ end
34
+ gem.default_executable = gem.executables.first if Gem::VERSION < '1.7.'
35
+
36
+ gem.extensions = glob[gemspec['extensions'] || 'ext/**/extconf.rb']
37
+ gem.test_files = glob[gemspec['test_files'] || 'spec/{**/}*_spec.rb']
38
+ gem.extra_rdoc_files = glob[gemspec['extra_doc_files'] || '*.{txt,md}']
39
+
40
+ gem.require_paths = Array(gemspec.fetch('require_paths') {
41
+ %w[ext lib].select { |dir| File.directory?(dir) }
42
+ })
43
+
44
+ gem.requirements = gemspec['requirements']
45
+ gem.required_ruby_version = gemspec['required_ruby_version']
46
+ gem.required_rubygems_version = gemspec['required_rubygems_version']
47
+ gem.post_install_message = gemspec['post_install_message']
48
+
49
+ split = lambda { |string| string.split(/,\s*/) }
50
+
51
+ if RUBY_PLATFORM =~ /java/
52
+ gem.platform = Gem::Platform.new("java")
53
+
54
+ if gemspec['jruby_dependencies']
55
+ gemspec['jruby_dependencies'].each do |name,versions|
56
+ gem.add_dependency(name,split[versions])
57
+ end
58
+ end
59
+ else
60
+ if gemspec['ruby_dependencies']
61
+ gemspec['ruby_dependencies'].each do |name,versions|
62
+ gem.add_dependency(name,split[versions])
63
+ end
64
+ end
65
+ end
66
+
67
+ if gemspec['dependencies']
68
+ gemspec['dependencies'].each do |name,versions|
69
+ gem.add_dependency(name,split[versions])
70
+ end
71
+ end
72
+
73
+ if gemspec['development_dependencies']
74
+ gemspec['development_dependencies'].each do |name,versions|
75
+ gem.add_development_dependency(name,split[versions])
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,220 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/cli/commands/add'
3
+
4
+ describe Ronin::DB::CLI::Commands::Add do
5
+ describe "options" do
6
+ before { subject.parse_options(argv) }
7
+
8
+ describe "--adapter" do
9
+ let(:adapter) { 'sqlite3' }
10
+ let(:argv) { ['--adapter', adapter] }
11
+
12
+ it "must set #config[:adapter]" do
13
+ expect(subject.config[:adapter]).to eq(adapter)
14
+ end
15
+ end
16
+
17
+ describe "--sqlite3" do
18
+ let(:database) { '/path/to/file.sqlite3' }
19
+ let(:argv) { ['--sqlite3', database] }
20
+
21
+ it "must set #config[:adapter] to 'sqlite3'" do
22
+ expect(subject.config[:adapter]).to eq('sqlite3')
23
+ end
24
+
25
+ it "must set #config[:database] to the given path" do
26
+ expect(subject.config[:database]).to eq(database)
27
+ end
28
+
29
+ context "when the argument is a relative path" do
30
+ let(:database) { 'file.sqlite3' }
31
+
32
+ it "must expand the relative path before setting #config[:database]" do
33
+ expect(subject.config[:database]).to eq(File.expand_path(database))
34
+ end
35
+ end
36
+ end
37
+
38
+ describe "--mysql2" do
39
+ let(:argv) { ['--mysql2'] }
40
+
41
+ it "must set #config[:adapter] to 'mysql2'" do
42
+ expect(subject.config[:adapter]).to eq('mysql2')
43
+ end
44
+ end
45
+
46
+ describe "--postgresql" do
47
+ let(:argv) { ['--postgresql'] }
48
+
49
+ it "must set #config[:adapter] to 'postgresql'" do
50
+ expect(subject.config[:adapter]).to eq('postgresql')
51
+ end
52
+ end
53
+
54
+ describe "--host" do
55
+ let(:host) { 'example.com' }
56
+ let(:argv) { ['--host', host] }
57
+
58
+ it "must set #config[:host]" do
59
+ expect(subject.config[:host]).to eq(host)
60
+ end
61
+ end
62
+
63
+ describe "--port" do
64
+ let(:port) { 1234 }
65
+ let(:argv) { ['--port', port.to_s] }
66
+
67
+ it "must set #config[:port]" do
68
+ expect(subject.config[:port]).to eq(port)
69
+ end
70
+ end
71
+
72
+ describe "--username" do
73
+ let(:username) { 'foo' }
74
+ let(:argv) { ['--username', username] }
75
+
76
+ it "must set #config[:username]" do
77
+ expect(subject.config[:username]).to eq(username)
78
+ end
79
+ end
80
+
81
+ describe "--password" do
82
+ let(:password) { 'secret' }
83
+ let(:argv) { ['--password', password] }
84
+
85
+ it "must set #config[:password]" do
86
+ expect(subject.config[:password]).to eq(password)
87
+ end
88
+ end
89
+
90
+ describe "--database" do
91
+ let(:database) { 'foo' }
92
+ let(:argv) { ['--database', database] }
93
+
94
+ it "must set #config[:database]" do
95
+ expect(subject.config[:database]).to eq(database)
96
+ end
97
+ end
98
+ end
99
+
100
+ describe "#initialize" do
101
+ it "must initialize #config to an empty Hash" do
102
+ expect(subject.config).to eq({})
103
+ end
104
+ end
105
+
106
+ describe "#run" do
107
+ let(:adapter) { 'sqlite3' }
108
+ let(:database) { '/path/to/test.sqlite3' }
109
+ let(:name) { 'test' }
110
+
111
+ let(:config_file_hash) { {} }
112
+
113
+ context "when given a URI argument" do
114
+ let(:uri) { "#{adapter}:#{database}" }
115
+
116
+ it "must parse the URI, call ConfigFile.edit, and add #config to it with the given NAME argument" do
117
+ expect(Ronin::DB::ConfigFile).to receive(:edit).and_yield(config_file_hash)
118
+
119
+ subject.run(name,uri)
120
+
121
+ expect(config_file_hash[name]).to eq(
122
+ {
123
+ adapter: adapter,
124
+ database: database
125
+ }
126
+ )
127
+ end
128
+ end
129
+
130
+ context "when given options instead of a URI argument" do
131
+ let(:argv) do
132
+ [
133
+ '--adapter', adapter,
134
+ '--database', database
135
+ ]
136
+ end
137
+
138
+ before { subject.parse_options(argv) }
139
+
140
+ it "must call ConfigFile.edit and add #config to it with the given NAME argument" do
141
+ expect(Ronin::DB::ConfigFile).to receive(:edit).and_yield(config_file_hash)
142
+
143
+ subject.run(name)
144
+
145
+ expect(config_file_hash[name]).to eq(
146
+ {
147
+ adapter: adapter,
148
+ database: database
149
+ }
150
+ )
151
+ end
152
+ end
153
+
154
+ context "when #config[:adapter] is not set" do
155
+ let(:argv) { ['--database', '/path/to/db.sqlite3'] }
156
+
157
+ before { subject.parse_options(argv) }
158
+
159
+ it "must print an error message and exit with 1" do
160
+ expect {
161
+ subject.run(name)
162
+ }.to output("add: must specify a URI or the --adapter option#{$/}").to_stderr.and(raise_error(SystemExit))
163
+ end
164
+ end
165
+
166
+ context "when #config[:database] is not set" do
167
+ let(:argv) { ['--adapter', 'sqlite3'] }
168
+
169
+ before { subject.parse_options(argv) }
170
+
171
+ it "must print an error message and exit with 1" do
172
+ expect {
173
+ subject.run(name)
174
+ }.to output("add: must specify a URI or the --database option#{$/}").to_stderr.and(raise_error(SystemExit))
175
+ end
176
+ end
177
+ end
178
+
179
+ describe "#read_password" do
180
+ let(:password) { 'secret' }
181
+
182
+ it "must call #ask_secret with 'Password' and set config[:password]" do
183
+ expect(subject).to receive(:ask_secret).with('Password').and_return(password)
184
+
185
+ subject.read_password
186
+
187
+ expect(subject.config[:password]).to eq(password)
188
+ end
189
+ end
190
+
191
+ describe "#validate_config!" do
192
+ context "when #config[:adapter] is not set" do
193
+ before do
194
+ subject.config[:database] = '/path/to/db.sqlite3'
195
+ end
196
+
197
+ it "must print an error message and exit with 1" do
198
+ expect(subject).to receive(:exit).with(1)
199
+
200
+ expect {
201
+ subject.validate_config!
202
+ }.to output("add: must specify a URI or the --adapter option#{$/}").to_stderr
203
+ end
204
+ end
205
+
206
+ context "when #config[:database] is not set" do
207
+ before do
208
+ subject.config[:adapter] = 'sqlite3'
209
+ end
210
+
211
+ it "must print an error message and exit with 1" do
212
+ expect(subject).to receive(:exit).with(1)
213
+
214
+ expect {
215
+ subject.validate_config!
216
+ }.to output("add: must specify a URI or the --database option#{$/}").to_stderr
217
+ end
218
+ end
219
+ end
220
+ end
@@ -0,0 +1,12 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/cli/commands/edit'
3
+
4
+ describe Ronin::DB::CLI::Commands::Edit do
5
+ describe "#run" do
6
+ it "must edit the ConfigFile::PATH" do
7
+ expect(subject).to receive(:edit).with(Ronin::DB::ConfigFile::PATH)
8
+
9
+ subject.run
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,26 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/cli/commands/irb'
3
+
4
+ describe Ronin::DB::CLI::Commands::Irb do
5
+ describe "#run" do
6
+ it "must call #connet, then #load_models, then CLI::RubyShell.start" do
7
+ expect(subject).to receive(:connect)
8
+ expect(subject).to receive(:load_models)
9
+ expect(Ronin::DB::CLI::RubyShell).to receive(:start)
10
+
11
+ subject.run
12
+ end
13
+
14
+ context "when #options[:no_connect] is set" do
15
+ before { subject.options[:no_connect] = true }
16
+
17
+ it "must not call #connet or #load_models" do
18
+ expect(subject).to_not receive(:connect)
19
+ expect(subject).to_not receive(:load_models)
20
+ expect(Ronin::DB::CLI::RubyShell).to receive(:start)
21
+
22
+ subject.run
23
+ end
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,53 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/cli/database_command'
3
+
4
+ describe Ronin::DB::CLI::DatabaseCommand do
5
+ describe "#config" do
6
+ context "when neither options[:db] nor options[:db_uri] are set" do
7
+ it "must default to connecting to the :default database" do
8
+ expect(subject.config).to eq(Ronin::DB.config[:default])
9
+ end
10
+ end
11
+
12
+ context "when options[:db] is set" do
13
+ let(:db_name) { :test }
14
+ let(:config) do
15
+ {
16
+ db_name => {
17
+ adapter: 'sqlite3',
18
+ database: '/path/to/db.sqlite3'
19
+ }
20
+ }
21
+ end
22
+
23
+ before do
24
+ allow(Ronin::DB).to receive(:config).and_return(config)
25
+
26
+ subject.options[:db] = db_name
27
+ end
28
+
29
+ it "must return the database configuration for options[:db]" do
30
+ expect(subject.config).to eq(Ronin::DB.config[db_name])
31
+ end
32
+ end
33
+
34
+ context "when options[:db_uri] is set" do
35
+ let(:db_uri) { "postgres://user:password@host:1234/database" }
36
+ let(:parsed_uri) { subject.parse_uri(subject.options[:db_uri]) }
37
+
38
+ before { subject.options[:db_uri] = db_uri }
39
+
40
+ it "must return the parsed URI for options[:db_uri]" do
41
+ expect(subject.config).to eq(parsed_uri)
42
+ end
43
+ end
44
+ end
45
+
46
+ describe "#connect" do
47
+ it "must call ActiveRecord::Base.establish_connection with #config" do
48
+ expect(ActiveRecord::Base).to receive(:establish_connection).with(subject.config)
49
+
50
+ subject.connect
51
+ end
52
+ end
53
+ end
@@ -0,0 +1,237 @@
1
+ require 'spec_helper'
2
+ require 'ronin/db/cli/model_command'
3
+ require 'ronin/db/ip_address'
4
+ require 'ronin/db/host_name'
5
+
6
+ describe Ronin::DB::CLI::ModelCommand do
7
+ it "must inherit from Ronin::DB::CLI::DatabaseCommand" do
8
+ expect(described_class).to be < Ronin::DB::CLI::DatabaseCommand
9
+ end
10
+
11
+ describe ".model_file" do
12
+ subject { test_class }
13
+
14
+ context "and when model_file is not set in the class" do
15
+ module TestModelCommand
16
+ class WithNoModelFileSet < Ronin::DB::CLI::ModelCommand
17
+ end
18
+ end
19
+
20
+ let(:test_class) { TestModelCommand::WithNoModelFileSet }
21
+
22
+ it do
23
+ expect {
24
+ subject.model_file
25
+ }.to raise_error(NotImplementedError,"#{subject} did not define model_file")
26
+ end
27
+ end
28
+
29
+ context "and when model_file is set in the class" do
30
+ module TestModelCommand
31
+ class WithModelFileSet < Ronin::DB::CLI::ModelCommand
32
+ model_file 'ronin/db/test'
33
+ end
34
+ end
35
+
36
+ let(:test_class) { TestModelCommand::WithModelFileSet }
37
+
38
+ it "must return the set model_file" do
39
+ expect(subject.model_file).to eq('ronin/db/test')
40
+ end
41
+ end
42
+
43
+ context "but when the model_file was set in the superclass" do
44
+ module TestModelCommand
45
+ class InheritsItsModelFile < WithModelFileSet
46
+ end
47
+ end
48
+
49
+ let(:test_class) { TestModelCommand::InheritsItsModelFile }
50
+
51
+ it "must return the model_file set in the superclass" do
52
+ expect(subject.model_file).to eq('ronin/db/test')
53
+ end
54
+
55
+ context "but the model_file is overridden in the sub-class" do
56
+ module TestModelCommand
57
+ class OverridesItsInheritedModelFile < WithModelFileSet
58
+ model_file 'ronin/db/test2'
59
+ end
60
+ end
61
+
62
+ let(:test_class) do
63
+ TestModelCommand::OverridesItsInheritedModelFile
64
+ end
65
+
66
+ it "must return the model_file set in the sub-class" do
67
+ expect(subject.model_file).to eq('ronin/db/test2')
68
+ end
69
+
70
+ it "must not modify the superclass'es model_file" do
71
+ expect(subject.superclass.model_file).to eq('ronin/db/test')
72
+ end
73
+ end
74
+ end
75
+ end
76
+
77
+ describe ".model_name" do
78
+ subject { test_class }
79
+
80
+ context "and when model_name is not set in the class" do
81
+ module TestModelCommand
82
+ class WithNoModelNameSet < Ronin::DB::CLI::ModelCommand
83
+ end
84
+ end
85
+
86
+ let(:test_class) { TestModelCommand::WithNoModelNameSet }
87
+
88
+ it do
89
+ expect {
90
+ subject.model_name
91
+ }.to raise_error(NotImplementedError,"#{subject} did not define model_name")
92
+ end
93
+ end
94
+
95
+ context "and when model_name is set in the class" do
96
+ module TestModelCommand
97
+ class WithModelNameSet < Ronin::DB::CLI::ModelCommand
98
+ model_name 'Test'
99
+ end
100
+ end
101
+
102
+ let(:test_class) { TestModelCommand::WithModelNameSet }
103
+
104
+ it "must return the set model_name" do
105
+ expect(subject.model_name).to eq('Test')
106
+ end
107
+ end
108
+
109
+ context "but when the model_name was set in the superclass" do
110
+ module TestModelCommand
111
+ class InheritsItsModelName < WithModelNameSet
112
+ end
113
+ end
114
+
115
+ let(:test_class) { TestModelCommand::InheritsItsModelName }
116
+
117
+ it "must return the model_name set in the superclass" do
118
+ expect(subject.model_name).to eq('Test')
119
+ end
120
+
121
+ context "but the model_name is overridden in the sub-class" do
122
+ module TestModelCommand
123
+ class OverridesItsInheritedModelName < WithModelNameSet
124
+ model_name 'Test2'
125
+ end
126
+ end
127
+
128
+ let(:test_class) do
129
+ TestModelCommand::OverridesItsInheritedModelName
130
+ end
131
+
132
+ it "must return the model_name set in the sub-class" do
133
+ expect(subject.model_name).to eq('Test2')
134
+ end
135
+
136
+ it "must not modify the superclass'es model_name" do
137
+ expect(subject.superclass.model_name).to eq('Test')
138
+ end
139
+ end
140
+ end
141
+ end
142
+
143
+ describe ".model_name" do
144
+ end
145
+
146
+ module TestModelCommand
147
+ class TestCommand < Ronin::DB::CLI::ModelCommand
148
+ model_file 'ronin/db/ip_address'
149
+ model_name 'IPAddress'
150
+ end
151
+ end
152
+
153
+ let(:test_command) { TestModelCommand::TestCommand }
154
+ subject { test_command.new }
155
+
156
+ describe "#initialize" do
157
+ it "must initialize #query_method_calls to an empty Array" do
158
+ expect(subject.query_method_calls).to eq([])
159
+ end
160
+ end
161
+
162
+ describe "#model" do
163
+ it "must resolve the class for the model within Ronin::DB::" do
164
+ expect(subject.model).to be(Ronin::DB.const_get(subject.class.model_name))
165
+ end
166
+ end
167
+
168
+ describe "#query" do
169
+ let(:host) { 'example.com' }
170
+ let(:ipv4) { '93.184.216.34' }
171
+ let(:ipv6) { '2606:2800:220:1:248:1893:25c8:1946' }
172
+
173
+ before do
174
+ host_name = Ronin::DB::HostName.create(name: host)
175
+
176
+ Ronin::DB::IPAddress.create(address: '127.0.0.1', version: 4)
177
+ Ronin::DB::IPAddress.create(
178
+ address: ipv4,
179
+ version: 4,
180
+ host_names: [host_name]
181
+ )
182
+ Ronin::DB::IPAddress.create(
183
+ address: ipv6,
184
+ version: 6,
185
+ host_names: [host_name]
186
+ )
187
+ Ronin::DB::IPAddress.create(address: '::1', version: 6)
188
+ end
189
+
190
+ context "when #query_method_calls is empty" do
191
+ it "must return a ActiveRecord_Relation object" do
192
+ expect(subject.query).to be_kind_of(
193
+ subject.model.const_get('ActiveRecord_Relation')
194
+ )
195
+ end
196
+ end
197
+
198
+ context "when #query_method_calls contains a :where method call" do
199
+ before do
200
+ subject.query_method_calls << [:where, [], {version: 4}]
201
+ end
202
+
203
+ it "must invoke #where with the given arguments on the query" do
204
+ expect(subject.query).to eq(
205
+ Ronin::DB::IPAddress.where(version: 4)
206
+ )
207
+ end
208
+ end
209
+
210
+ context "when #query_method_calls contains a scoped query method call" do
211
+ before do
212
+ subject.query_method_calls << [:with_host_name, [host]]
213
+ end
214
+
215
+ it "must invoke the scoped query method on the query" do
216
+ expect(subject.query).to eq(
217
+ Ronin::DB::IPAddress.with_host_name(host)
218
+ )
219
+ end
220
+ end
221
+
222
+ after do
223
+ Ronin::DB::IPAddress.destroy_all
224
+ Ronin::DB::HostName.destroy_all
225
+ end
226
+ end
227
+
228
+ describe "#print_record" do
229
+ let(:record) { Ronin::DB::IPAddress.new(address: '127.0.0.1') }
230
+
231
+ it "must print the record using #puts" do
232
+ expect {
233
+ subject.print_record(record)
234
+ }.to output("#{record}#{$/}").to_stdout
235
+ end
236
+ end
237
+ end