berkshelf-api 0.1.0

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 (59) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +17 -0
  3. data/.ruby-version +1 -0
  4. data/.travis.yml +17 -0
  5. data/CONTRIBUTING.md +33 -0
  6. data/Gemfile +40 -0
  7. data/Guardfile +20 -0
  8. data/LICENSE +201 -0
  9. data/README.md +37 -0
  10. data/Thorfile +39 -0
  11. data/berkshelf-api.gemspec +35 -0
  12. data/bin/berks-api +5 -0
  13. data/lib/berkshelf-api.rb +1 -0
  14. data/lib/berkshelf/api.rb +25 -0
  15. data/lib/berkshelf/api/application.rb +114 -0
  16. data/lib/berkshelf/api/cache_builder.rb +60 -0
  17. data/lib/berkshelf/api/cache_builder/worker.rb +116 -0
  18. data/lib/berkshelf/api/cache_builder/worker/chef_server.rb +46 -0
  19. data/lib/berkshelf/api/cache_builder/worker/opscode.rb +59 -0
  20. data/lib/berkshelf/api/cache_manager.rb +96 -0
  21. data/lib/berkshelf/api/config.rb +23 -0
  22. data/lib/berkshelf/api/cucumber.rb +11 -0
  23. data/lib/berkshelf/api/dependency_cache.rb +123 -0
  24. data/lib/berkshelf/api/endpoint.rb +17 -0
  25. data/lib/berkshelf/api/endpoint/v1.rb +19 -0
  26. data/lib/berkshelf/api/errors.rb +8 -0
  27. data/lib/berkshelf/api/generic_server.rb +50 -0
  28. data/lib/berkshelf/api/logging.rb +37 -0
  29. data/lib/berkshelf/api/mixin.rb +7 -0
  30. data/lib/berkshelf/api/mixin/services.rb +48 -0
  31. data/lib/berkshelf/api/rack_app.rb +5 -0
  32. data/lib/berkshelf/api/remote_cookbook.rb +3 -0
  33. data/lib/berkshelf/api/rest_gateway.rb +62 -0
  34. data/lib/berkshelf/api/rspec.rb +20 -0
  35. data/lib/berkshelf/api/rspec/server.rb +29 -0
  36. data/lib/berkshelf/api/site_connector.rb +7 -0
  37. data/lib/berkshelf/api/site_connector/opscode.rb +162 -0
  38. data/lib/berkshelf/api/srv_ctl.rb +63 -0
  39. data/lib/berkshelf/api/version.rb +5 -0
  40. data/spec/fixtures/reset.pem +27 -0
  41. data/spec/spec_helper.rb +53 -0
  42. data/spec/support/actor_mocking.rb +7 -0
  43. data/spec/support/chef_server.rb +73 -0
  44. data/spec/unit/berkshelf/api/application_spec.rb +24 -0
  45. data/spec/unit/berkshelf/api/cache_builder/worker/chef_server_spec.rb +59 -0
  46. data/spec/unit/berkshelf/api/cache_builder/worker/opscode_spec.rb +41 -0
  47. data/spec/unit/berkshelf/api/cache_builder/worker_spec.rb +80 -0
  48. data/spec/unit/berkshelf/api/cache_builder_spec.rb +37 -0
  49. data/spec/unit/berkshelf/api/cache_manager_spec.rb +123 -0
  50. data/spec/unit/berkshelf/api/config_spec.rb +24 -0
  51. data/spec/unit/berkshelf/api/dependency_cache_spec.rb +109 -0
  52. data/spec/unit/berkshelf/api/endpoint/v1_spec.rb +18 -0
  53. data/spec/unit/berkshelf/api/logging_spec.rb +28 -0
  54. data/spec/unit/berkshelf/api/mixin/services_spec.rb +68 -0
  55. data/spec/unit/berkshelf/api/rack_app_spec.rb +6 -0
  56. data/spec/unit/berkshelf/api/rest_gateway_spec.rb +26 -0
  57. data/spec/unit/berkshelf/api/site_connector/opscode_spec.rb +85 -0
  58. data/spec/unit/berkshelf/api/srv_ctl_spec.rb +56 -0
  59. metadata +293 -0
@@ -0,0 +1,59 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::CacheBuilder::Worker::ChefServer do
4
+ describe "ClassMethods" do
5
+ subject { described_class }
6
+ its(:worker_type) { should eql("chef_server") }
7
+ end
8
+
9
+ subject do
10
+ described_class.new(url: "http://localhost:8889", client_name: "reset",
11
+ client_key: fixtures_path.join("reset.pem"))
12
+ end
13
+
14
+ describe "#cookbooks" do
15
+ before do
16
+ chef_cookbook("ruby", "1.0.0")
17
+ chef_cookbook("ruby", "2.0.0")
18
+ chef_cookbook("elixir", "3.0.0")
19
+ chef_cookbook("elixir", "3.0.1")
20
+ end
21
+
22
+ it "returns an array containing an item for each cookbook on the server" do
23
+ expect(subject.cookbooks).to have(4).items
24
+ end
25
+
26
+ it "returns an array of RemoteCookbooks" do
27
+ subject.cookbooks.each do |cookbook|
28
+ expect(cookbook).to be_a(Berkshelf::API::RemoteCookbook)
29
+ end
30
+ end
31
+
32
+ it "each RemoteCookbook is tagged with a location_type matching the worker_type of the builder" do
33
+ subject.cookbooks.each do |cookbook|
34
+ expect(cookbook.location_type).to eql(described_class.worker_type)
35
+ end
36
+ end
37
+ end
38
+
39
+ describe "#build" do
40
+ before do
41
+ Berkshelf::API::CacheManager.start
42
+ chef_cookbook("ruby", "1.0.0")
43
+ chef_cookbook("ruby", "2.0.0")
44
+ chef_cookbook("elixir", "3.0.0")
45
+ chef_cookbook("elixir", "3.0.1")
46
+ end
47
+
48
+ let(:cache) { Berkshelf::API::CacheManager.instance.cache }
49
+
50
+ it "adds each item to the cache" do
51
+ subject.build
52
+ expect(cache).to have_cookbook("ruby", "1.0.0")
53
+ expect(cache).to have_cookbook("ruby", "2.0.0")
54
+ expect(cache).to have_cookbook("elixir", "3.0.0")
55
+ expect(cache).to have_cookbook("elixir", "3.0.1")
56
+ expect(cache.cookbooks).to have(4).items
57
+ end
58
+ end
59
+ end
@@ -0,0 +1,41 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::CacheBuilder::Worker::Opscode do
4
+ describe "ClassMethods" do
5
+ subject { described_class }
6
+ its(:worker_type) { should eql("opscode") }
7
+ end
8
+
9
+ let(:cookbooks) { ["chicken", "tuna"] }
10
+ let(:chicken_versions) { ["1.0", "2.0"] }
11
+ let(:tuna_versions) { ["3.0.0", "3.0.1"] }
12
+ let(:connection) do
13
+ connection = double('connection')
14
+ connection.stub(:cookbooks).and_return(cookbooks)
15
+ connection
16
+ end
17
+
18
+ subject do
19
+ Berkshelf::API::CacheManager.start
20
+ described_class.new
21
+ end
22
+
23
+ describe "#cookbooks" do
24
+ let(:location_type) { described_class.worker_type }
25
+ let(:location_path) { Berkshelf::API::SiteConnector::Opscode::V1_API}
26
+
27
+ it "returns an array of RemoteCookbooks described by the server" do
28
+ expected_value = [
29
+ Berkshelf::API::RemoteCookbook.new("chicken", "1.0", location_type, location_path),
30
+ Berkshelf::API::RemoteCookbook.new("chicken", "2.0", location_type, location_path),
31
+ Berkshelf::API::RemoteCookbook.new("tuna", "3.0.0", location_type, location_path),
32
+ Berkshelf::API::RemoteCookbook.new("tuna", "3.0.1", location_type, location_path)
33
+ ]
34
+
35
+ connection.should_receive(:future).with(:versions, "chicken").and_return(double(value: chicken_versions))
36
+ connection.should_receive(:future).with(:versions, "tuna").and_return(double(value: tuna_versions))
37
+ subject.should_receive(:connection).at_least(1).times.and_return(connection)
38
+ expect(subject.cookbooks).to eql(expected_value)
39
+ end
40
+ end
41
+ end
@@ -0,0 +1,80 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::CacheBuilder::Worker do
4
+ describe "ClassMethods" do
5
+ describe "::[]" do
6
+ it "returns the class of the registered worker" do
7
+ expect(described_class["opscode"]).to eql(Berkshelf::API::CacheBuilder::Worker::Opscode)
8
+ end
9
+ end
10
+
11
+ describe "::register" do
12
+ it "adds the item to the Hash of types" do
13
+ worker = double('new-worker')
14
+ described_class.register("rspec-2", worker)
15
+ expect(described_class.types["rspec-2"]).to eql(worker)
16
+ end
17
+ end
18
+
19
+ describe "::types" do
20
+ subject { described_class.types }
21
+
22
+ it "returns a Hash" do
23
+ expect(subject).to be_a(Hash)
24
+ end
25
+ end
26
+ end
27
+ end
28
+
29
+ describe Berkshelf::API::CacheBuilder::Worker::Base do
30
+ describe "ClassMethods" do
31
+ describe "::worker_type" do
32
+ let(:klass) { Class.new(described_class) }
33
+
34
+ it "registers the worker type and class to Worker.types" do
35
+ klass.worker_type("rspec")
36
+ expect(Berkshelf::API::CacheBuilder::Worker.types).to include("rspec")
37
+ end
38
+ end
39
+ end
40
+
41
+ let(:cache_manager) { double(:diff => :chicken) }
42
+ subject { described_class.new }
43
+
44
+ describe "#diff" do
45
+ it "should delegate to the cache_manager to calculate the diff" do
46
+ subject.should_receive(:cache_manager).and_return(cache_manager)
47
+ subject.should_receive(:cookbooks).and_return(:cookbooks)
48
+
49
+ expect(subject.diff).to eql(:chicken)
50
+ end
51
+
52
+ it "should memoize the diff to prevent recalculating" do
53
+ subject.should_receive(:cache_manager).exactly(1).times.and_return(cache_manager)
54
+ subject.should_receive(:cookbooks).and_return(:cookbooks)
55
+
56
+ subject.diff
57
+ subject.diff
58
+ end
59
+ end
60
+
61
+ describe "#clear_diff" do
62
+ it "should set the diff to nil" do
63
+ subject.should_receive(:cache_manager).and_return(cache_manager)
64
+ subject.should_receive(:cookbooks).and_return(:cookbooks)
65
+
66
+ subject.diff
67
+ expect(subject.instance_variable_get(:@diff)).to eql(:chicken)
68
+ subject.send(:clear_diff)
69
+ expect(subject.instance_variable_get(:@diff)).to eql(nil)
70
+ end
71
+
72
+ it "memoizes the diff to prevent recalculating" do
73
+ subject.should_receive(:cache_manager).exactly(1).times.and_return(cache_manager)
74
+ subject.should_receive(:cookbooks).and_return(:cookbooks)
75
+
76
+ subject.diff
77
+ subject.diff
78
+ end
79
+ end
80
+ end
@@ -0,0 +1,37 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::CacheBuilder do
4
+ let(:instance) { described_class.new }
5
+
6
+ describe "#build" do
7
+ subject(:build) { instance.build }
8
+ let(:workers) { [ double('worker') ] }
9
+ let(:future) { double('future', value: nil) }
10
+
11
+ before { instance.stub(workers: workers) }
12
+
13
+ it "sends a #build message to each worker" do
14
+ workers.each { |worker| worker.should_receive(:future).with(:build).and_return(future) }
15
+ build
16
+ end
17
+ end
18
+
19
+ describe "#workers" do
20
+ subject(:workers) { instance.workers }
21
+
22
+ it "returns an array of workers" do
23
+ expect(workers).to be_a(Array)
24
+ workers.each do |worker|
25
+ expect(worker).to be_a(described_class::Worker::Base)
26
+ end
27
+ end
28
+
29
+ it "has one worker started by default" do
30
+ expect(workers).to have(1).item
31
+ end
32
+
33
+ it "has an opscode worker started by default" do
34
+ expect(workers.first).to be_a(described_class::Worker::Opscode)
35
+ end
36
+ end
37
+ end
@@ -0,0 +1,123 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::CacheManager do
4
+ describe "ClassMethods" do
5
+ describe "::new" do
6
+ subject { described_class.new }
7
+ its(:cache) { should be_empty }
8
+
9
+ context "when a save file exists" do
10
+ before do
11
+ @tempfile = Tempfile.new('berkshelf-api-rspec')
12
+ described_class.stub(:cache_file) { @tempfile.path }
13
+ end
14
+ after { @tempfile.close(true) }
15
+
16
+ it "loads the saved cache" do
17
+ described_class.any_instance.should_receive(:load_save)
18
+ subject
19
+ end
20
+ end
21
+
22
+ context "when a save file does not exist" do
23
+ before { described_class.stub(cache_file: tmp_path.join('does_not_exist').to_s) }
24
+
25
+ it "skips loading of the saved cache" do
26
+ described_class.any_instance.should_not_receive(:load_save)
27
+ subject
28
+ end
29
+ end
30
+ end
31
+
32
+ describe "::start" do
33
+ it "starts and registers a cache manager it with the application" do
34
+ described_class.start
35
+
36
+ expect(Berkshelf::API::Application[:cache_manager]).to be_a(described_class)
37
+ expect(Berkshelf::API::Application[:cache_manager]).to be_alive
38
+ end
39
+ end
40
+ end
41
+
42
+ subject { described_class.new }
43
+
44
+ describe "#add" do
45
+ pending
46
+ end
47
+
48
+ describe "#load_save" do
49
+ pending
50
+ end
51
+
52
+ describe "#remove" do
53
+ pending
54
+ end
55
+
56
+ describe "#clear" do
57
+ it "returns an empty Hash" do
58
+ result = subject.clear
59
+ expect(result).to be_a(Hash)
60
+ expect(result).to be_empty
61
+ end
62
+
63
+ it "empties the cache" do
64
+ subject.clear
65
+ expect(subject.cache).to be_empty
66
+ end
67
+ end
68
+
69
+ describe "#diff" do
70
+ let(:cookbook_one) { Berkshelf::API::RemoteCookbook.new("ruby", "1.2.3", "opscode") }
71
+ let(:cookbook_two) { Berkshelf::API::RemoteCookbook.new("elixir", "2.0.0", "opscode") }
72
+ let(:comparison) { Array.new }
73
+
74
+ before do
75
+ subject.add(cookbook_one, double(dependencies: nil, platforms: nil))
76
+ subject.add(cookbook_two, double(dependencies: nil, platforms: nil))
77
+
78
+ @created, @deleted = @diff = subject.diff(comparison)
79
+ end
80
+
81
+ it "returns two items" do
82
+ expect(@diff).to have(2).items
83
+ end
84
+
85
+ context "when there are created and deleted cookbooks" do
86
+ let(:new_cookbook) { Berkshelf::API::RemoteCookbook.new("ruby", "3.0.0", "opscode") }
87
+ let(:comparison) { [ cookbook_one, new_cookbook ] }
88
+
89
+ it "should return created and deleted cookbooks" do
90
+ expect(@created).to eql([new_cookbook])
91
+ expect(@deleted).to eql([cookbook_two])
92
+ end
93
+ end
94
+
95
+ context "when there are only created cookbooks" do
96
+ let(:new_cookbook) { Berkshelf::API::RemoteCookbook.new("ruby", "3.0.0", "opscode") }
97
+ let(:comparison) { [ cookbook_one, cookbook_two, new_cookbook ] }
98
+
99
+ it "should return only created cookbooks" do
100
+ expect(@created).to eql([new_cookbook])
101
+ expect(@deleted).to be_empty
102
+ end
103
+ end
104
+
105
+ context "when there are only deleted cookbooks" do
106
+ let(:comparison) { [ cookbook_one ] }
107
+
108
+ it "should return only deleted cookbooks" do
109
+ expect(@created).to be_empty
110
+ expect(@deleted).to eql([cookbook_two])
111
+ end
112
+ end
113
+
114
+ context "when there are no differences" do
115
+ let(:comparison) { [ cookbook_one, cookbook_two ] }
116
+
117
+ it "should return empty arrays" do
118
+ expect(@created).to be_empty
119
+ expect(@deleted).to be_empty
120
+ end
121
+ end
122
+ end
123
+ end
@@ -0,0 +1,24 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::Config do
4
+ describe "ClassMethods" do
5
+ describe "::default_path" do
6
+ it "returns a String" do
7
+ expect(described_class.default_path).to be_a(String)
8
+ end
9
+ end
10
+ end
11
+
12
+ describe "default config" do
13
+ subject { described_class.new }
14
+
15
+ it "has a endpoint configured" do
16
+ expect(subject.endpoints).to have(1).item
17
+ end
18
+
19
+ it "has the Opscode community site as an endpoint" do
20
+ expect(subject.endpoints.first.type).to eql("opscode")
21
+ expect(subject.endpoints.first.options[:url]).to eql("http://cookbooks.opscode.com/api/v1")
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,109 @@
1
+ require 'spec_helper'
2
+
3
+ describe Berkshelf::API::DependencyCache do
4
+ describe "ClassMethods" do
5
+ describe "::from_file" do
6
+ let(:filepath) { @tempfile.path }
7
+ before { @tempfile = Tempfile.new('berkshelf-api-rspec') }
8
+ after { @tempfile.close(true) }
9
+
10
+ subject { described_class.from_file(filepath) }
11
+
12
+ context "when the file contains valid json" do
13
+ before do
14
+ @tempfile.write(JSON.generate({brooke: "winsor"}))
15
+ @tempfile.flush
16
+ end
17
+
18
+ it "returns an instance of DependencyCache" do
19
+ expect(subject).to be_a(described_class)
20
+ end
21
+ end
22
+
23
+ context "when the filepath does not exist" do
24
+ let(:filepath) { nil }
25
+
26
+ it "raises a SaveNotFoundError" do
27
+ expect { subject }.to raise_error(Berkshelf::API::SaveNotFoundError)
28
+ end
29
+ end
30
+
31
+ context "when the file does not contain valid JSON" do
32
+ let(:filepath) { @tempfile.path }
33
+ before do
34
+ @tempfile.write("asdfasdfasdf")
35
+ @tempfile.flush
36
+ end
37
+
38
+ it "raises an InvalidSaveError" do
39
+ expect { subject }.to raise_error(Berkshelf::API::InvalidSaveError)
40
+ end
41
+ end
42
+ end
43
+ end
44
+
45
+ let(:chicken) do
46
+ { "1.0" =>
47
+ {
48
+ dependencies: { "tuna" => "= 3.0.0" },
49
+ platforms: { "centos" => ">= 0.0.0" }
50
+ }
51
+ }
52
+ end
53
+ let(:tuna) do
54
+ { "3.0.0" =>
55
+ {
56
+ dependencies: { },
57
+ platforms: { "centos" => ">= 0.0.0" }
58
+ }
59
+ }
60
+ end
61
+ let(:contents) do
62
+ {
63
+ "chicken" => chicken,
64
+ "tuna" => tuna,
65
+ }
66
+ end
67
+
68
+ subject { described_class.new(contents) }
69
+
70
+ describe "#cookbooks" do
71
+ it "should return a list of RemoteCookbooks" do
72
+ expected_value = [
73
+ Berkshelf::API::RemoteCookbook.new("chicken", "1.0"),
74
+ Berkshelf::API::RemoteCookbook.new("tuna", "3.0.0")
75
+ ]
76
+
77
+ expect(subject.cookbooks).to eql(expected_value)
78
+ end
79
+ end
80
+
81
+ describe "#add" do
82
+ let(:cookbook) { Berkshelf::API::RemoteCookbook.new("ruby", "1.2.3", "opscode") }
83
+ before { subject.clear }
84
+
85
+ it "adds items to the cache" do
86
+ subject.add(cookbook, double(platforms: nil, dependencies: nil))
87
+ expect(subject.to_hash).to have(1).item
88
+ end
89
+ end
90
+
91
+ describe "#save" do
92
+ let(:path) { tmp_path.join('cerch.json') }
93
+
94
+ it "saves the contents of the cache as json to the given path" do
95
+ subject.save(path)
96
+ expect(File.exist?(path)).to be_true
97
+ end
98
+ end
99
+
100
+ describe "#clear" do
101
+ let(:cookbook) { Berkshelf::API::RemoteCookbook.new("ruby", "1.2.3", "opscode") }
102
+ before { subject.add(cookbook, double(platforms: nil, dependencies: nil)) }
103
+
104
+ it "empties items added to the cache" do
105
+ subject.clear
106
+ expect(subject).to be_empty
107
+ end
108
+ end
109
+ end