chef-zero 15.1.0 → 15.1.11
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.
- checksums.yaml +4 -4
- data/Gemfile +1 -1
- data/chef-zero.gemspec +3 -4
- data/lib/chef_zero/data_store/data_already_exists_error.rb +1 -1
- data/lib/chef_zero/data_store/data_error.rb +1 -1
- data/lib/chef_zero/data_store/data_not_found_error.rb +1 -1
- data/lib/chef_zero/data_store/memory_store.rb +1 -1
- data/lib/chef_zero/data_store/memory_store_v2.rb +1 -1
- data/lib/chef_zero/data_store/raw_file_store.rb +1 -1
- data/lib/chef_zero/data_store/v2_to_v1_adapter.rb +1 -1
- data/lib/chef_zero/endpoints/environment_cookbook_versions_endpoint.rb +6 -3
- data/lib/chef_zero/server.rb +1 -1
- data/lib/chef_zero/socketless_server_map.rb +1 -1
- data/lib/chef_zero/version.rb +1 -1
- data/spec/endpoints/environment_cookbook_versions_endpoint_spec.rb +436 -0
- data/spec/support/oc_pedant.rb +1 -1
- metadata +20 -27
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA256:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: deb326897728f384377d741e312e4c513918d1d3e6270106a46dc267f830924d
|
|
4
|
+
data.tar.gz: b22286cf8ea5b081b3242f70610e38d63fa8bb4bf8fd2c18a0d62299c93e98ca
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: 6e51ac4dad86f587a860231dfdf204db27aed48d9c3fd75be4467580b3d8fac913bffa650b6f9ce88be16484dce81fa861dc5405ccde6e385f34c380971e8e3a
|
|
7
|
+
data.tar.gz: e1be28ae5469a3538c28172e904aa1391aba8a3f83665c8d44e41eb23e4af0821f5023d89f3f8ab61993095f3f147e0950f82f9d4bf85ac96c83d219eb3b9f0c
|
data/Gemfile
CHANGED
data/chef-zero.gemspec
CHANGED
|
@@ -15,11 +15,10 @@ Gem::Specification.new do |s|
|
|
|
15
15
|
|
|
16
16
|
s.add_dependency "mixlib-log", ">= 2.0", "< 4.0"
|
|
17
17
|
s.add_dependency "hashie", ">= 2.0", "< 6.0"
|
|
18
|
-
s.add_dependency "uuidtools", "
|
|
18
|
+
s.add_dependency "uuidtools", ">= 2.1", "< 4.0"
|
|
19
19
|
s.add_dependency "ffi-yajl", ">= 2.2", "< 4.0"
|
|
20
|
-
s.add_dependency "rack", "~> 3.
|
|
21
|
-
s.add_dependency "rackup", "~> 2.
|
|
22
|
-
s.add_dependency "unf_ext", "~> 0.0.8"
|
|
20
|
+
s.add_dependency "rack", "~> 3.2", ">= 3.2.6"
|
|
21
|
+
s.add_dependency "rackup", "~> 2.3", ">= 2.3.1"
|
|
23
22
|
s.add_dependency "webrick"
|
|
24
23
|
|
|
25
24
|
s.bindir = "bin"
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c)
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -84,7 +84,8 @@ module ChefZero
|
|
|
84
84
|
new_unsolved = unsolved[1..-1]
|
|
85
85
|
|
|
86
86
|
# Pick this cookbook, and add dependencies
|
|
87
|
-
cookbook_obj =
|
|
87
|
+
cookbook_obj = cookbook_obj_cache.dig(solve_for, desired_version) ||
|
|
88
|
+
FFI_Yajl::Parser.parse(get_data(request, request.rest_path[0..1] + ["cookbooks", solve_for, desired_version]))
|
|
88
89
|
cookbook_obj_cache[solve_for] ||= {}
|
|
89
90
|
cookbook_obj_cache[solve_for][desired_version] = cookbook_obj
|
|
90
91
|
cookbook_metadata = cookbook_obj["metadata"] || {}
|
|
@@ -110,7 +111,8 @@ module ChefZero
|
|
|
110
111
|
next if dep_not_found
|
|
111
112
|
|
|
112
113
|
# Depsolve children with this desired version! First solution wins.
|
|
113
|
-
result,
|
|
114
|
+
result, returned_cache = depsolve(request, new_unsolved, new_desired_versions, environment_constraints, cookbook_obj_cache)
|
|
115
|
+
cookbook_obj_cache = returned_cache || cookbook_obj_cache
|
|
114
116
|
return [result, cookbook_obj_cache] if result
|
|
115
117
|
end
|
|
116
118
|
[nil, nil]
|
|
@@ -118,7 +120,8 @@ module ChefZero
|
|
|
118
120
|
|
|
119
121
|
def sort_versions(versions)
|
|
120
122
|
result = versions.sort_by { |version| Gem::Version.new(version.dup) }
|
|
121
|
-
result.reverse
|
|
123
|
+
result.reverse!
|
|
124
|
+
result
|
|
122
125
|
end
|
|
123
126
|
|
|
124
127
|
def filter_by_constraint(versions, cookbook_name, constraint)
|
data/lib/chef_zero/server.rb
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: John Keiser (<jkeiser@opscode.com>)
|
|
3
|
-
# Copyright:: Copyright (c) 2012-
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
#
|
|
2
2
|
# Author:: Daniel DeLeo (<dan@chef.io>)
|
|
3
|
-
# Copyright:: Copyright (c) 2012
|
|
3
|
+
# Copyright:: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
4
4
|
# License:: Apache License, Version 2.0
|
|
5
5
|
#
|
|
6
6
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
data/lib/chef_zero/version.rb
CHANGED
|
@@ -0,0 +1,436 @@
|
|
|
1
|
+
require "uri" unless defined?(URI)
|
|
2
|
+
require "chef_zero/endpoints/environment_cookbook_versions_endpoint"
|
|
3
|
+
|
|
4
|
+
describe ChefZero::Endpoints::EnvironmentCookbookVersionsEndpoint do
|
|
5
|
+
let(:server) { double("server") }
|
|
6
|
+
let(:endpoint) { described_class.new(server) }
|
|
7
|
+
|
|
8
|
+
describe "#sort_versions" do
|
|
9
|
+
it "returns versions sorted descending by semver" do
|
|
10
|
+
versions = ["1.0.0", "2.0.0", "1.5.0", "0.9.0"]
|
|
11
|
+
expect(endpoint.sort_versions(versions)).to eq(["2.0.0", "1.5.0", "1.0.0", "0.9.0"])
|
|
12
|
+
end
|
|
13
|
+
|
|
14
|
+
it "handles single-element lists" do
|
|
15
|
+
expect(endpoint.sort_versions(["1.0.0"])).to eq(["1.0.0"])
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
it "handles an empty list" do
|
|
19
|
+
expect(endpoint.sort_versions([])).to eq([])
|
|
20
|
+
end
|
|
21
|
+
|
|
22
|
+
it "sorts multi-digit version components numerically" do
|
|
23
|
+
versions = ["1.2.3", "1.10.0", "1.9.0"]
|
|
24
|
+
expect(endpoint.sort_versions(versions)).to eq(["1.10.0", "1.9.0", "1.2.3"])
|
|
25
|
+
end
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
describe "#filter_by_constraint" do
|
|
29
|
+
let(:versions) { { "apache" => ["1.0.0", "1.5.0", "2.0.0", "2.1.0"] } }
|
|
30
|
+
|
|
31
|
+
it "returns versions unchanged when constraint is nil" do
|
|
32
|
+
result = endpoint.filter_by_constraint(versions, "apache", nil)
|
|
33
|
+
expect(result["apache"]).to eq(["1.0.0", "1.5.0", "2.0.0", "2.1.0"])
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
it "filters with an exact version constraint" do
|
|
37
|
+
result = endpoint.filter_by_constraint(versions, "apache", "= 1.5.0")
|
|
38
|
+
expect(result["apache"]).to eq(["1.5.0"])
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
it "filters with a >= constraint" do
|
|
42
|
+
result = endpoint.filter_by_constraint(versions, "apache", ">= 2.0.0")
|
|
43
|
+
expect(result["apache"]).to eq(["2.0.0", "2.1.0"])
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
it "filters with a ~> constraint" do
|
|
47
|
+
result = endpoint.filter_by_constraint(versions, "apache", "~> 1.0")
|
|
48
|
+
expect(result["apache"]).to eq(["1.0.0", "1.5.0"])
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
it "returns empty array when no versions match" do
|
|
52
|
+
result = endpoint.filter_by_constraint(versions, "apache", "= 9.9.9")
|
|
53
|
+
expect(result["apache"]).to eq([])
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
it "does not mutate the original versions hash" do
|
|
57
|
+
original = versions.dup
|
|
58
|
+
endpoint.filter_by_constraint(versions, "apache", "= 1.0.0")
|
|
59
|
+
expect(versions).to eq(original)
|
|
60
|
+
end
|
|
61
|
+
end
|
|
62
|
+
|
|
63
|
+
describe "#depsolve" do
|
|
64
|
+
let(:org_prefix) { %w{organizations testorg} }
|
|
65
|
+
let(:request) { double("request", rest_path: org_prefix + %w{environments _default cookbook_versions}) }
|
|
66
|
+
let(:data_store) { double("data_store") }
|
|
67
|
+
|
|
68
|
+
before do
|
|
69
|
+
allow(server).to receive(:data_store).and_return(data_store)
|
|
70
|
+
end
|
|
71
|
+
|
|
72
|
+
def cookbook_json(name, version, dependencies = {})
|
|
73
|
+
FFI_Yajl::Encoder.encode({
|
|
74
|
+
"metadata" => {
|
|
75
|
+
"name" => name,
|
|
76
|
+
"version" => version,
|
|
77
|
+
"dependencies" => dependencies,
|
|
78
|
+
},
|
|
79
|
+
})
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
context "base cases" do
|
|
83
|
+
it "returns [nil, nil] when a cookbook has empty versions" do
|
|
84
|
+
desired = { "apache" => [] }
|
|
85
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
86
|
+
expect(result).to be_nil
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
it "sets @last_constraint_failure when a cookbook has empty versions" do
|
|
90
|
+
desired = { "apache" => [] }
|
|
91
|
+
endpoint.depsolve(request, ["apache"], desired, {})
|
|
92
|
+
expect(endpoint.instance_variable_get(:@last_constraint_failure)).to eq("apache")
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
it "returns desired_versions when unsolved list is empty" do
|
|
96
|
+
desired = { "apache" => ["1.0.0"] }
|
|
97
|
+
result, _cache = endpoint.depsolve(request, [], desired, {})
|
|
98
|
+
expect(result).to eq(desired)
|
|
99
|
+
end
|
|
100
|
+
|
|
101
|
+
it "resolves a cookbook with no metadata key" do
|
|
102
|
+
desired = { "minimal" => ["1.0.0"] }
|
|
103
|
+
allow(data_store).to receive(:get)
|
|
104
|
+
.with(org_prefix + ["cookbooks", "minimal", "1.0.0"], request)
|
|
105
|
+
.and_return(FFI_Yajl::Encoder.encode({}))
|
|
106
|
+
|
|
107
|
+
result, cache = endpoint.depsolve(request, ["minimal"], desired, {})
|
|
108
|
+
expect(result["minimal"]).to eq(["1.0.0"])
|
|
109
|
+
expect(cache["minimal"]).to have_key("1.0.0")
|
|
110
|
+
end
|
|
111
|
+
end
|
|
112
|
+
|
|
113
|
+
context "simple resolution" do
|
|
114
|
+
it "resolves a single cookbook with no dependencies" do
|
|
115
|
+
desired = { "apache" => ["1.0.0", "2.0.0"] }
|
|
116
|
+
allow(data_store).to receive(:get)
|
|
117
|
+
.with(org_prefix + ["cookbooks", "apache", "2.0.0"], request)
|
|
118
|
+
.and_return(cookbook_json("apache", "2.0.0"))
|
|
119
|
+
allow(data_store).to receive(:get)
|
|
120
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
121
|
+
.and_return(cookbook_json("apache", "1.0.0"))
|
|
122
|
+
|
|
123
|
+
result, cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
124
|
+
expect(result["apache"]).to eq(["2.0.0"])
|
|
125
|
+
expect(cache["apache"]["2.0.0"]).to be_a(Hash)
|
|
126
|
+
end
|
|
127
|
+
|
|
128
|
+
it "resolves a cookbook with a satisfiable dependency" do
|
|
129
|
+
desired = { "apache" => ["1.0.0"] }
|
|
130
|
+
allow(data_store).to receive(:get)
|
|
131
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
132
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 1.0.0" }))
|
|
133
|
+
allow(data_store).to receive(:exists_dir?)
|
|
134
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
135
|
+
.and_return(true)
|
|
136
|
+
allow(data_store).to receive(:list)
|
|
137
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
138
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
139
|
+
allow(data_store).to receive(:get)
|
|
140
|
+
.with(org_prefix + ["cookbooks", "mysql", "2.0.0"], request)
|
|
141
|
+
.and_return(cookbook_json("mysql", "2.0.0"))
|
|
142
|
+
allow(data_store).to receive(:get)
|
|
143
|
+
.with(org_prefix + ["cookbooks", "mysql", "1.0.0"], request)
|
|
144
|
+
.and_return(cookbook_json("mysql", "1.0.0"))
|
|
145
|
+
|
|
146
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
147
|
+
expect(result["apache"]).to eq(["1.0.0"])
|
|
148
|
+
expect(result["mysql"]).to eq(["2.0.0"])
|
|
149
|
+
end
|
|
150
|
+
|
|
151
|
+
it "returns [nil, nil] when a dependency cookbook does not exist" do
|
|
152
|
+
desired = { "apache" => ["1.0.0"] }
|
|
153
|
+
allow(data_store).to receive(:get)
|
|
154
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
155
|
+
.and_return(cookbook_json("apache", "1.0.0", { "missing" => ">= 0.0.0" }))
|
|
156
|
+
allow(data_store).to receive(:exists_dir?)
|
|
157
|
+
.with(org_prefix + %w{cookbooks missing})
|
|
158
|
+
.and_return(false)
|
|
159
|
+
|
|
160
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
161
|
+
expect(result).to be_nil
|
|
162
|
+
expect(endpoint.instance_variable_get(:@last_missing_dep)).to eq("missing")
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
context "constraint filtering" do
|
|
167
|
+
it "applies environment constraints to dependency versions" do
|
|
168
|
+
desired = { "apache" => ["1.0.0"] }
|
|
169
|
+
env_constraints = { "mysql" => "= 1.0.0" }
|
|
170
|
+
|
|
171
|
+
allow(data_store).to receive(:get)
|
|
172
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
173
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 0.0.0" }))
|
|
174
|
+
allow(data_store).to receive(:exists_dir?)
|
|
175
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
176
|
+
.and_return(true)
|
|
177
|
+
allow(data_store).to receive(:list)
|
|
178
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
179
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
180
|
+
allow(data_store).to receive(:get)
|
|
181
|
+
.with(org_prefix + ["cookbooks", "mysql", "1.0.0"], request)
|
|
182
|
+
.and_return(cookbook_json("mysql", "1.0.0"))
|
|
183
|
+
|
|
184
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, env_constraints)
|
|
185
|
+
expect(result["mysql"]).to eq(["1.0.0"])
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
it "filters dependency versions by the dependency's own constraint" do
|
|
189
|
+
desired = { "apache" => ["1.0.0"] }
|
|
190
|
+
allow(data_store).to receive(:get)
|
|
191
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
192
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 2.0.0" }))
|
|
193
|
+
allow(data_store).to receive(:exists_dir?)
|
|
194
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
195
|
+
.and_return(true)
|
|
196
|
+
allow(data_store).to receive(:list)
|
|
197
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
198
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
199
|
+
allow(data_store).to receive(:get)
|
|
200
|
+
.with(org_prefix + ["cookbooks", "mysql", "2.0.0"], request)
|
|
201
|
+
.and_return(cookbook_json("mysql", "2.0.0"))
|
|
202
|
+
|
|
203
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
204
|
+
expect(result["mysql"]).to eq(["2.0.0"])
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
it "returns nil when dep constraint filters out all available versions" do
|
|
208
|
+
desired = { "apache" => ["1.0.0"] }
|
|
209
|
+
allow(data_store).to receive(:get)
|
|
210
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
211
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 5.0.0" }))
|
|
212
|
+
allow(data_store).to receive(:exists_dir?)
|
|
213
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
214
|
+
.and_return(true)
|
|
215
|
+
allow(data_store).to receive(:list)
|
|
216
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
217
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
218
|
+
|
|
219
|
+
result, _cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
220
|
+
expect(result).to be_nil
|
|
221
|
+
end
|
|
222
|
+
end
|
|
223
|
+
|
|
224
|
+
context "backtracking" do
|
|
225
|
+
it "falls back to an older version when newest has unsatisfiable dep" do
|
|
226
|
+
desired = { "web" => ["1.0.0", "2.0.0"] }
|
|
227
|
+
# v2.0.0 depends on "ghost" which doesn't exist
|
|
228
|
+
allow(data_store).to receive(:get)
|
|
229
|
+
.with(org_prefix + ["cookbooks", "web", "2.0.0"], request)
|
|
230
|
+
.and_return(cookbook_json("web", "2.0.0", { "ghost" => ">= 0.0.0" }))
|
|
231
|
+
allow(data_store).to receive(:exists_dir?)
|
|
232
|
+
.with(org_prefix + %w{cookbooks ghost})
|
|
233
|
+
.and_return(false)
|
|
234
|
+
# v1.0.0 has no deps
|
|
235
|
+
allow(data_store).to receive(:get)
|
|
236
|
+
.with(org_prefix + ["cookbooks", "web", "1.0.0"], request)
|
|
237
|
+
.and_return(cookbook_json("web", "1.0.0"))
|
|
238
|
+
|
|
239
|
+
result, _cache = endpoint.depsolve(request, ["web"], desired, {})
|
|
240
|
+
expect(result["web"]).to eq(["1.0.0"])
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
it "backtracks through multiple failing versions" do
|
|
244
|
+
desired = { "web" => ["1.0.0", "2.0.0", "3.0.0"] }
|
|
245
|
+
allow(data_store).to receive(:get)
|
|
246
|
+
.with(org_prefix + ["cookbooks", "web", "3.0.0"], request)
|
|
247
|
+
.and_return(cookbook_json("web", "3.0.0", { "missing_a" => ">= 0.0.0" }))
|
|
248
|
+
allow(data_store).to receive(:exists_dir?)
|
|
249
|
+
.with(org_prefix + %w{cookbooks missing_a})
|
|
250
|
+
.and_return(false)
|
|
251
|
+
allow(data_store).to receive(:get)
|
|
252
|
+
.with(org_prefix + ["cookbooks", "web", "2.0.0"], request)
|
|
253
|
+
.and_return(cookbook_json("web", "2.0.0", { "missing_b" => ">= 0.0.0" }))
|
|
254
|
+
allow(data_store).to receive(:exists_dir?)
|
|
255
|
+
.with(org_prefix + %w{cookbooks missing_b})
|
|
256
|
+
.and_return(false)
|
|
257
|
+
allow(data_store).to receive(:get)
|
|
258
|
+
.with(org_prefix + ["cookbooks", "web", "1.0.0"], request)
|
|
259
|
+
.and_return(cookbook_json("web", "1.0.0"))
|
|
260
|
+
|
|
261
|
+
result, _cache = endpoint.depsolve(request, ["web"], desired, {})
|
|
262
|
+
expect(result["web"]).to eq(["1.0.0"])
|
|
263
|
+
end
|
|
264
|
+
end
|
|
265
|
+
|
|
266
|
+
context "multiple cookbooks and dependencies" do
|
|
267
|
+
it "populates cache entries for all resolved cookbooks" do
|
|
268
|
+
desired = { "apache" => ["1.0.0"] }
|
|
269
|
+
allow(data_store).to receive(:get)
|
|
270
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
271
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 1.0.0" }))
|
|
272
|
+
allow(data_store).to receive(:exists_dir?)
|
|
273
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
274
|
+
.and_return(true)
|
|
275
|
+
allow(data_store).to receive(:list)
|
|
276
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
277
|
+
.and_return(["1.0.0"])
|
|
278
|
+
allow(data_store).to receive(:get)
|
|
279
|
+
.with(org_prefix + ["cookbooks", "mysql", "1.0.0"], request)
|
|
280
|
+
.and_return(cookbook_json("mysql", "1.0.0"))
|
|
281
|
+
|
|
282
|
+
_result, cache = endpoint.depsolve(request, ["apache"], desired, {})
|
|
283
|
+
expect(cache["apache"]).to have_key("1.0.0")
|
|
284
|
+
expect(cache["apache"]["1.0.0"]["metadata"]["name"]).to eq("apache")
|
|
285
|
+
expect(cache["mysql"]).to have_key("1.0.0")
|
|
286
|
+
expect(cache["mysql"]["1.0.0"]["metadata"]["name"]).to eq("mysql")
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
it "resolves multiple independent unsolved cookbooks" do
|
|
290
|
+
desired = {
|
|
291
|
+
"apache" => ["1.0.0", "2.0.0"],
|
|
292
|
+
"nginx" => ["3.0.0", "4.0.0"],
|
|
293
|
+
}
|
|
294
|
+
allow(data_store).to receive(:get)
|
|
295
|
+
.with(org_prefix + ["cookbooks", "apache", "2.0.0"], request)
|
|
296
|
+
.and_return(cookbook_json("apache", "2.0.0"))
|
|
297
|
+
allow(data_store).to receive(:get)
|
|
298
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
299
|
+
.and_return(cookbook_json("apache", "1.0.0"))
|
|
300
|
+
allow(data_store).to receive(:get)
|
|
301
|
+
.with(org_prefix + ["cookbooks", "nginx", "4.0.0"], request)
|
|
302
|
+
.and_return(cookbook_json("nginx", "4.0.0"))
|
|
303
|
+
allow(data_store).to receive(:get)
|
|
304
|
+
.with(org_prefix + ["cookbooks", "nginx", "3.0.0"], request)
|
|
305
|
+
.and_return(cookbook_json("nginx", "3.0.0"))
|
|
306
|
+
|
|
307
|
+
result, cache = endpoint.depsolve(request, %w{apache nginx}, desired, {})
|
|
308
|
+
expect(result["apache"]).to eq(["2.0.0"])
|
|
309
|
+
expect(result["nginx"]).to eq(["4.0.0"])
|
|
310
|
+
expect(cache.keys).to contain_exactly("apache", "nginx")
|
|
311
|
+
end
|
|
312
|
+
|
|
313
|
+
it "resolves a diamond dependency (two cookbooks sharing a dep)" do
|
|
314
|
+
desired = {
|
|
315
|
+
"apache" => ["1.0.0"],
|
|
316
|
+
"nginx" => ["1.0.0"],
|
|
317
|
+
}
|
|
318
|
+
allow(data_store).to receive(:get)
|
|
319
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
320
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 1.0.0" }))
|
|
321
|
+
allow(data_store).to receive(:get)
|
|
322
|
+
.with(org_prefix + ["cookbooks", "nginx", "1.0.0"], request)
|
|
323
|
+
.and_return(cookbook_json("nginx", "1.0.0", { "mysql" => ">= 2.0.0" }))
|
|
324
|
+
allow(data_store).to receive(:exists_dir?)
|
|
325
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
326
|
+
.and_return(true)
|
|
327
|
+
allow(data_store).to receive(:list)
|
|
328
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
329
|
+
.and_return(["1.0.0", "2.0.0", "3.0.0"])
|
|
330
|
+
allow(data_store).to receive(:get)
|
|
331
|
+
.with(org_prefix + ["cookbooks", "mysql", "3.0.0"], request)
|
|
332
|
+
.and_return(cookbook_json("mysql", "3.0.0"))
|
|
333
|
+
allow(data_store).to receive(:get)
|
|
334
|
+
.with(org_prefix + ["cookbooks", "mysql", "2.0.0"], request)
|
|
335
|
+
.and_return(cookbook_json("mysql", "2.0.0"))
|
|
336
|
+
|
|
337
|
+
result, _cache = endpoint.depsolve(request, %w{apache nginx}, desired, {})
|
|
338
|
+
expect(result["apache"]).to eq(["1.0.0"])
|
|
339
|
+
expect(result["nginx"]).to eq(["1.0.0"])
|
|
340
|
+
expect(result["mysql"]).to eq(["3.0.0"])
|
|
341
|
+
end
|
|
342
|
+
|
|
343
|
+
it "returns nil when dependency constraints from two cookbooks conflict" do
|
|
344
|
+
desired = {
|
|
345
|
+
"apache" => ["1.0.0"],
|
|
346
|
+
"nginx" => ["1.0.0"],
|
|
347
|
+
}
|
|
348
|
+
allow(data_store).to receive(:get)
|
|
349
|
+
.with(org_prefix + ["cookbooks", "apache", "1.0.0"], request)
|
|
350
|
+
.and_return(cookbook_json("apache", "1.0.0", { "mysql" => ">= 2.0.0" }))
|
|
351
|
+
allow(data_store).to receive(:get)
|
|
352
|
+
.with(org_prefix + ["cookbooks", "nginx", "1.0.0"], request)
|
|
353
|
+
.and_return(cookbook_json("nginx", "1.0.0", { "mysql" => "< 2.0.0" }))
|
|
354
|
+
allow(data_store).to receive(:exists_dir?)
|
|
355
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
356
|
+
.and_return(true)
|
|
357
|
+
allow(data_store).to receive(:list)
|
|
358
|
+
.with(org_prefix + %w{cookbooks mysql})
|
|
359
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
360
|
+
|
|
361
|
+
result, _cache = endpoint.depsolve(request, %w{apache nginx}, desired, {})
|
|
362
|
+
expect(result).to be_nil
|
|
363
|
+
end
|
|
364
|
+
|
|
365
|
+
it "uses cached cookbook data instead of re-fetching during backtracking" do
|
|
366
|
+
desired = {
|
|
367
|
+
"web" => ["1.0.0", "2.0.0"],
|
|
368
|
+
"db" => ["1.0.0"],
|
|
369
|
+
}
|
|
370
|
+
# web 2.0.0 depends on lib, which depends on missing (doesn't exist) → branch fails
|
|
371
|
+
# web 1.0.0 has no deps → backtracks here, db must be re-solved
|
|
372
|
+
# db 1.0.0 should be fetched only once (cached from the first branch)
|
|
373
|
+
allow(data_store).to receive(:get)
|
|
374
|
+
.with(org_prefix + ["cookbooks", "web", "2.0.0"], request)
|
|
375
|
+
.and_return(cookbook_json("web", "2.0.0", { "lib" => ">= 1.0.0" }))
|
|
376
|
+
allow(data_store).to receive(:get)
|
|
377
|
+
.with(org_prefix + ["cookbooks", "web", "1.0.0"], request)
|
|
378
|
+
.and_return(cookbook_json("web", "1.0.0"))
|
|
379
|
+
expect(data_store).to receive(:get)
|
|
380
|
+
.with(org_prefix + ["cookbooks", "db", "1.0.0"], request)
|
|
381
|
+
.once
|
|
382
|
+
.and_return(cookbook_json("db", "1.0.0"))
|
|
383
|
+
allow(data_store).to receive(:exists_dir?)
|
|
384
|
+
.with(org_prefix + %w{cookbooks lib})
|
|
385
|
+
.and_return(true)
|
|
386
|
+
allow(data_store).to receive(:list)
|
|
387
|
+
.with(org_prefix + %w{cookbooks lib})
|
|
388
|
+
.and_return(["1.0.0"])
|
|
389
|
+
allow(data_store).to receive(:get)
|
|
390
|
+
.with(org_prefix + ["cookbooks", "lib", "1.0.0"], request)
|
|
391
|
+
.and_return(cookbook_json("lib", "1.0.0", { "missing" => ">= 1.0.0" }))
|
|
392
|
+
allow(data_store).to receive(:exists_dir?)
|
|
393
|
+
.with(org_prefix + %w{cookbooks missing})
|
|
394
|
+
.and_return(false)
|
|
395
|
+
|
|
396
|
+
result, _cache = endpoint.depsolve(request, %w{web db}, desired, {})
|
|
397
|
+
expect(result["web"]).to eq(["1.0.0"])
|
|
398
|
+
expect(result["db"]).to eq(["1.0.0"])
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
it "resolves a deep dependency chain" do
|
|
402
|
+
desired = { "app" => ["1.0.0"] }
|
|
403
|
+
allow(data_store).to receive(:get)
|
|
404
|
+
.with(org_prefix + ["cookbooks", "app", "1.0.0"], request)
|
|
405
|
+
.and_return(cookbook_json("app", "1.0.0", { "framework" => ">= 1.0.0" }))
|
|
406
|
+
allow(data_store).to receive(:exists_dir?)
|
|
407
|
+
.with(org_prefix + %w{cookbooks framework})
|
|
408
|
+
.and_return(true)
|
|
409
|
+
allow(data_store).to receive(:list)
|
|
410
|
+
.with(org_prefix + %w{cookbooks framework})
|
|
411
|
+
.and_return(["1.0.0"])
|
|
412
|
+
allow(data_store).to receive(:get)
|
|
413
|
+
.with(org_prefix + ["cookbooks", "framework", "1.0.0"], request)
|
|
414
|
+
.and_return(cookbook_json("framework", "1.0.0", { "lib" => ">= 1.0.0" }))
|
|
415
|
+
allow(data_store).to receive(:exists_dir?)
|
|
416
|
+
.with(org_prefix + %w{cookbooks lib})
|
|
417
|
+
.and_return(true)
|
|
418
|
+
allow(data_store).to receive(:list)
|
|
419
|
+
.with(org_prefix + %w{cookbooks lib})
|
|
420
|
+
.and_return(["1.0.0", "2.0.0"])
|
|
421
|
+
allow(data_store).to receive(:get)
|
|
422
|
+
.with(org_prefix + ["cookbooks", "lib", "2.0.0"], request)
|
|
423
|
+
.and_return(cookbook_json("lib", "2.0.0"))
|
|
424
|
+
allow(data_store).to receive(:get)
|
|
425
|
+
.with(org_prefix + ["cookbooks", "lib", "1.0.0"], request)
|
|
426
|
+
.and_return(cookbook_json("lib", "1.0.0"))
|
|
427
|
+
|
|
428
|
+
result, cache = endpoint.depsolve(request, ["app"], desired, {})
|
|
429
|
+
expect(result["app"]).to eq(["1.0.0"])
|
|
430
|
+
expect(result["framework"]).to eq(["1.0.0"])
|
|
431
|
+
expect(result["lib"]).to eq(["2.0.0"])
|
|
432
|
+
expect(cache.keys).to contain_exactly("app", "framework", "lib")
|
|
433
|
+
end
|
|
434
|
+
end
|
|
435
|
+
end
|
|
436
|
+
end
|
data/spec/support/oc_pedant.rb
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Copyright: Copyright (c) 2012
|
|
1
|
+
# Copyright: Copyright (c) 2012-2025 Progress Software Corporation and/or its subsidiaries or affiliates. All Rights Reserved.
|
|
2
2
|
# License: Apache License, Version 2.0
|
|
3
3
|
#
|
|
4
4
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
metadata
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: chef-zero
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 15.1.
|
|
4
|
+
version: 15.1.11
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Chef Software, Inc.
|
|
8
8
|
bindir: bin
|
|
9
9
|
cert_chain: []
|
|
10
|
-
date:
|
|
10
|
+
date: 2026-05-28 00:00:00.000000000 Z
|
|
11
11
|
dependencies:
|
|
12
12
|
- !ruby/object:Gem::Dependency
|
|
13
13
|
name: mixlib-log
|
|
@@ -53,16 +53,22 @@ dependencies:
|
|
|
53
53
|
name: uuidtools
|
|
54
54
|
requirement: !ruby/object:Gem::Requirement
|
|
55
55
|
requirements:
|
|
56
|
-
- - "
|
|
56
|
+
- - ">="
|
|
57
57
|
- !ruby/object:Gem::Version
|
|
58
58
|
version: '2.1'
|
|
59
|
+
- - "<"
|
|
60
|
+
- !ruby/object:Gem::Version
|
|
61
|
+
version: '4.0'
|
|
59
62
|
type: :runtime
|
|
60
63
|
prerelease: false
|
|
61
64
|
version_requirements: !ruby/object:Gem::Requirement
|
|
62
65
|
requirements:
|
|
63
|
-
- - "
|
|
66
|
+
- - ">="
|
|
64
67
|
- !ruby/object:Gem::Version
|
|
65
68
|
version: '2.1'
|
|
69
|
+
- - "<"
|
|
70
|
+
- !ruby/object:Gem::Version
|
|
71
|
+
version: '4.0'
|
|
66
72
|
- !ruby/object:Gem::Dependency
|
|
67
73
|
name: ffi-yajl
|
|
68
74
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -89,54 +95,40 @@ dependencies:
|
|
|
89
95
|
requirements:
|
|
90
96
|
- - "~>"
|
|
91
97
|
- !ruby/object:Gem::Version
|
|
92
|
-
version: '3.
|
|
98
|
+
version: '3.2'
|
|
93
99
|
- - ">="
|
|
94
100
|
- !ruby/object:Gem::Version
|
|
95
|
-
version: 3.
|
|
101
|
+
version: 3.2.6
|
|
96
102
|
type: :runtime
|
|
97
103
|
prerelease: false
|
|
98
104
|
version_requirements: !ruby/object:Gem::Requirement
|
|
99
105
|
requirements:
|
|
100
106
|
- - "~>"
|
|
101
107
|
- !ruby/object:Gem::Version
|
|
102
|
-
version: '3.
|
|
108
|
+
version: '3.2'
|
|
103
109
|
- - ">="
|
|
104
110
|
- !ruby/object:Gem::Version
|
|
105
|
-
version: 3.
|
|
111
|
+
version: 3.2.6
|
|
106
112
|
- !ruby/object:Gem::Dependency
|
|
107
113
|
name: rackup
|
|
108
114
|
requirement: !ruby/object:Gem::Requirement
|
|
109
115
|
requirements:
|
|
110
116
|
- - "~>"
|
|
111
117
|
- !ruby/object:Gem::Version
|
|
112
|
-
version: '2.
|
|
118
|
+
version: '2.3'
|
|
113
119
|
- - ">="
|
|
114
120
|
- !ruby/object:Gem::Version
|
|
115
|
-
version: 2.
|
|
121
|
+
version: 2.3.1
|
|
116
122
|
type: :runtime
|
|
117
123
|
prerelease: false
|
|
118
124
|
version_requirements: !ruby/object:Gem::Requirement
|
|
119
125
|
requirements:
|
|
120
126
|
- - "~>"
|
|
121
127
|
- !ruby/object:Gem::Version
|
|
122
|
-
version: '2.
|
|
128
|
+
version: '2.3'
|
|
123
129
|
- - ">="
|
|
124
130
|
- !ruby/object:Gem::Version
|
|
125
|
-
version: 2.
|
|
126
|
-
- !ruby/object:Gem::Dependency
|
|
127
|
-
name: unf_ext
|
|
128
|
-
requirement: !ruby/object:Gem::Requirement
|
|
129
|
-
requirements:
|
|
130
|
-
- - "~>"
|
|
131
|
-
- !ruby/object:Gem::Version
|
|
132
|
-
version: 0.0.8
|
|
133
|
-
type: :runtime
|
|
134
|
-
prerelease: false
|
|
135
|
-
version_requirements: !ruby/object:Gem::Requirement
|
|
136
|
-
requirements:
|
|
137
|
-
- - "~>"
|
|
138
|
-
- !ruby/object:Gem::Version
|
|
139
|
-
version: 0.0.8
|
|
131
|
+
version: 2.3.1
|
|
140
132
|
- !ruby/object:Gem::Dependency
|
|
141
133
|
name: webrick
|
|
142
134
|
requirement: !ruby/object:Gem::Requirement
|
|
@@ -272,6 +264,7 @@ files:
|
|
|
272
264
|
- lib/chef_zero/solr/solr_doc.rb
|
|
273
265
|
- lib/chef_zero/solr/solr_parser.rb
|
|
274
266
|
- lib/chef_zero/version.rb
|
|
267
|
+
- spec/endpoints/environment_cookbook_versions_endpoint_spec.rb
|
|
275
268
|
- spec/run_oc_pedant.rb
|
|
276
269
|
- spec/search_spec.rb
|
|
277
270
|
- spec/server_spec.rb
|
|
@@ -297,7 +290,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
|
297
290
|
- !ruby/object:Gem::Version
|
|
298
291
|
version: '0'
|
|
299
292
|
requirements: []
|
|
300
|
-
rubygems_version: 3.
|
|
293
|
+
rubygems_version: 3.6.2
|
|
301
294
|
specification_version: 4
|
|
302
295
|
summary: Self-contained, easy-setup, fast-start in-memory Chef server for testing
|
|
303
296
|
and solo setup purposes
|