summaryrefslogtreecommitdiffstats
path: root/spec/unit/other/pgraph.rb
blob: 10ab934a64fd6665b020e79968bccf18eb6954f3 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
#!/usr/bin/env ruby
#
#  Created by Luke Kanies on 2007-9-12.
#  Copyright (c) 2006. All rights reserved.

require File.dirname(__FILE__) + '/../../spec_helper'

require 'puppet/pgraph'
require 'puppet/util/graph'

class Container
    include Puppet::Util::Graph
    include Enumerable
    attr_accessor :name
    def each
        @children.each do |c| yield c end
    end
    
    def initialize(name, ary)
        @name = name
        @children = ary
    end
    
    def push(*ary)
        ary.each { |c| @children.push(c)}
    end
    
    def to_s
        @name
    end
end

describe Puppet::PGraph do
    before do
        @graph = Puppet::PGraph.new
    end

    it "should correctly clear vertices and edges when asked" do
	    @graph.add_edge("a", "b")
	    @graph.add_vertex "c"
        @graph.clear
        @graph.vertices.should be_empty
        @graph.edges.should be_empty
    end
end

describe Puppet::PGraph, " when matching edges" do
    before do
        @graph = Puppet::PGraph.new
	    @event = Puppet::Event.new(:source => "a", :event => :yay)
	    @none = Puppet::Event.new(:source => "a", :event => :NONE)

	    @edges = {}
	    @edges["a/b"] = Puppet::Relationship.new("a", "b", {:event => :yay, :callback => :refresh})
	    @edges["a/c"] = Puppet::Relationship.new("a", "c", {:event => :yay, :callback => :refresh})
	    @graph.add_edge(@edges["a/b"])
    end

    it "should match edges whose source matches the source of the event" do
	    @graph.matching_edges([@event]).should == [@edges["a/b"]]
    end

    it "should match always match nothing when the event is :NONE" do
	    @graph.matching_edges([@none]).should be_empty
    end

    it "should match multiple edges" do
	    @graph.add_edge(@edges["a/c"])
        edges = @graph.matching_edges([@event])
        edges.should be_include(@edges["a/b"])
        edges.should be_include(@edges["a/c"])
    end
end

describe Puppet::PGraph, " when determining dependencies" do
    before do
        @graph = Puppet::PGraph.new
        
        @graph.add_edge("a", "b")
        @graph.add_edge("a", "c")
        @graph.add_edge("b", "d")
    end

    it "should find all dependents when they are on multiple levels" do
        @graph.dependents("a").sort.should == %w{b c d}.sort
    end

    it "should find single dependents" do
        @graph.dependents("b").sort.should == %w{d}.sort
    end

    it "should return an empty array when there are no dependents" do
        @graph.dependents("c").sort.should == [].sort
    end

    it "should find all dependencies when they are on multiple levels" do
        @graph.dependencies("d").sort.should == %w{a b}
    end

    it "should find single dependencies" do
        @graph.dependencies("c").sort.should == %w{a}
    end
    
    it "should return an empty array when there are no dependencies" do
        @graph.dependencies("a").sort.should == []
    end
end

describe Puppet::PGraph, " when splicing the relationship graph" do
    def container_graph
        @one = Container.new("one", %w{a b})
        @two = Container.new("two", ["c", "d"])
        @three = Container.new("three", ["i", "j"])
        @middle = Container.new("middle", ["e", "f", @two])
        @top = Container.new("top", ["g", "h", @middle, @one, @three])
        @empty = Container.new("empty", [])

        @contgraph = @top.to_graph

        # We have to add the container to the main graph, else it won't
        # be spliced in the dependency graph.
        @contgraph.add_vertex(@empty)
    end

    def dependency_graph
        @depgraph = Puppet::PGraph.new
        @contgraph.vertices.each do |v|
            @depgraph.add_vertex(v)
        end

        # We have to specify a relationship to our empty container, else it
        # never makes it into the dep graph in the first place.
        {@one => @two, "f" => "c", "h" => @middle, "c" => @empty}.each do |source, target|
            @depgraph.add_edge(source, target, :callback => :refresh)
        end
    end

    def splice
        @depgraph.splice!(@contgraph, Container)
    end

    before do
        container_graph
        dependency_graph
        splice
    end

    # This is the real heart of splicing -- replacing all containers in
    # our relationship and exploding their relationships so that each
    # relationship to a container gets copied to all of its children.
    it "should remove all Container objects from the dependency graph" do
        @depgraph.vertices.find_all { |v| v.is_a?(Container) }.should be_empty
    end

    it "should add container relationships to contained objects" do
        @contgraph.leaves(@middle).each do |leaf|
            @depgraph.should be_edge("h", leaf)
        end
    end

    it "should explode container-to-container relationships, making edges between all respective contained objects" do
        @one.each do |oobj|
            @two.each do |tobj|
                @depgraph.should be_edge(oobj, tobj)
            end
        end
    end

    it "should no longer contain anything but the non-container objects" do
        @depgraph.vertices.find_all { |v| ! v.is_a?(String) }.should be_empty
    end

    it "should copy labels" do
        @depgraph.edges.each do |edge|
            edge.label.should == {:callback => :refresh}
        end
    end

    it "should not add labels to edges that have none" do
        @depgraph.add_edge(@two, @three)
        splice
        @depgraph.edge_label("c", "i").should == {}
    end

    it "should copy labels over edges that have none" do
        @depgraph.add_edge("c", @three, {:callback => :refresh})
        splice
        # And make sure the label got copied.
        @depgraph.edge_label("c", "i").should == {:callback => :refresh}
    end

    it "should not replace a label with a nil label" do
        # Lastly, add some new label-less edges and make sure the label stays.
        @depgraph.add_edge(@middle, @three)
        @depgraph.add_edge("c", @three, {:callback => :refresh})
        splice
        @depgraph.edge_label("c", "i").should == {:callback => :refresh}
    end

    it "should copy labels to all created edges" do
        @depgraph.add_edge(@middle, @three)
        @depgraph.add_edge("c", @three, {:callback => :refresh})
        splice
        @three.each do |child|
            edge = Puppet::Relationship.new("c", child)
            @depgraph.should be_edge(edge.source, edge.target)
            @depgraph.edge_label(edge.source, edge.target).should == {:callback => :refresh}
        end
    end
end