ml-puppetdb-terminus 3.2.1

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 (38) hide show
  1. checksums.yaml +7 -0
  2. data/LICENSE.txt +202 -0
  3. data/NOTICE.txt +17 -0
  4. data/README.md +22 -0
  5. data/puppet/lib/puppet/application/storeconfigs.rb +4 -0
  6. data/puppet/lib/puppet/face/node/deactivate.rb +37 -0
  7. data/puppet/lib/puppet/face/node/status.rb +80 -0
  8. data/puppet/lib/puppet/face/storeconfigs.rb +193 -0
  9. data/puppet/lib/puppet/indirector/catalog/puppetdb.rb +400 -0
  10. data/puppet/lib/puppet/indirector/facts/puppetdb.rb +152 -0
  11. data/puppet/lib/puppet/indirector/facts/puppetdb_apply.rb +25 -0
  12. data/puppet/lib/puppet/indirector/node/puppetdb.rb +19 -0
  13. data/puppet/lib/puppet/indirector/resource/puppetdb.rb +108 -0
  14. data/puppet/lib/puppet/reports/puppetdb.rb +188 -0
  15. data/puppet/lib/puppet/util/puppetdb.rb +108 -0
  16. data/puppet/lib/puppet/util/puppetdb/char_encoding.rb +316 -0
  17. data/puppet/lib/puppet/util/puppetdb/command.rb +116 -0
  18. data/puppet/lib/puppet/util/puppetdb/command_names.rb +8 -0
  19. data/puppet/lib/puppet/util/puppetdb/config.rb +148 -0
  20. data/puppet/lib/puppet/util/puppetdb/http.rb +121 -0
  21. data/puppet/spec/README.markdown +8 -0
  22. data/puppet/spec/spec.opts +6 -0
  23. data/puppet/spec/spec_helper.rb +38 -0
  24. data/puppet/spec/unit/face/node/deactivate_spec.rb +28 -0
  25. data/puppet/spec/unit/face/node/status_spec.rb +43 -0
  26. data/puppet/spec/unit/face/storeconfigs_spec.rb +199 -0
  27. data/puppet/spec/unit/indirector/catalog/puppetdb_spec.rb +703 -0
  28. data/puppet/spec/unit/indirector/facts/puppetdb_apply_spec.rb +27 -0
  29. data/puppet/spec/unit/indirector/facts/puppetdb_spec.rb +347 -0
  30. data/puppet/spec/unit/indirector/node/puppetdb_spec.rb +61 -0
  31. data/puppet/spec/unit/indirector/resource/puppetdb_spec.rb +199 -0
  32. data/puppet/spec/unit/reports/puppetdb_spec.rb +249 -0
  33. data/puppet/spec/unit/util/puppetdb/char_encoding_spec.rb +212 -0
  34. data/puppet/spec/unit/util/puppetdb/command_spec.rb +98 -0
  35. data/puppet/spec/unit/util/puppetdb/config_spec.rb +227 -0
  36. data/puppet/spec/unit/util/puppetdb/http_spec.rb +138 -0
  37. data/puppet/spec/unit/util/puppetdb_spec.rb +33 -0
  38. metadata +115 -0
@@ -0,0 +1,703 @@
1
+ #!/usr/bin/env rspec
2
+
3
+ require 'spec_helper'
4
+
5
+ require 'puppet/indirector/catalog/puppetdb'
6
+ require 'puppet/util/puppetdb'
7
+ require 'puppet/util/puppetdb/command_names'
8
+ require 'json'
9
+
10
+ describe Puppet::Resource::Catalog::Puppetdb do
11
+ before :each do
12
+ Puppet::Util::Puppetdb.stubs(:server).returns 'localhost'
13
+ Puppet::Util::Puppetdb.stubs(:port).returns 0
14
+ create_environmentdir("my_environment")
15
+ end
16
+
17
+ describe "#save" do
18
+ let(:response) { Net::HTTPOK.new('1.1', 200, 'OK') }
19
+ let(:http) { mock 'http' }
20
+ let(:catalog) do
21
+ cat = Puppet::Resource::Catalog.new('foo')
22
+ cat.add_resource(Puppet::Resource.new(:file, 'my_file'))
23
+ cat
24
+ end
25
+ let(:options) {{
26
+ :code_id => 'my_git_sha1',
27
+ :transaction_uuid => 'abcdefg',
28
+ :environment => 'my_environment',
29
+ :producer_timestamp => "a test",
30
+ }}
31
+
32
+ before :each do
33
+ response.stubs(:body).returns '{"uuid": "a UUID"}'
34
+ Puppet::Network::HttpPool.expects(:http_instance).returns http
35
+ end
36
+
37
+ def save
38
+ subject.save(Puppet::Resource::Catalog.indirection.request(:save, catalog.name, catalog, options))
39
+ end
40
+
41
+ it "should POST the catalog command as a JSON string" do
42
+ command_payload = subject.munge_catalog(catalog, options)
43
+ payload = {
44
+ :command => Puppet::Util::Puppetdb::CommandNames::CommandReplaceCatalog,
45
+ :version => 7,
46
+ :payload => command_payload,
47
+ }.to_json
48
+
49
+ http.expects(:post).with do |uri, body, headers|
50
+ expect(body).to eq(payload)
51
+ end.returns response
52
+
53
+ save
54
+ end
55
+
56
+ it "should log a deprecation warning if one is returned from PuppetDB" do
57
+ response['x-deprecation'] = 'A horrible deprecation warning!'
58
+
59
+ Puppet.expects(:deprecation_warning).with do |msg|
60
+ msg =~ /A horrible deprecation warning!/
61
+ end
62
+
63
+ http.stubs(:post).returns response
64
+
65
+ save
66
+ end
67
+ end
68
+
69
+ describe "catalog transformation methods" do
70
+ let(:catalog) { Puppet::Parser::Compiler.compile(Puppet::Node.new('node')) }
71
+ let(:resource) { Puppet::Resource.new(:notify, 'anyone') }
72
+
73
+ # This is a little abuse of the laziness of let. Set Puppet[:code], then
74
+ # create the catalog based on that manifest simply by asking for it.
75
+ def catalog_data_hash
76
+ Puppet[:code] = resource.to_manifest
77
+ catalog.to_data_hash
78
+ end
79
+
80
+ describe "#add_transaction_uuid" do
81
+ it "should add the given transaction uuid" do
82
+ result = subject.add_transaction_uuid(catalog_data_hash, 'abc123')
83
+ result['transaction_uuid'].should == 'abc123'
84
+ end
85
+
86
+ it "should add nil transaction uuid if none was given" do
87
+ result = subject.add_transaction_uuid(catalog_data_hash, nil)
88
+ result.has_key?('transaction_uuid').should be_true
89
+ result['transaction_uuid'].should be_nil
90
+ end
91
+ end
92
+
93
+ describe "#add_parameters_if_missing" do
94
+ it "should create an empty parameters hash if none exists" do
95
+ result = subject.add_parameters_if_missing(catalog_data_hash)
96
+
97
+ result['resources'].each do |res|
98
+ res['parameters'].should be_a(Hash)
99
+ end
100
+ end
101
+
102
+ it "should leave an existing parameters hash alone" do
103
+ msg = "with up so floating many bells down"
104
+ resource[:message] = msg
105
+
106
+ result = subject.add_parameters_if_missing(catalog_data_hash)
107
+ resource = result['resources'].find do |res|
108
+ res['type'] == 'Notify' and res['title'] == 'anyone'
109
+ end
110
+
111
+ resource.should_not be_nil
112
+ resource['parameters'].should == {:message => msg}
113
+ end
114
+ end
115
+
116
+ describe "#stringify_titles" do
117
+ if Puppet::Util::Puppetdb.puppet3compat?
118
+ it "should make all resource titles strings if they aren't" do
119
+ Puppet[:code] = <<-MANIFEST
120
+ $foo = true
121
+ notify { $foo: }
122
+ MANIFEST
123
+
124
+ hash = catalog.to_data_hash
125
+ result = subject.stringify_titles(hash)
126
+
127
+ result['resources'].should be_any { |res|
128
+ res['type'] == 'Notify' and res['title'] == 'true'
129
+ }
130
+ end
131
+ end
132
+ end
133
+
134
+ describe "#add_namevar_aliases" do
135
+ it "should add namevar to aliases if it's not already present" do
136
+ name = 'with a different name'
137
+ resource[:name] = name
138
+
139
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
140
+ result = subject.add_namevar_aliases(hash, catalog)
141
+
142
+ resource = result['resources'].find do |res|
143
+ res['type'] == 'Notify' and res['title'] == 'anyone'
144
+ end
145
+
146
+ resource.should_not be_nil
147
+ resource['parameters'][:alias].should include(name)
148
+ end
149
+
150
+ context "with resource types that provide #title_patterns" do
151
+ context "if #title_patterns munges the title to set the namevar" do
152
+ it "should add namevar to aliases if it's not already present" do
153
+ # So, what we are testing here is the case where the resource type
154
+ # defines one or more title_patterns, which, when used to set
155
+ # the value of the namevar, may munge the value via regex
156
+ # awesomeness. 'File' is an example of such a resource, as
157
+ # it will strip trailing slashes from the title to set the
158
+ # :path parameter, if :path is not specified.
159
+ #
160
+ # In a case like this it is important that the munged value of
161
+ # the namevar be set as an alias, so that catalog dependencies
162
+ # can be resolved properly.
163
+
164
+ # To test this, first we create a File resource whose title contains
165
+ # a trailing slash.
166
+ file_resource = Puppet::Resource.new(:file, '/tmp/foo/')
167
+
168
+ # I find it fairly well revolting that we can hack stuff into
169
+ # the compiler via this global :code variable. It doesn't seem
170
+ # like it should be hard to provide a more explicit and sensible
171
+ # way to accomplish this...
172
+ Puppet[:code] = file_resource.to_manifest
173
+
174
+ hash = subject.add_parameters_if_missing(catalog.to_data_hash)
175
+ result = subject.add_namevar_aliases(hash, catalog)
176
+
177
+ resource = result['resources'].find do |res|
178
+ res['type'] == 'File' and res['title'] == '/tmp/foo/'
179
+ end
180
+
181
+ # Now we need to check to make sure that there is an alias without
182
+ # the trailing slash. This test relies on the secret knowledge
183
+ # that the File resource has a title_pattern that munges the
184
+ # namevar (in this case, removes trailing slashes), but hopefully
185
+ # this test should cover other resource types that fall into
186
+ # this category as well.
187
+ resource.should_not be_nil
188
+ resource['parameters'][:alias].should_not be_nil
189
+ resource['parameters'][:alias].should include('/tmp/foo')
190
+ end
191
+ end
192
+ end
193
+
194
+ it "should not create an alias parameter if the list would be empty" do
195
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
196
+ result = subject.add_namevar_aliases(hash, catalog)
197
+
198
+ resource = result['resources'].find do |res|
199
+ res['type'] == 'Notify' and res['title'] == 'anyone'
200
+ end
201
+
202
+ resource.should_not be_nil
203
+ resource['parameters'][:alias].should be_nil
204
+ end
205
+
206
+ describe "for resources with composite namevars" do
207
+ let(:resource) do
208
+ r = Puppet::Resource.new(:notify, 'yo matey')
209
+ r.stubs(:key_attributes).returns [:name, :message]
210
+ r
211
+ end
212
+
213
+ it "should not create aliases" do
214
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
215
+ result = subject.add_namevar_aliases(hash, catalog)
216
+
217
+ resource = result['resources'].find do |res|
218
+ res['type'] == 'Notify' and res['title'] == 'yo matey'
219
+ end
220
+
221
+ resource.should_not be_nil
222
+ resource['parameters'][:alias].should be_nil
223
+ end
224
+ end
225
+
226
+ describe "for non-isomorphic resources" do
227
+ let(:resource) do
228
+ Puppet::Resource.new(:exec, 'an_exec', :parameters => {:command => '/bin/true', :alias => 'something awesome'})
229
+ end
230
+
231
+ it "should not add a namevar alias" do
232
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
233
+ result = subject.add_namevar_aliases(hash, catalog)
234
+
235
+ resource = result['resources'].find do |res|
236
+ res['type'] == 'Exec' and res['title'] == 'an_exec'
237
+ end
238
+
239
+ resource.should_not be_nil
240
+ resource['parameters'][:alias].should == ['something awesome']
241
+ end
242
+ end
243
+ end
244
+
245
+ describe "#sort_unordered_metaparams" do
246
+ let(:resource) do
247
+ Puppet::Resource.new(:exec, 'an_exec', :parameters => {:command => '/bin/true',
248
+ :path => ['/foo/goo', '/foo/bar'],
249
+ :audit => 'path',
250
+ :tag => ['c', 'b', 'a']})
251
+ end
252
+
253
+ it "should leave ordered/singleton metaparams (and vanilla params) alone" do
254
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
255
+ result = subject.sort_unordered_metaparams(hash)
256
+
257
+ resource = result['resources'].find do |res|
258
+ res['type'] == 'Exec' and res['title'] == 'an_exec'
259
+ end
260
+
261
+ resource.should_not be_nil
262
+ resource['parameters'][:command].should == '/bin/true'
263
+ resource['parameters'][:path].should == ['/foo/goo', '/foo/bar']
264
+ resource['parameters'][:audit].should == 'path'
265
+ end
266
+
267
+ it "should sort unordered metaparams with array values" do
268
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
269
+ result = subject.sort_unordered_metaparams(hash)
270
+
271
+ resource = result['resources'].find do |res|
272
+ res['type'] == 'Exec' and res['title'] == 'an_exec'
273
+ end
274
+
275
+ resource.should_not be_nil
276
+ resource['parameters'][:audit].should == 'path'
277
+ resource['parameters'][:tag].should == ['a', 'b', 'c']
278
+ end
279
+ end
280
+
281
+ describe "#munge_edges" do
282
+ it "should replace existing source/target refs with type/title hashes" do
283
+ result = subject.munge_edges(catalog_data_hash)
284
+
285
+ # Ensure we don't get a vacuous success from an empty list
286
+ result['edges'].should_not be_empty
287
+
288
+ result['edges'].each do |edge|
289
+ edge['source'].should be_a(Hash)
290
+ edge['source'].keys.should =~ ['type', 'title']
291
+ edge['target'].should be_a(Hash)
292
+ edge['target'].keys.should =~ ['type', 'title']
293
+ end
294
+ end
295
+
296
+ it "should leave type/title hashes alone" do
297
+ hash = catalog_data_hash
298
+
299
+ edge = {'source' => {'type' => 'Notify', 'title' => 'bar'},
300
+ 'target' => {'type' => 'Notify', 'title' => 'baz'},
301
+ 'relationship' => 'notifies'}
302
+
303
+ hash['edges'] << edge.dup
304
+
305
+ result = subject.munge_edges(hash)
306
+ result['edges'].should include(edge)
307
+ end
308
+
309
+ it "should set the edge relationship to contains if it doesn't have one" do
310
+ result = subject.munge_edges(catalog_data_hash)
311
+ result['edges'].each do |edge|
312
+ edge['relationship'].should == 'contains'
313
+ end
314
+ end
315
+ end
316
+
317
+ describe "#synthesize_edges" do
318
+ it "should add edges based on relationship metaparameters" do
319
+ other_resource = Puppet::Resource.new(:notify, 'noone', :parameters => {:require => "Notify[anyone]"})
320
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
321
+
322
+ hash = catalog.to_data_hash
323
+ subject.add_parameters_if_missing(hash)
324
+ result = subject.synthesize_edges(hash, catalog)
325
+
326
+ edge = {'source' => {'type' => 'Notify', 'title' => 'anyone'},
327
+ 'target' => {'type' => 'Notify', 'title' => 'noone'},
328
+ 'relationship' => 'required-by'}
329
+
330
+ result['edges'].should include(edge)
331
+ end
332
+
333
+ it "should add edges from relationship arrows" do
334
+ other_resource = Puppet::Resource.new(:notify, 'noone')
335
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
336
+ Puppet[:code] << "Notify[anyone] -> Notify[noone]"
337
+
338
+ hash = catalog.to_data_hash
339
+ subject.add_parameters_if_missing(hash)
340
+ result = subject.synthesize_edges(hash, catalog)
341
+
342
+ edge = {'source' => {'type' => 'Notify', 'title' => 'anyone'},
343
+ 'target' => {'type' => 'Notify', 'title' => 'noone'},
344
+ 'relationship' => 'before'}
345
+
346
+ result['edges'].should include(edge)
347
+ end
348
+
349
+ it "should allow resources with newlines" do
350
+ Puppet[:code] = <<-MANIFEST
351
+ exec{"foo\nbar": }
352
+ exec{'/bin/true': subscribe => Exec["foo\nbar"]}
353
+ MANIFEST
354
+
355
+ expect { subject.munge_catalog(catalog) }.not_to raise_error
356
+ end
357
+
358
+ describe "exported resources" do
359
+ before :each do
360
+ Puppet[:storeconfigs] = true
361
+ Puppet[:storeconfigs_backend] = 'puppetdb'
362
+ Puppet::Resource.indirection.stubs(:search).returns []
363
+ end
364
+
365
+ let(:edge) do
366
+ {
367
+ 'source' => {'type' => 'Notify', 'title' => 'source'},
368
+ 'target' => {'type' => 'Notify', 'title' => 'target'},
369
+ 'relationship' => 'before'
370
+ }
371
+ end
372
+
373
+ it "should add edges which refer to collected exported resources" do
374
+ Puppet[:code] = <<-MANIFEST
375
+ notify { source:
376
+ before => Notify[target],
377
+ }
378
+
379
+ @@notify { target: }
380
+
381
+ Notify <<| |>>
382
+ MANIFEST
383
+
384
+ result = subject.munge_catalog(catalog)
385
+
386
+ result['edges'].should include(edge)
387
+ end
388
+
389
+ it "should add edges defined on collected exported resources" do
390
+ Puppet[:code] = <<-MANIFEST
391
+ @@notify { source:
392
+ before => Notify[target],
393
+ }
394
+
395
+ notify { target: }
396
+
397
+ Notify <<| |>>
398
+ MANIFEST
399
+
400
+ result = subject.munge_catalog(catalog)
401
+
402
+ result['edges'].should include(edge)
403
+ end
404
+
405
+ it "should fail if an edge refers to an uncollected exported resource" do
406
+ Puppet[:code] = <<-MANIFEST
407
+ notify { source:
408
+ before => Notify[target],
409
+ }
410
+
411
+ @@notify { target: }
412
+ MANIFEST
413
+
414
+ expect do
415
+ subject.munge_catalog(catalog)
416
+ end.to raise_error(Puppet::Error, "Invalid relationship: Notify[source] { before => Notify[target] }, because Notify[target] is exported but not collected")
417
+ end
418
+
419
+ it "should not add edges defined on an uncollected exported resource" do
420
+ Puppet[:code] = <<-MANIFEST
421
+ @@notify { source:
422
+ before => Notify[target],
423
+ }
424
+
425
+ notify { target: }
426
+ MANIFEST
427
+
428
+ result = subject.munge_catalog(catalog)
429
+
430
+ result['edges'].should_not include(edge)
431
+ end
432
+ end
433
+
434
+ describe "virtual resources" do
435
+ let(:edge) do
436
+ {
437
+ 'source' => {'type' => 'Notify', 'title' => 'source'},
438
+ 'target' => {'type' => 'Notify', 'title' => 'target'},
439
+ 'relationship' => 'before'
440
+ }
441
+ end
442
+
443
+ it "should add edges which refer to collected virtual resources" do
444
+ Puppet[:code] = <<-MANIFEST
445
+ notify { source:
446
+ before => Notify[target],
447
+ }
448
+
449
+ @notify { target: }
450
+
451
+ Notify <| |>
452
+ MANIFEST
453
+
454
+ result = subject.munge_catalog(catalog)
455
+
456
+ result['edges'].should include(edge)
457
+ end
458
+
459
+ if Puppet::Util::Puppetdb.puppet3compat?
460
+ it "should add edges which refer to collected virtual resources with hyphens in the classname" do
461
+ Puppet[:code] = <<-MANIFEST
462
+ define foo-bar- (){}
463
+ @foo-bar- { 'baz': }
464
+
465
+ notify { source:
466
+ before => Foo-bar-[baz],
467
+ }
468
+
469
+ Foo-bar- <| |>
470
+ MANIFEST
471
+
472
+ result = subject.munge_catalog(catalog)
473
+ other_edge = {
474
+ 'source' => {'type' => 'Notify', 'title' => 'source'},
475
+ 'target' => {'type' => 'Foo-bar-', 'title' => 'baz'},
476
+ 'relationship' => 'before'
477
+ }
478
+
479
+ result['edges'].should include(other_edge)
480
+ end
481
+ end
482
+
483
+ it "should add edges defined on collected virtual resources" do
484
+ Puppet[:code] = <<-MANIFEST
485
+ @notify { source:
486
+ before => Notify[target],
487
+ }
488
+
489
+ notify { target: }
490
+
491
+ Notify <| |>
492
+ MANIFEST
493
+
494
+ result = subject.munge_catalog(catalog)
495
+
496
+ result['edges'].should include(edge)
497
+ end
498
+
499
+ it "should add edges which refer to realized virtual resources" do
500
+ Puppet[:code] = <<-MANIFEST
501
+ notify { source:
502
+ before => Notify[target],
503
+ }
504
+
505
+ @notify { target: }
506
+
507
+ realize Notify[target]
508
+ MANIFEST
509
+
510
+ result = subject.munge_catalog(catalog)
511
+
512
+ result['edges'].should include(edge)
513
+ end
514
+
515
+ it "should add edges defined on realized virtual resources" do
516
+ Puppet[:code] = <<-MANIFEST
517
+ @notify { source:
518
+ before => Notify[target],
519
+ }
520
+
521
+ notify { target: }
522
+
523
+ realize Notify[source]
524
+ MANIFEST
525
+
526
+ result = subject.munge_catalog(catalog)
527
+
528
+ result['edges'].should include(edge)
529
+ end
530
+
531
+ it "should fail if an edge refers to an uncollected virtual resource" do
532
+ Puppet[:code] = <<-MANIFEST
533
+ notify { source:
534
+ before => Notify[target],
535
+ }
536
+
537
+ @notify { target: }
538
+ MANIFEST
539
+
540
+ expect do
541
+ subject.munge_catalog(catalog)
542
+ end.to raise_error(Puppet::Error, "Invalid relationship: Notify[source] { before => Notify[target] }, because Notify[target] doesn't seem to be in the catalog")
543
+ end
544
+
545
+ it "should not add edges defined on an uncollected virtual resource" do
546
+ Puppet[:code] = <<-MANIFEST
547
+ @notify { source:
548
+ before => Notify[target],
549
+ }
550
+
551
+ notify { target: }
552
+ MANIFEST
553
+
554
+ result = subject.munge_catalog(catalog)
555
+
556
+ result['edges'].should_not include(edge)
557
+ end
558
+ end
559
+
560
+ it "should add edges even if the other end is an alias" do
561
+ other_resource = Puppet::Resource.new(:notify, 'noone', :parameters => {:alias => 'another_thing'})
562
+ resource[:require] = 'Notify[another_thing]'
563
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
564
+
565
+ hash = catalog.to_data_hash
566
+ subject.add_parameters_if_missing(hash)
567
+ subject.add_namevar_aliases(hash, catalog)
568
+ result = subject.synthesize_edges(hash, catalog)
569
+
570
+ edge = {'source' => {'type' => 'Notify', 'title' => 'noone'},
571
+ 'target' => {'type' => 'Notify', 'title' => 'anyone'},
572
+ 'relationship' => 'required-by'}
573
+
574
+ result['edges'].should include(edge)
575
+ end
576
+
577
+ it "should produce a reasonable error message for a missing 'before' relationship" do
578
+ resource[:before] = 'Notify[non-existent]'
579
+
580
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
581
+ expect {
582
+ subject.synthesize_edges(hash, catalog)
583
+ }.to raise_error(Puppet::Error, "Invalid relationship: Notify[anyone] { before => Notify[non-existent] }, because Notify[non-existent] doesn't seem to be in the catalog")
584
+ end
585
+
586
+ it "should produce a reasonable error message for a missing 'required-by' relationship" do
587
+ resource[:require] = 'Notify[non-existent]'
588
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
589
+ expect {
590
+ subject.synthesize_edges(hash, catalog)
591
+ }.to raise_error(Puppet::Error, "Invalid relationship: Notify[anyone] { require => Notify[non-existent] }, because Notify[non-existent] doesn't seem to be in the catalog")
592
+ end
593
+
594
+ it "should produce a reasonable error message for a missing 'notifies' relationship" do
595
+ resource[:notify] = 'Notify[non-existent]'
596
+
597
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
598
+ expect {
599
+ subject.synthesize_edges(hash, catalog)
600
+ }.to raise_error(Puppet::Error, "Invalid relationship: Notify[anyone] { notify => Notify[non-existent] }, because Notify[non-existent] doesn't seem to be in the catalog")
601
+ end
602
+
603
+ it "should produce a reasonable error message for a missing 'subscription-of' relationship" do
604
+ resource[:subscribe] = 'Notify[non-existent]'
605
+
606
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
607
+ expect {
608
+ subject.synthesize_edges(hash, catalog)
609
+ }.to raise_error(Puppet::Error, "Invalid relationship: Notify[anyone] { subscribe => Notify[non-existent] }, because Notify[non-existent] doesn't seem to be in the catalog")
610
+ end
611
+
612
+ it "should produce a reasonable error message for an invalid resourceref" do
613
+ resource[:subscribe] = 'Foobar::baz[name]'
614
+
615
+ hash = subject.add_parameters_if_missing(catalog_data_hash)
616
+ expect {
617
+ subject.synthesize_edges(hash, catalog)
618
+ }.to raise_error(Puppet::Error, "Invalid relationship: Notify[anyone] { subscribe => Foobar::baz[name] }, because Foobar::baz[name] doesn't seem to be in the correct format. Resource references should be formatted as: Classname['title'] or Modulename::Classname['title'] (take careful note of the capitalization).")
619
+ end
620
+ end #synthesize_edges
621
+
622
+ describe "#munge_catalog" do
623
+ it "should make an edge if the other end is referred to by its namevar" do
624
+ other_resource = Puppet::Resource.new(:notify, 'noone', :parameters => {:name => 'completely_different'})
625
+ resource[:require] = 'Notify[completely_different]'
626
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
627
+
628
+ result = subject.munge_catalog(catalog)
629
+
630
+ edge = {'source' => {'type' => 'Notify', 'title' => 'noone'},
631
+ 'target' => {'type' => 'Notify', 'title' => 'anyone'},
632
+ 'relationship' => 'required-by'}
633
+
634
+ result['edges'].should include(edge)
635
+ end
636
+
637
+ context "when dealing with file resources and trailing slashes in their titles" do
638
+
639
+ def test_file_require(resource_title, require_title)
640
+ other_resource = Puppet::Resource.new(:file, resource_title)
641
+ resource[:require] = "File[#{require_title}]"
642
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
643
+ result = subject.munge_catalog(catalog)
644
+
645
+ edge = {'source' => {'type' => 'File', 'title' => resource_title},
646
+ 'target' => {'type' => 'Notify', 'title' => 'anyone'},
647
+ 'relationship' => 'required-by'}
648
+
649
+ result['edges'].should include(edge)
650
+ end
651
+
652
+ it "should make an edge if the other end is a file resource with a missing trailing slash" do
653
+ test_file_require('/tmp/foo/', '/tmp/foo')
654
+ end
655
+
656
+ it "should make an edge if the other end is a file resource with an extra trailing slash" do
657
+ test_file_require('/tmp/foo', '/tmp/foo/')
658
+ end
659
+
660
+ it "should make an edge if the other end is a file resource with two missing trailing slashes" do
661
+ test_file_require('/tmp/foo//', '/tmp/foo')
662
+ end
663
+
664
+ it "should make an edge if the other end is a file resource with two extra trailing slashes" do
665
+ test_file_require('/tmp/foo', '/tmp/foo//')
666
+ end
667
+ end
668
+
669
+ it "should make an edge if the other end is an exec referred to by an alias" do
670
+ other_resource = Puppet::Resource.new(:exec, 'noone', :parameters => {:alias => 'completely_different', :path => '/anything'})
671
+ resource[:require] = 'Exec[completely_different]'
672
+ Puppet[:code] = [resource, other_resource].map(&:to_manifest).join
673
+
674
+ result = subject.munge_catalog(catalog)
675
+
676
+ edge = {'source' => {'type' => 'Exec', 'title' => 'noone'},
677
+ 'target' => {'type' => 'Notify', 'title' => 'anyone'},
678
+ 'relationship' => 'required-by'}
679
+
680
+ result['edges'].should include(edge)
681
+ end
682
+
683
+ it "should not include virtual resources" do
684
+ Puppet[:code] = <<-MANIFEST
685
+ @notify { something: }
686
+ MANIFEST
687
+
688
+ result = subject.munge_catalog(catalog)
689
+
690
+ result['resources'].each do |res|
691
+ [res['type'], res['title']].should_not == ['Notify', 'something']
692
+ end
693
+ end
694
+
695
+ it "should have the correct set of keys" do
696
+ result = subject.munge_catalog(catalog)
697
+
698
+ result.keys.should =~ ['certname', 'version', 'edges', 'resources',
699
+ 'transaction_uuid', 'environment', 'producer_timestamp', "code_id"]
700
+ end
701
+ end
702
+ end
703
+ end