puppet 2.7.13 → 2.7.14

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of puppet might be problematic. Click here for more details.

Files changed (215) hide show
  1. data/CHANGELOG +144 -1
  2. data/conf/osx/preflight +1 -1
  3. data/conf/redhat/puppet.spec +9 -5
  4. data/conf/suse/puppet.spec +4 -1
  5. data/conf/windows/eventlog/Rakefile +32 -0
  6. data/conf/windows/eventlog/puppetres.dll +0 -0
  7. data/conf/windows/eventlog/puppetres.mc +18 -0
  8. data/ext/rack/files/apache2.conf +3 -0
  9. data/install.rb +23 -1
  10. data/lib/puppet.rb +1 -1
  11. data/lib/puppet/agent.rb +1 -14
  12. data/lib/puppet/application/kick.rb +1 -1
  13. data/lib/puppet/application/module.rb +11 -0
  14. data/lib/puppet/daemon.rb +74 -3
  15. data/lib/puppet/defaults.rb +1 -1
  16. data/lib/puppet/face/certificate.rb +1 -1
  17. data/lib/puppet/face/help/man.erb +1 -1
  18. data/lib/puppet/face/module.rb +17 -0
  19. data/lib/puppet/face/module/build.rb +10 -4
  20. data/lib/puppet/face/module/changes.rb +5 -5
  21. data/lib/puppet/face/module/generate.rb +6 -4
  22. data/lib/puppet/face/module/install.rb +122 -32
  23. data/lib/puppet/face/module/list.rb +234 -33
  24. data/lib/puppet/face/module/search.rb +56 -23
  25. data/lib/puppet/face/module/uninstall.rb +33 -38
  26. data/lib/puppet/face/module/upgrade.rb +84 -0
  27. data/lib/puppet/feature/eventlog.rb +6 -0
  28. data/lib/puppet/forge.rb +67 -122
  29. data/lib/puppet/forge/cache.rb +1 -1
  30. data/lib/puppet/forge/repository.rb +6 -25
  31. data/lib/puppet/indirector/facts/network_device.rb +1 -1
  32. data/lib/puppet/interface/action.rb +1 -1
  33. data/lib/puppet/module.rb +79 -28
  34. data/lib/puppet/module_tool.rb +72 -34
  35. data/lib/puppet/module_tool/applications.rb +12 -14
  36. data/lib/puppet/module_tool/applications/application.rb +21 -19
  37. data/lib/puppet/module_tool/applications/builder.rb +4 -4
  38. data/lib/puppet/module_tool/applications/checksummer.rb +12 -3
  39. data/lib/puppet/module_tool/applications/generator.rb +1 -1
  40. data/lib/puppet/module_tool/applications/installer.rb +163 -34
  41. data/lib/puppet/module_tool/applications/searcher.rb +2 -3
  42. data/lib/puppet/module_tool/applications/uninstaller.rb +84 -36
  43. data/lib/puppet/module_tool/applications/unpacker.rb +4 -26
  44. data/lib/puppet/module_tool/applications/upgrader.rb +109 -0
  45. data/lib/puppet/module_tool/checksums.rb +2 -2
  46. data/lib/puppet/module_tool/contents_description.rb +1 -1
  47. data/lib/puppet/module_tool/dependency.rb +2 -2
  48. data/lib/puppet/module_tool/errors.rb +9 -0
  49. data/lib/puppet/module_tool/errors/base.rb +15 -0
  50. data/lib/puppet/module_tool/errors/installer.rb +90 -0
  51. data/lib/puppet/module_tool/errors/shared.rb +115 -0
  52. data/lib/puppet/module_tool/errors/uninstaller.rb +45 -0
  53. data/lib/puppet/module_tool/errors/upgrader.rb +72 -0
  54. data/lib/puppet/module_tool/metadata.rb +2 -2
  55. data/lib/puppet/module_tool/modulefile.rb +7 -7
  56. data/lib/puppet/module_tool/shared_behaviors.rb +161 -0
  57. data/lib/puppet/module_tool/skeleton.rb +1 -1
  58. data/lib/puppet/node/environment.rb +4 -2
  59. data/lib/puppet/parser/ast/leaf.rb +1 -1
  60. data/lib/puppet/parser/functions/create_resources.rb +3 -2
  61. data/lib/puppet/parser/scope.rb +44 -9
  62. data/lib/puppet/provider/augeas/augeas.rb +2 -2
  63. data/lib/puppet/provider/exec.rb +8 -3
  64. data/lib/puppet/provider/exec/shell.rb +1 -2
  65. data/lib/puppet/provider/nameservice/directoryservice.rb +10 -4
  66. data/lib/puppet/provider/package/gem.rb +1 -1
  67. data/lib/puppet/provider/package/pkg.rb +10 -21
  68. data/lib/puppet/provider/selmodule/semodule.rb +1 -2
  69. data/lib/puppet/provider/service/upstart.rb +33 -17
  70. data/lib/puppet/provider/ssh_authorized_key/parsed.rb +1 -1
  71. data/lib/puppet/rails/inventory_node.rb +7 -7
  72. data/lib/puppet/reports/http.rb +4 -1
  73. data/lib/puppet/reports/tagmail.rb +8 -1
  74. data/lib/puppet/resource/type.rb +1 -1
  75. data/lib/puppet/test/test_helper.rb +138 -0
  76. data/lib/puppet/type.rb +9 -1
  77. data/lib/puppet/type/file.rb +18 -10
  78. data/lib/puppet/type/package.rb +13 -9
  79. data/lib/puppet/type/resources.rb +1 -1
  80. data/lib/puppet/type/ssh_authorized_key.rb +3 -4
  81. data/lib/puppet/type/sshkey.rb +4 -4
  82. data/lib/puppet/type/user.rb +1 -0
  83. data/lib/puppet/type/vlan.rb +1 -1
  84. data/lib/puppet/util.rb +31 -14
  85. data/lib/puppet/util/autoload.rb +1 -1
  86. data/lib/puppet/util/command_line.rb +2 -6
  87. data/lib/puppet/util/instrumentation/indirection_probe.rb +1 -1
  88. data/lib/puppet/util/instrumentation/instrumentable.rb +1 -1
  89. data/lib/puppet/util/instrumentation/listeners/log.rb +1 -1
  90. data/lib/puppet/util/instrumentation/listeners/performance.rb +1 -1
  91. data/lib/puppet/util/log.rb +3 -1
  92. data/lib/puppet/util/log/destinations.rb +38 -0
  93. data/lib/puppet/util/monkey_patches.rb +45 -0
  94. data/lib/puppet/util/network_device/base.rb +1 -1
  95. data/lib/puppet/util/network_device/cisco.rb +1 -1
  96. data/lib/puppet/util/network_device/cisco/facts.rb +1 -1
  97. data/lib/puppet/util/network_device/cisco/interface.rb +1 -1
  98. data/lib/puppet/util/network_device/config.rb +1 -1
  99. data/lib/puppet/util/network_device/ipcalc.rb +1 -1
  100. data/lib/puppet/util/network_device/transport.rb +1 -1
  101. data/lib/puppet/util/network_device/transport/base.rb +1 -1
  102. data/lib/puppet/util/network_device/transport/ssh.rb +1 -1
  103. data/lib/puppet/util/settings.rb +2 -11
  104. data/lib/puppet/util/settings/file_setting.rb +3 -5
  105. data/lib/puppet/util/terminal.rb +16 -0
  106. data/lib/puppet/util/zaml.rb +3 -1
  107. data/lib/semver.rb +15 -7
  108. data/spec/fixtures/releases/jamtur01-apache/metadata.json +1 -1
  109. data/spec/fixtures/unit/parser/lexer/arithmetic_expression.pp +1 -1
  110. data/spec/fixtures/unit/provider/package/pkg/dummy +1 -0
  111. data/spec/fixtures/unit/provider/package/pkg/incomplete +1 -0
  112. data/spec/fixtures/unit/provider/package/pkg/publisher +2 -0
  113. data/spec/fixtures/unit/provider/package/pkg/simple +4 -0
  114. data/spec/fixtures/unit/reports/tagmail/tagmail_email.conf +2 -0
  115. data/spec/fixtures/yaml/report0.25.x.yaml +1 -1
  116. data/spec/fixtures/yaml/report2.6.x.yaml +1 -1
  117. data/spec/integration/faces/documentation_spec.rb +1 -1
  118. data/spec/integration/network/rest_authconfig_spec.rb +1 -1
  119. data/spec/lib/puppet_spec/compiler.rb +6 -0
  120. data/spec/lib/puppet_spec/database.rb +30 -0
  121. data/spec/lib/puppet_spec/files.rb +4 -2
  122. data/spec/shared_behaviours/path_parameters.rb +2 -29
  123. data/spec/shared_contexts/platform.rb +43 -0
  124. data/spec/spec_helper.rb +36 -65
  125. data/spec/unit/agent_spec.rb +0 -32
  126. data/spec/unit/application/kick_spec.rb +2 -2
  127. data/spec/unit/daemon_spec.rb +1 -17
  128. data/spec/unit/face/module/install_spec.rb +158 -0
  129. data/spec/unit/face/module/list_spec.rb +182 -0
  130. data/spec/unit/face/module/search_spec.rb +163 -0
  131. data/spec/unit/face/module/uninstall_spec.rb +77 -0
  132. data/spec/unit/face/module/upgrade_spec.rb +26 -0
  133. data/spec/unit/forge/repository_spec.rb +0 -30
  134. data/spec/unit/forge_spec.rb +28 -86
  135. data/spec/unit/indirector/catalog/active_record_spec.rb +45 -65
  136. data/spec/unit/indirector/facts/inventory_active_record_spec.rb +5 -18
  137. data/spec/unit/indirector/resource/active_record_spec.rb +2 -11
  138. data/spec/unit/indirector/resource/ral_spec.rb +7 -2
  139. data/spec/unit/module_spec.rb +240 -107
  140. data/spec/unit/module_tool/application_spec.rb +3 -5
  141. data/spec/unit/module_tool/applications/application_spec.rb +19 -0
  142. data/spec/unit/module_tool/applications/installer_spec.rb +205 -0
  143. data/spec/unit/module_tool/applications/uninstaller_spec.rb +206 -0
  144. data/spec/unit/module_tool/applications/upgrader_spec.rb +37 -0
  145. data/spec/unit/module_tool/metadata_spec.rb +2 -2
  146. data/spec/unit/module_tool_spec.rb +109 -1
  147. data/spec/unit/node/environment_spec.rb +16 -1
  148. data/spec/unit/parser/ast/leaf_spec.rb +16 -1
  149. data/spec/unit/parser/collector_spec.rb +2 -12
  150. data/spec/unit/parser/functions/create_resources_spec.rb +135 -86
  151. data/spec/unit/parser/functions/generate_spec.rb +2 -10
  152. data/spec/unit/parser/scope_spec.rb +345 -16
  153. data/spec/unit/provider/augeas/augeas_spec.rb +19 -0
  154. data/spec/unit/provider/exec/shell_spec.rb +17 -14
  155. data/spec/unit/provider/exec/windows_spec.rb +1 -7
  156. data/spec/unit/provider/exec_spec.rb +35 -0
  157. data/spec/unit/provider/nameservice/directoryservice_spec.rb +10 -0
  158. data/spec/unit/provider/package/dpkg_spec.rb +2 -1
  159. data/spec/unit/provider/package/gem_spec.rb +15 -0
  160. data/spec/unit/provider/package/openbsd_spec.rb +5 -4
  161. data/spec/unit/provider/package/pacman_spec.rb +3 -2
  162. data/spec/unit/provider/package/pkg_spec.rb +56 -33
  163. data/spec/unit/provider/selmodule_spec.rb +11 -4
  164. data/spec/unit/provider/service/redhat_spec.rb +1 -3
  165. data/spec/unit/provider/service/smf_spec.rb +1 -3
  166. data/spec/unit/provider/service/upstart_spec.rb +38 -0
  167. data/spec/unit/provider/ssh_authorized_key/parsed_spec.rb +28 -0
  168. data/spec/unit/rails/host_spec.rb +6 -12
  169. data/spec/unit/rails/param_value_spec.rb +3 -8
  170. data/spec/unit/rails/resource_spec.rb +2 -8
  171. data/spec/unit/reports/http_spec.rb +47 -31
  172. data/spec/unit/reports/tagmail_spec.rb +77 -0
  173. data/spec/unit/resource/type_spec.rb +2 -2
  174. data/spec/unit/resource_spec.rb +18 -20
  175. data/spec/unit/semver_spec.rb +31 -13
  176. data/spec/unit/type/exec_spec.rb +8 -15
  177. data/spec/unit/type/group_spec.rb +0 -9
  178. data/spec/unit/type/package_spec.rb +10 -0
  179. data/spec/unit/type/resources_spec.rb +4 -5
  180. data/spec/unit/type/ssh_authorized_key_spec.rb +4 -15
  181. data/spec/unit/type/sshkey_spec.rb +9 -11
  182. data/spec/unit/type/user_spec.rb +123 -127
  183. data/spec/unit/type_spec.rb +20 -0
  184. data/spec/unit/util/command_line_spec.rb +2 -2
  185. data/spec/unit/util/instrumentation/data_spec.rb +1 -1
  186. data/spec/unit/util/instrumentation/indirection_probe_spec.rb +1 -1
  187. data/spec/unit/util/instrumentation/instrumentable_spec.rb +1 -1
  188. data/spec/unit/util/instrumentation/listener_spec.rb +1 -1
  189. data/spec/unit/util/instrumentation/listeners/log_spec.rb +1 -1
  190. data/spec/unit/util/instrumentation/listeners/performance_spec.rb +1 -1
  191. data/spec/unit/util/instrumentation_spec.rb +1 -1
  192. data/spec/unit/util/log/destinations_spec.rb +4 -8
  193. data/spec/unit/util/log_spec.rb +47 -0
  194. data/spec/unit/util/reference_spec.rb +1 -1
  195. data/spec/unit/util/settings/file_setting_spec.rb +9 -0
  196. data/spec/unit/util/settings_spec.rb +0 -53
  197. data/spec/unit/util/terminal_spec.rb +42 -0
  198. data/spec/unit/util/zaml_spec.rb +7 -0
  199. data/spec/unit/util_spec.rb +63 -20
  200. data/tasks/rake/manpages.rake +1 -1
  201. data/test/data/snippets/arithmetic_expression.pp +1 -1
  202. data/test/other/puppet.rb +0 -1
  203. data/test/util/log.rb +6 -6
  204. metadata +41 -16
  205. data/lib/puppet/external/event-loop.rb +0 -1
  206. data/lib/puppet/external/event-loop/better-definers.rb +0 -367
  207. data/lib/puppet/external/event-loop/event-loop.rb +0 -355
  208. data/lib/puppet/external/event-loop/signal-system.rb +0 -218
  209. data/lib/puppet/face/module/clean.rb +0 -30
  210. data/lib/puppet/module_tool/applications/cleaner.rb +0 -16
  211. data/lib/puppet/module_tool/skeleton/templates/generator/metadata.json +0 -12
  212. data/lib/puppet/module_tool/utils.rb +0 -5
  213. data/lib/puppet/module_tool/utils/interrogation.rb +0 -25
  214. data/spec/integration/module_tool_spec.rb +0 -475
  215. data/spec/unit/module_tool/uninstaller_spec.rb +0 -124
@@ -270,36 +270,4 @@ describe Puppet::Agent do
270
270
  end
271
271
  end
272
272
  end
273
-
274
- describe "when starting" do
275
- before do
276
- @agent.stubs(:observe_signal)
277
- end
278
-
279
- it "should create a timer with the runinterval, a tolerance of 1, and :start? set to true" do
280
- Puppet.settings.expects(:value).with(:runinterval).returns 5
281
- timer = stub 'timer', :sound_alarm => nil
282
- EventLoop::Timer.expects(:new).with(:interval => 5, :start? => true, :tolerance => 1).returns timer
283
-
284
- @agent.stubs(:run)
285
- @agent.start
286
- end
287
-
288
- it "should run once immediately" do
289
- timer = mock 'timer'
290
- EventLoop::Timer.expects(:new).returns timer
291
-
292
- timer.expects(:sound_alarm)
293
-
294
- @agent.start
295
- end
296
-
297
- it "should run within the block passed to the timer" do
298
- timer = stub 'timer', :sound_alarm => nil
299
- EventLoop::Timer.expects(:new).returns(timer).yields
300
- @agent.expects(:run)
301
-
302
- @agent.start
303
- end
304
- end
305
273
  end
@@ -239,14 +239,14 @@ describe Puppet::Application::Kick, :if => Puppet.features.posix? do
239
239
  @kick.hosts = ['host1', 'host2', 'host3']
240
240
  Process.stubs(:wait).returns(1).then.returns(2).then.returns(3).then.raises(Errno::ECHILD)
241
241
 
242
- @kick.expects(:fork).times(3).returns(1).then.returns(2).then.returns(3)
242
+ @kick.expects(:safe_posix_fork).times(3).returns(1).then.returns(2).then.returns(3)
243
243
 
244
244
  expect { @kick.main }.to raise_error SystemExit
245
245
  end
246
246
 
247
247
  it "should delegate to run_for_host per host" do
248
248
  @kick.hosts = ['host1', 'host2']
249
- @kick.stubs(:fork).returns(1).yields
249
+ @kick.stubs(:safe_posix_fork).returns(1).yields
250
250
  Process.stubs(:wait).returns(1).then.raises(Errno::ECHILD)
251
251
 
252
252
  @kick.expects(:run_for_host).times(2)
@@ -49,7 +49,7 @@ describe Puppet::Daemon do
49
49
  before do
50
50
  @daemon.stubs(:create_pidfile)
51
51
  @daemon.stubs(:set_signal_traps)
52
- EventLoop.current.stubs(:run)
52
+ @daemon.stubs(:run_event_loop)
53
53
  end
54
54
 
55
55
  it "should fail if it has neither agent nor server" do
@@ -58,19 +58,10 @@ describe Puppet::Daemon do
58
58
 
59
59
  it "should create its pidfile" do
60
60
  @daemon.stubs(:agent).returns stub('agent', :start => nil)
61
-
62
61
  @daemon.expects(:create_pidfile)
63
62
  @daemon.start
64
63
  end
65
64
 
66
- it "should start the agent if the agent is configured" do
67
- agent = mock 'agent'
68
- agent.expects(:start)
69
- @daemon.stubs(:agent).returns agent
70
-
71
- @daemon.start
72
- end
73
-
74
65
  it "should start its server if one is configured" do
75
66
  server = mock 'server'
76
67
  server.expects(:start)
@@ -78,13 +69,6 @@ describe Puppet::Daemon do
78
69
 
79
70
  @daemon.start
80
71
  end
81
-
82
- it "should let the current EventLoop run" do
83
- @daemon.stubs(:agent).returns stub('agent', :start => nil)
84
- EventLoop.current.expects(:run)
85
-
86
- @daemon.start
87
- end
88
72
  end
89
73
 
90
74
  describe "when stopping" do
@@ -0,0 +1,158 @@
1
+ require 'spec_helper'
2
+ require 'puppet/face'
3
+ require 'puppet/module_tool'
4
+
5
+ describe "puppet module install" do
6
+
7
+ subject { Puppet::Face[:module, :current] }
8
+
9
+ let(:options) do
10
+ {}
11
+ end
12
+
13
+ describe "option validation" do
14
+ before do
15
+ Puppet.settings[:modulepath] = fakemodpath
16
+ end
17
+
18
+ let(:expected_options) do
19
+ {
20
+ :target_dir => fakefirstpath,
21
+ :modulepath => fakemodpath,
22
+ :environment => 'production'
23
+ }
24
+ end
25
+
26
+ let(:sep) { File::PATH_SEPARATOR }
27
+ let(:fakefirstpath) { "/my/fake/modpath" }
28
+ let(:fakesecondpath) { "/other/fake/path" }
29
+ let(:fakemodpath) { "#{fakefirstpath}#{sep}#{fakesecondpath}" }
30
+ let(:fakedirpath) { "/my/fake/path" }
31
+
32
+ context "without any options" do
33
+ it "should require a name" do
34
+ pattern = /wrong number of arguments/
35
+ expect { subject.install }.to raise_error ArgumentError, pattern
36
+ end
37
+
38
+ it "should not require any options" do
39
+ Puppet::ModuleTool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
40
+ subject.install("puppetlabs-apache")
41
+ end
42
+ end
43
+
44
+ it "should accept the --force option" do
45
+ options[:force] = true
46
+ expected_options.merge!(options)
47
+ Puppet::ModuleTool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
48
+ subject.install("puppetlabs-apache", options)
49
+ end
50
+
51
+ it "should accept the --target-dir option" do
52
+ options[:target_dir] = "/foo/puppet/modules"
53
+ expected_options.merge!(options)
54
+ expected_options[:modulepath] = "#{options[:target_dir]}#{sep}#{fakemodpath}"
55
+
56
+ Puppet::ModuleTool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
57
+ subject.install("puppetlabs-apache", options)
58
+ end
59
+
60
+ it "should accept the --version option" do
61
+ options[:version] = "0.0.1"
62
+ expected_options.merge!(options)
63
+ Puppet::ModuleTool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
64
+ subject.install("puppetlabs-apache", options)
65
+ end
66
+
67
+ it "should accept the --ignore-dependencies option" do
68
+ options[:ignore_dependencies] = true
69
+ expected_options.merge!(options)
70
+ Puppet::ModuleTool::Applications::Installer.expects(:run).with("puppetlabs-apache", expected_options).once
71
+ subject.install("puppetlabs-apache", options)
72
+ end
73
+
74
+ describe "when modulepath option is passed" do
75
+ let(:expected_options) { { :modulepath => fakemodpath, :environment => 'production' } }
76
+ let(:options) { { :modulepath => fakemodpath } }
77
+
78
+ describe "when target-dir option is not passed" do
79
+ it "should set target-dir to be first path from modulepath" do
80
+ expected_options[:target_dir] = fakefirstpath
81
+
82
+ Puppet::ModuleTool::Applications::Installer.
83
+ expects(:run).
84
+ with("puppetlabs-apache", expected_options)
85
+
86
+ Puppet::Face[:module, :current].install("puppetlabs-apache", options)
87
+
88
+ Puppet.settings[:modulepath].should == fakemodpath
89
+ end
90
+ end
91
+
92
+ describe "when target-dir option is passed" do
93
+ it "should set target-dir to be first path of modulepath" do
94
+ options[:target_dir] = fakedirpath
95
+ expected_options[:target_dir] = fakedirpath
96
+ expected_options[:modulepath] = "#{fakedirpath}#{sep}#{fakemodpath}"
97
+
98
+ Puppet::ModuleTool::Applications::Installer.
99
+ expects(:run).
100
+ with("puppetlabs-apache", expected_options)
101
+
102
+ Puppet::Face[:module, :current].install("puppetlabs-apache", options)
103
+
104
+ Puppet.settings[:modulepath].should == "#{fakedirpath}#{sep}#{fakemodpath}"
105
+ end
106
+ end
107
+ end
108
+
109
+ describe "when modulepath option is not passed" do
110
+ before do
111
+ Puppet.settings[:modulepath] = fakemodpath
112
+ end
113
+
114
+ describe "when target-dir option is not passed" do
115
+ it "should set target-dir to be first path of default mod path" do
116
+ expected_options[:target_dir] = fakefirstpath
117
+ expected_options[:modulepath] = fakemodpath
118
+
119
+ Puppet::ModuleTool::Applications::Installer.
120
+ expects(:run).
121
+ with("puppetlabs-apache", expected_options)
122
+
123
+ Puppet::Face[:module, :current].install("puppetlabs-apache", options)
124
+ end
125
+ end
126
+
127
+ describe "when target-dir option is passed" do
128
+ it "should prepend target-dir to modulepath" do
129
+ options[:target_dir] = fakedirpath
130
+ expected_options[:target_dir] = fakedirpath
131
+ expected_options[:modulepath] = "#{options[:target_dir]}#{sep}#{fakemodpath}"
132
+
133
+ Puppet::ModuleTool::Applications::Installer.
134
+ expects(:run).
135
+ with("puppetlabs-apache", expected_options)
136
+
137
+ Puppet::Face[:module, :current].install("puppetlabs-apache", options)
138
+ Puppet.settings[:modulepath].should == expected_options[:modulepath]
139
+ end
140
+ end
141
+ end
142
+ end
143
+
144
+ describe "inline documentation" do
145
+ subject { Puppet::Face[:module, :current].get_action :install }
146
+
147
+ its(:summary) { should =~ /install.*module/im }
148
+ its(:description) { should =~ /install.*module/im }
149
+ its(:returns) { should =~ /pathname/i }
150
+ its(:examples) { should_not be_empty }
151
+
152
+ %w{ license copyright summary description returns examples }.each do |doc|
153
+ context "of the" do
154
+ its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
155
+ end
156
+ end
157
+ end
158
+ end
@@ -0,0 +1,182 @@
1
+ # encoding: UTF-8
2
+
3
+ require 'spec_helper'
4
+ require 'puppet/face'
5
+ require 'puppet/module_tool'
6
+ require 'puppet_spec/modules'
7
+
8
+ describe "puppet module list", :fails_on_windows => true do
9
+ include PuppetSpec::Files
10
+
11
+ before do
12
+ dir = tmpdir("deep_path")
13
+
14
+ @modpath1 = File.join(dir, "modpath1")
15
+ @modpath2 = File.join(dir, "modpath2")
16
+ @modulepath = "#{@modpath1}#{File::PATH_SEPARATOR}#{@modpath2}"
17
+ Puppet.settings[:modulepath] = @modulepath
18
+
19
+ FileUtils.mkdir_p(@modpath1)
20
+ FileUtils.mkdir_p(@modpath2)
21
+ end
22
+
23
+ it "should return an empty list per dir in path if there are no modules" do
24
+ Puppet.settings[:modulepath] = @modulepath
25
+ Puppet::Face[:module, :current].list.should == {
26
+ @modpath1 => [],
27
+ @modpath2 => []
28
+ }
29
+ end
30
+
31
+ it "should include modules separated by the environment's modulepath" do
32
+ foomod1 = PuppetSpec::Modules.create('foo', @modpath1)
33
+ barmod1 = PuppetSpec::Modules.create('bar', @modpath1)
34
+ foomod2 = PuppetSpec::Modules.create('foo', @modpath2)
35
+
36
+ env = Puppet::Node::Environment.new
37
+
38
+ Puppet::Face[:module, :current].list.should == {
39
+ @modpath1 => [
40
+ Puppet::Module.new('bar', :environment => env, :path => barmod1.path),
41
+ Puppet::Module.new('foo', :environment => env, :path => foomod1.path)
42
+ ],
43
+ @modpath2 => [Puppet::Module.new('foo', :environment => env, :path => foomod2.path)]
44
+ }
45
+ end
46
+
47
+ it "should use the specified environment" do
48
+ PuppetSpec::Modules.create('foo', @modpath1)
49
+ PuppetSpec::Modules.create('bar', @modpath1)
50
+
51
+ usedenv = Puppet::Node::Environment.new('useme')
52
+ usedenv.modulepath = [@modpath1, @modpath2]
53
+
54
+ Puppet::Face[:module, :current].list(:environment => 'useme').should == {
55
+ @modpath1 => [
56
+ Puppet::Module.new('bar', :environment => usedenv),
57
+ Puppet::Module.new('foo', :environment => usedenv)
58
+ ],
59
+ @modpath2 => []
60
+ }
61
+ end
62
+
63
+ it "should use the specified modulepath" do
64
+ PuppetSpec::Modules.create('foo', @modpath1)
65
+ PuppetSpec::Modules.create('bar', @modpath2)
66
+
67
+ Puppet::Face[:module, :current].list(:modulepath => "#{@modpath1}#{File::PATH_SEPARATOR}#{@modpath2}").should == {
68
+ @modpath1 => [ Puppet::Module.new('foo') ],
69
+ @modpath2 => [ Puppet::Module.new('bar') ]
70
+ }
71
+ end
72
+
73
+ it "should use the specified modulepath over the specified environment in place of the environment's default path" do
74
+ foomod1 = PuppetSpec::Modules.create('foo', @modpath1)
75
+ barmod2 = PuppetSpec::Modules.create('bar', @modpath2)
76
+ env = Puppet::Node::Environment.new('myenv')
77
+ env.modulepath = ['/tmp/notused']
78
+
79
+ list = Puppet::Face[:module, :current].list(:environment => 'myenv', :modulepath => "#{@modpath1}#{File::PATH_SEPARATOR}#{@modpath2}")
80
+
81
+ # Changing Puppet[:modulepath] causes Puppet::Node::Environment.new('myenv')
82
+ # to have a different object_id than the env above
83
+ env = Puppet::Node::Environment.new('myenv')
84
+ list.should == {
85
+ @modpath1 => [ Puppet::Module.new('foo', :environment => env, :path => foomod1.path) ],
86
+ @modpath2 => [ Puppet::Module.new('bar', :environment => env, :path => barmod2.path) ]
87
+ }
88
+ end
89
+
90
+ describe "inline documentation" do
91
+ subject { Puppet::Face[:module, :current].get_action :list }
92
+
93
+ its(:summary) { should =~ /list.*module/im }
94
+ its(:description) { should =~ /list.*module/im }
95
+ its(:returns) { should =~ /hash of paths to module objects/i }
96
+ its(:examples) { should_not be_empty }
97
+ end
98
+
99
+ describe "when rendering" do
100
+ it "should explicitly state when a modulepath is empty" do
101
+ empty_modpath = tmpdir('empty')
102
+ Puppet::Face[:module, :current].list_when_rendering_console(
103
+ { empty_modpath => [] },
104
+ {:modulepath => empty_modpath}
105
+ ).should == <<-HEREDOC.gsub(' ', '')
106
+ #{empty_modpath} (no modules installed)
107
+ HEREDOC
108
+ end
109
+
110
+ it "should print both modules with and without metadata" do
111
+ modpath = tmpdir('modpath')
112
+ Puppet.settings[:modulepath] = modpath
113
+ PuppetSpec::Modules.create('nometadata', modpath)
114
+ PuppetSpec::Modules.create('metadata', modpath, :metadata => {:author => 'metaman'})
115
+
116
+ dependency_tree = Puppet::Face[:module, :current].list
117
+
118
+ output = Puppet::Face[:module, :current].list_when_rendering_console(
119
+ dependency_tree,
120
+ {}
121
+ )
122
+
123
+ output.should == <<-HEREDOC.gsub(' ', '')
124
+ #{modpath}
125
+ ├── metaman-metadata (\e[0;36mv9.9.9\e[0m)
126
+ └── nometadata (\e[0;36m???\e[0m)
127
+ HEREDOC
128
+ end
129
+
130
+ it "should print the modulepaths in the order they are in the modulepath setting" do
131
+ path1 = tmpdir('b')
132
+ path2 = tmpdir('c')
133
+ path3 = tmpdir('a')
134
+
135
+ sep = File::PATH_SEPARATOR
136
+ Puppet.settings[:modulepath] = "#{path1}#{sep}#{path2}#{sep}#{path3}"
137
+
138
+ Puppet::Face[:module, :current].list_when_rendering_console(
139
+ {
140
+ path2 => [],
141
+ path3 => [],
142
+ path1 => [],
143
+ },
144
+ {}
145
+ ).should == <<-HEREDOC.gsub(' ', '')
146
+ #{path1} (no modules installed)
147
+ #{path2} (no modules installed)
148
+ #{path3} (no modules installed)
149
+ HEREDOC
150
+ end
151
+
152
+ it "should print dependencies as a tree" do
153
+ PuppetSpec::Modules.create('dependable', @modpath1, :metadata => { :version => '0.0.5'})
154
+ PuppetSpec::Modules.create(
155
+ 'other_mod',
156
+ @modpath1,
157
+ :metadata => {
158
+ :version => '1.0.0',
159
+ :dependencies => [{
160
+ "version_requirement" => ">= 0.0.5",
161
+ "name" => "puppetlabs/dependable"
162
+ }]
163
+ }
164
+ )
165
+
166
+ dependency_tree = Puppet::Face[:module, :current].list
167
+
168
+ output = Puppet::Face[:module, :current].list_when_rendering_console(
169
+ dependency_tree,
170
+ {:tree => true}
171
+ )
172
+
173
+ output.should == <<-HEREDOC.gsub(' ', '')
174
+ #{@modpath1}
175
+ └─┬ puppetlabs-other_mod (\e[0;36mv1.0.0\e[0m)
176
+ └── puppetlabs-dependable (\e[0;36mv0.0.5\e[0m)
177
+ #{@modpath2} (no modules installed)
178
+ HEREDOC
179
+ end
180
+ end
181
+
182
+ end
@@ -0,0 +1,163 @@
1
+ require 'spec_helper'
2
+ require 'puppet/face'
3
+ require 'puppet/application/module'
4
+ require 'puppet/module_tool'
5
+
6
+ describe "puppet module search", :fails_on_windows => true do
7
+ subject { Puppet::Face[:module, :current] }
8
+
9
+ let(:options) do
10
+ {}
11
+ end
12
+
13
+ describe Puppet::Application::Module do
14
+ subject do
15
+ app = Puppet::Application::Module.new
16
+ app.stubs(:action).returns(Puppet::Face.find_action(:module, :search))
17
+ app
18
+ end
19
+
20
+ before { subject.render_as = :console }
21
+ before { Puppet::Util::Terminal.stubs(:width).returns(100) }
22
+
23
+ it 'should output nothing when receiving an empty dataset' do
24
+ subject.render([], ['apache', {}]).should == "No results found for 'apache'."
25
+ end
26
+
27
+ it 'should output a header when receiving a non-empty dataset' do
28
+ results = [
29
+ {'full_name' => '', 'author' => '', 'desc' => '', 'tag_list' => [] },
30
+ ]
31
+
32
+ subject.render(results, ['apache', {}]).should =~ /NAME/
33
+ subject.render(results, ['apache', {}]).should =~ /DESCRIPTION/
34
+ subject.render(results, ['apache', {}]).should =~ /AUTHOR/
35
+ subject.render(results, ['apache', {}]).should =~ /KEYWORDS/
36
+ end
37
+
38
+ it 'should output the relevant fields when receiving a non-empty dataset' do
39
+ results = [
40
+ {'full_name' => 'Name', 'author' => 'Author', 'desc' => 'Summary', 'tag_list' => ['tag1', 'tag2'] },
41
+ ]
42
+
43
+ subject.render(results, ['apache', {}]).should =~ /Name/
44
+ subject.render(results, ['apache', {}]).should =~ /Author/
45
+ subject.render(results, ['apache', {}]).should =~ /Summary/
46
+ subject.render(results, ['apache', {}]).should =~ /tag1/
47
+ subject.render(results, ['apache', {}]).should =~ /tag2/
48
+ end
49
+
50
+ it 'should elide really long descriptions' do
51
+ results = [
52
+ {
53
+ 'full_name' => 'Name',
54
+ 'author' => 'Author',
55
+ 'desc' => 'This description is really too long to fit in a single data table, guys -- we should probably set about truncating it',
56
+ 'tag_list' => ['tag1', 'tag2'],
57
+ },
58
+ ]
59
+
60
+ subject.render(results, ['apache', {}]).should =~ /\.{3} @Author/
61
+ end
62
+
63
+ it 'should never truncate the module name' do
64
+ results = [
65
+ {
66
+ 'full_name' => 'This-module-has-a-really-really-long-name',
67
+ 'author' => 'Author',
68
+ 'desc' => 'Description',
69
+ 'tag_list' => ['tag1', 'tag2'],
70
+ },
71
+ ]
72
+
73
+ subject.render(results, ['apache', {}]).should =~ /This-module-has-a-really-really-long-name/
74
+ end
75
+
76
+ it 'should never truncate the author name' do
77
+ results = [
78
+ {
79
+ 'full_name' => 'Name',
80
+ 'author' => 'This-author-has-a-really-really-long-name',
81
+ 'desc' => 'Description',
82
+ 'tag_list' => ['tag1', 'tag2'],
83
+ },
84
+ ]
85
+
86
+ subject.render(results, ['apache', {}]).should =~ /@This-author-has-a-really-really-long-name/
87
+ end
88
+
89
+ it 'should never remove tags that match the search term' do
90
+ results = [
91
+ {
92
+ 'full_name' => 'Name',
93
+ 'author' => 'Author',
94
+ 'desc' => 'Description',
95
+ 'tag_list' => ['Supercalifragilisticexpialidocious'] + (1..100).map { |i| "tag#{i}" },
96
+ },
97
+ ]
98
+
99
+ subject.render(results, ['Supercalifragilisticexpialidocious', {}]).should =~ /Supercalifragilisticexpialidocious/
100
+ subject.render(results, ['Supercalifragilisticexpialidocious', {}]).should_not =~ /tag/
101
+ end
102
+
103
+ {
104
+ 100 => "NAME DESCRIPTION AUTHOR KEYWORDS#{' '*15}\n"\
105
+ "Name This description is really too long to fit ... @JohnnyApples tag1 tag2 taggitty3#{' '*4}\n",
106
+
107
+ 70 => "NAME DESCRIPTION AUTHOR KEYWORDS#{' '*5}\n"\
108
+ "Name This description is rea... @JohnnyApples tag1 tag2#{' '*4}\n",
109
+
110
+ 80 => "NAME DESCRIPTION AUTHOR KEYWORDS#{' '*8}\n"\
111
+ "Name This description is really too... @JohnnyApples tag1 tag2#{' '*7}\n",
112
+
113
+ 200 => "NAME DESCRIPTION AUTHOR KEYWORDS#{' '*48}\n"\
114
+ "Name This description is really too long to fit in a single data table, guys -- we should probably set about trunca... @JohnnyApples tag1 tag2 taggitty3#{' '*37}\n"
115
+ }.each do |width, expectation|
116
+ it "should resize the table to fit the screen, when #{width} columns" do
117
+ results = [
118
+ {
119
+ 'full_name' => 'Name',
120
+ 'author' => 'JohnnyApples',
121
+ 'desc' => 'This description is really too long to fit in a single data table, guys -- we should probably set about truncating it',
122
+ 'tag_list' => ['tag1', 'tag2', 'taggitty3'],
123
+ },
124
+ ]
125
+
126
+ Puppet::Util::Terminal.expects(:width).returns(width)
127
+ result = subject.render(results, ['apache', {}])
128
+ result.lines.sort_by(&:length).last.chomp.length.should <= width
129
+ result.should == expectation
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "option validation" do
135
+ context "without any options" do
136
+ it "should require a search term" do
137
+ pattern = /wrong number of arguments/
138
+ expect { subject.search }.to raise_error ArgumentError, pattern
139
+ end
140
+ end
141
+
142
+ it "should accept the --module-repository option" do
143
+ options[:module_repository] = "http://forge.example.com"
144
+ Puppet::ModuleTool::Applications::Searcher.expects(:run).with("puppetlabs-apache", options).once
145
+ subject.search("puppetlabs-apache", options)
146
+ end
147
+ end
148
+
149
+ describe "inline documentation" do
150
+ subject { Puppet::Face[:module, :current].get_action :search }
151
+
152
+ its(:summary) { should =~ /search.*module/im }
153
+ its(:description) { should =~ /search.*module/im }
154
+ its(:returns) { should =~ /array/i }
155
+ its(:examples) { should_not be_empty }
156
+
157
+ %w{ license copyright summary description returns examples }.each do |doc|
158
+ context "of the" do
159
+ its(doc.to_sym) { should_not =~ /(FIXME|REVISIT|TODO)/ }
160
+ end
161
+ end
162
+ end
163
+ end