bosh_cli 0.16

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 (113) hide show
  1. data/README +4 -0
  2. data/Rakefile +55 -0
  3. data/bin/bosh +17 -0
  4. data/lib/cli.rb +76 -0
  5. data/lib/cli/cache.rb +44 -0
  6. data/lib/cli/changeset_helper.rb +142 -0
  7. data/lib/cli/command_definition.rb +52 -0
  8. data/lib/cli/commands/base.rb +245 -0
  9. data/lib/cli/commands/biff.rb +300 -0
  10. data/lib/cli/commands/blob.rb +125 -0
  11. data/lib/cli/commands/cloudcheck.rb +169 -0
  12. data/lib/cli/commands/deployment.rb +147 -0
  13. data/lib/cli/commands/job.rb +42 -0
  14. data/lib/cli/commands/job_management.rb +117 -0
  15. data/lib/cli/commands/log_management.rb +81 -0
  16. data/lib/cli/commands/maintenance.rb +131 -0
  17. data/lib/cli/commands/misc.rb +240 -0
  18. data/lib/cli/commands/package.rb +112 -0
  19. data/lib/cli/commands/property_management.rb +125 -0
  20. data/lib/cli/commands/release.rb +469 -0
  21. data/lib/cli/commands/ssh.rb +271 -0
  22. data/lib/cli/commands/stemcell.rb +184 -0
  23. data/lib/cli/commands/task.rb +213 -0
  24. data/lib/cli/commands/user.rb +28 -0
  25. data/lib/cli/commands/vms.rb +53 -0
  26. data/lib/cli/config.rb +154 -0
  27. data/lib/cli/core_ext.rb +145 -0
  28. data/lib/cli/dependency_helper.rb +62 -0
  29. data/lib/cli/deployment_helper.rb +263 -0
  30. data/lib/cli/deployment_manifest_compiler.rb +28 -0
  31. data/lib/cli/director.rb +633 -0
  32. data/lib/cli/director_task.rb +64 -0
  33. data/lib/cli/errors.rb +48 -0
  34. data/lib/cli/event_log_renderer.rb +351 -0
  35. data/lib/cli/job_builder.rb +226 -0
  36. data/lib/cli/package_builder.rb +254 -0
  37. data/lib/cli/packaging_helper.rb +248 -0
  38. data/lib/cli/release.rb +176 -0
  39. data/lib/cli/release_builder.rb +215 -0
  40. data/lib/cli/release_compiler.rb +178 -0
  41. data/lib/cli/release_tarball.rb +272 -0
  42. data/lib/cli/runner.rb +771 -0
  43. data/lib/cli/stemcell.rb +83 -0
  44. data/lib/cli/task_log_renderer.rb +40 -0
  45. data/lib/cli/templates/help_message.erb +75 -0
  46. data/lib/cli/validation.rb +42 -0
  47. data/lib/cli/version.rb +7 -0
  48. data/lib/cli/version_calc.rb +48 -0
  49. data/lib/cli/versions_index.rb +126 -0
  50. data/lib/cli/yaml_helper.rb +62 -0
  51. data/spec/assets/biff/bad_gateway_config.yml +28 -0
  52. data/spec/assets/biff/good_simple_config.yml +63 -0
  53. data/spec/assets/biff/good_simple_golden_config.yml +63 -0
  54. data/spec/assets/biff/good_simple_template.erb +69 -0
  55. data/spec/assets/biff/multiple_subnets_config.yml +40 -0
  56. data/spec/assets/biff/network_only_template.erb +34 -0
  57. data/spec/assets/biff/no_cc_config.yml +27 -0
  58. data/spec/assets/biff/no_range_config.yml +27 -0
  59. data/spec/assets/biff/no_subnet_config.yml +16 -0
  60. data/spec/assets/biff/ok_network_config.yml +30 -0
  61. data/spec/assets/biff/properties_template.erb +6 -0
  62. data/spec/assets/deployment.MF +0 -0
  63. data/spec/assets/plugins/bosh/cli/commands/echo.rb +43 -0
  64. data/spec/assets/plugins/bosh/cli/commands/ruby.rb +24 -0
  65. data/spec/assets/release/jobs/cacher.tgz +0 -0
  66. data/spec/assets/release/jobs/cacher/config/file1.conf +0 -0
  67. data/spec/assets/release/jobs/cacher/config/file2.conf +0 -0
  68. data/spec/assets/release/jobs/cacher/job.MF +6 -0
  69. data/spec/assets/release/jobs/cacher/monit +1 -0
  70. data/spec/assets/release/jobs/cleaner.tgz +0 -0
  71. data/spec/assets/release/jobs/cleaner/job.MF +4 -0
  72. data/spec/assets/release/jobs/cleaner/monit +1 -0
  73. data/spec/assets/release/jobs/sweeper.tgz +0 -0
  74. data/spec/assets/release/jobs/sweeper/config/test.conf +1 -0
  75. data/spec/assets/release/jobs/sweeper/job.MF +5 -0
  76. data/spec/assets/release/jobs/sweeper/monit +1 -0
  77. data/spec/assets/release/packages/mutator.tar.gz +0 -0
  78. data/spec/assets/release/packages/stuff.tgz +0 -0
  79. data/spec/assets/release/release.MF +17 -0
  80. data/spec/assets/release_invalid_checksum.tgz +0 -0
  81. data/spec/assets/release_invalid_jobs.tgz +0 -0
  82. data/spec/assets/release_no_name.tgz +0 -0
  83. data/spec/assets/release_no_version.tgz +0 -0
  84. data/spec/assets/stemcell/image +1 -0
  85. data/spec/assets/stemcell/stemcell.MF +6 -0
  86. data/spec/assets/stemcell_invalid_mf.tgz +0 -0
  87. data/spec/assets/stemcell_no_image.tgz +0 -0
  88. data/spec/assets/valid_release.tgz +0 -0
  89. data/spec/assets/valid_stemcell.tgz +0 -0
  90. data/spec/spec_helper.rb +25 -0
  91. data/spec/unit/base_command_spec.rb +66 -0
  92. data/spec/unit/biff_spec.rb +135 -0
  93. data/spec/unit/cache_spec.rb +36 -0
  94. data/spec/unit/cli_commands_spec.rb +481 -0
  95. data/spec/unit/config_spec.rb +139 -0
  96. data/spec/unit/core_ext_spec.rb +77 -0
  97. data/spec/unit/dependency_helper_spec.rb +52 -0
  98. data/spec/unit/deployment_manifest_compiler_spec.rb +63 -0
  99. data/spec/unit/director_spec.rb +511 -0
  100. data/spec/unit/director_task_spec.rb +48 -0
  101. data/spec/unit/event_log_renderer_spec.rb +171 -0
  102. data/spec/unit/hash_changeset_spec.rb +73 -0
  103. data/spec/unit/job_builder_spec.rb +454 -0
  104. data/spec/unit/package_builder_spec.rb +567 -0
  105. data/spec/unit/release_builder_spec.rb +65 -0
  106. data/spec/unit/release_spec.rb +66 -0
  107. data/spec/unit/release_tarball_spec.rb +33 -0
  108. data/spec/unit/runner_spec.rb +140 -0
  109. data/spec/unit/ssh_spec.rb +78 -0
  110. data/spec/unit/stemcell_spec.rb +17 -0
  111. data/spec/unit/version_calc_spec.rb +27 -0
  112. data/spec/unit/versions_index_spec.rb +132 -0
  113. metadata +338 -0
@@ -0,0 +1,65 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::ReleaseBuilder do
6
+
7
+ before(:each) do
8
+ @release_dir = Dir.mktmpdir
9
+ FileUtils.mkdir_p(File.join(@release_dir, "config"))
10
+ @release = Bosh::Cli::Release.new(@release_dir)
11
+ end
12
+
13
+ def new_builder
14
+ Bosh::Cli::ReleaseBuilder.new(@release, [], [])
15
+ end
16
+
17
+ it "uses version 1 if no previous releases have been created" do
18
+ new_builder.version.should == 1
19
+ end
20
+
21
+ it "builds a release" do
22
+ builder = new_builder
23
+ builder.build
24
+
25
+ expected_tarball_path = File.join(@release_dir,
26
+ "dev_releases", "bosh_release-1.tgz")
27
+
28
+ builder.tarball_path.should == expected_tarball_path
29
+ File.file?(expected_tarball_path).should be_true
30
+ end
31
+
32
+ it "doesn't build a new release if nothing has changed" do
33
+ builder = new_builder
34
+ builder.build
35
+ builder.build
36
+
37
+ File.file?(File.join(@release_dir, "dev_releases", "bosh_release-1.tgz")).
38
+ should be_true
39
+ File.file?(File.join(@release_dir, "dev_releases", "bosh_release-2.tgz")).
40
+ should be_false
41
+ end
42
+
43
+ it "has a list of jobs affected by building this release" do
44
+ job1 = mock(:job, :new_version? => true,
45
+ :packages => ["bar", "baz"], :name => "job1")
46
+ job2 = mock(:job, :new_version? => false,
47
+ :packages => ["foo", "baz"], :name => "job2")
48
+ job3 = mock(:job, :new_version? => false,
49
+ :packages => ["baz", "zb"], :name => "job3")
50
+ job4 = mock(:job, :new_version? => false,
51
+ :packages => ["bar", "baz"], :name => "job4")
52
+
53
+ package1 = mock(:package, :name => "foo", :new_version? => true)
54
+ package2 = mock(:package, :name => "bar", :new_version? => false)
55
+ package3 = mock(:package, :name => "baz", :new_version? => false)
56
+ package4 = mock(:package, :name => "zb", :new_version? => true)
57
+
58
+ builder = Bosh::Cli::ReleaseBuilder.new(@release,
59
+ [package1, package2,
60
+ package3, package4],
61
+ [job1, job2, job3, job4])
62
+ builder.affected_jobs.should =~ [job1, job2, job3]
63
+ end
64
+
65
+ end
@@ -0,0 +1,66 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::Release do
6
+
7
+ before :each do
8
+ @release_dir = Dir.mktmpdir
9
+ FileUtils.mkdir_p(File.join(@release_dir, "config"))
10
+ end
11
+
12
+ def new_release(dir)
13
+ Bosh::Cli::Release.new(@release_dir)
14
+ end
15
+
16
+ it "persists release attributes" do
17
+ r = new_release(@dir)
18
+
19
+ r.dev_name.should be_nil
20
+ r.final_name.should be_nil
21
+ r.min_cli_version.should be_nil
22
+ r.latest_release_filename.should be_nil
23
+
24
+ r.dev_name = "dev-release"
25
+ r.final_name = "prod-release"
26
+ r.min_cli_version = "0.5.2"
27
+ r.latest_release_filename = "foobar"
28
+ r.save_config
29
+
30
+ r2 = new_release(@release_dir)
31
+ r.dev_name.should == "dev-release"
32
+ r.final_name.should == "prod-release"
33
+ r.min_cli_version.should == "0.5.2"
34
+ r.latest_release_filename.should == "foobar"
35
+ end
36
+
37
+ it "has attributes persisted in bosh user config" do
38
+ r = new_release(@release_dir)
39
+ r.dev_name = "dev-release"
40
+ r.final_name = "prod-release"
41
+ r.min_cli_version = "0.5.2"
42
+ r.save_config
43
+
44
+ FileUtils.rm_rf(File.join(@release_dir, "config", "dev.yml"))
45
+
46
+ r = new_release(@release_dir)
47
+ r.dev_name.should be_nil
48
+ r.final_name.should == "prod-release"
49
+ r.min_cli_version.should == "0.5.2"
50
+ end
51
+
52
+ it "has attributes persisted in public release config" do
53
+ r = new_release(@release_dir)
54
+ r.dev_name = "dev-release"
55
+ r.final_name = "prod-release"
56
+ r.min_cli_version = "0.5.2"
57
+ r.save_config
58
+
59
+ FileUtils.rm_rf(File.join(@release_dir, "config", "final.yml"))
60
+
61
+ r = new_release(@release_dir)
62
+ r.dev_name.should == "dev-release"
63
+ r.final_name.should be_nil
64
+ r.min_cli_version.should be_nil
65
+ end
66
+ end
@@ -0,0 +1,33 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::ReleaseTarball do
6
+
7
+ describe "verifying a release" do
8
+ it "verifies and reports a valid release" do
9
+ tarball = Bosh::Cli::ReleaseTarball.new(spec_asset("valid_release.tgz"))
10
+ tarball.should be_valid
11
+ end
12
+
13
+ it "verifies repacked release if appropriate option is set" do
14
+ tarball = Bosh::Cli::ReleaseTarball.new(spec_asset("valid_release.tgz"))
15
+ remote_release = {
16
+ "packages" => [{ "name" => "mutator", "version" => "2.99.7" }],
17
+ "jobs" => [{ "name" => "cacher", "version" => "1" },
18
+ { "name" => "sweeper", "version" => "1" }]
19
+ }
20
+ repacked_tarball_path = tarball.repack(remote_release)
21
+
22
+ tarball.skipped.should == 2
23
+
24
+ repacked_tarball = Bosh::Cli::ReleaseTarball.new(repacked_tarball_path)
25
+ repacked_tarball.valid?.should be_false
26
+ repacked_tarball.reset_validation
27
+ repacked_tarball.valid?(:allow_sparse => true).should be_true
28
+ end
29
+ end
30
+
31
+ # TODO: add whining on potential errors
32
+
33
+ end
@@ -0,0 +1,140 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::Runner do
6
+
7
+ before(:all) do
8
+ @out = StringIO.new
9
+ Bosh::Cli::Config.output = @out
10
+ end
11
+
12
+ def test_cmd(args, namespace, action, cmd_args = [])
13
+ runner = Bosh::Cli::Runner.new(args)
14
+ runner.prepare
15
+ runner.dispatch
16
+
17
+ runner.namespace.should == namespace
18
+ runner.action.should == action
19
+ runner.args.should == cmd_args
20
+ end
21
+
22
+ it "has a set of default global options" do
23
+ runner = Bosh::Cli::Runner.new(["do", "some", "stuff"])
24
+ runner.parse_options!
25
+ runner.options[:verbose].should == nil
26
+ runner.options[:colorize].should == true
27
+ runner.options[:director_checks].should == true
28
+ runner.options[:quiet].should == nil
29
+ runner.options[:non_interactive].should == nil
30
+ end
31
+
32
+ it "allows overriding global options" do
33
+ runner = Bosh::Cli::Runner.new(["--verbose", "--no-color",
34
+ "--skip-director-checks", "--quiet",
35
+ "--non-interactive", "release",
36
+ "upload", "/path"])
37
+ runner.parse_options!
38
+ runner.options[:verbose].should == true
39
+ runner.options[:colorize].should == false
40
+ runner.options[:director_checks].should == false
41
+ runner.options[:quiet].should == true
42
+ runner.options[:non_interactive].should == true
43
+ end
44
+
45
+ it "dispatches commands to appropriate methods (nu school)" do
46
+ test_cmd(["version"], :misc, :version)
47
+ test_cmd(["status"], :misc, :status)
48
+ test_cmd(["target"], :misc, :show_target)
49
+ test_cmd(["target", "test"], :misc, :set_target, ["test"])
50
+ test_cmd(["target", "test", "alias"], :misc, :set_target, ["test", "alias"])
51
+ test_cmd(["deploy"], :deployment, :perform)
52
+ test_cmd(["deployment"], :deployment, :show_current)
53
+ test_cmd(["deployment", "test"], :deployment, :set_current, ["test"])
54
+
55
+ test_cmd(["delete", "deployment", "foo"], :deployment, :delete, ["foo"])
56
+ test_cmd(["delete", "stemcell", "a", "1"], :stemcell, :delete, ["a", "1"])
57
+ test_cmd(["delete", "release", "a"], :release, :delete, ["a"])
58
+ test_cmd(["delete", "release", "a", "--force"],
59
+ :release, :delete, ["a", "--force"])
60
+ test_cmd(["delete", "release", "a", "2.2.1", "--force"],
61
+ :release, :delete, ["a", "2.2.1", "--force"])
62
+
63
+ test_cmd(["create", "user", "admin"], :user, :create, ["admin"])
64
+ test_cmd(["create", "user", "admin", "12321"],
65
+ :user, :create, ["admin", "12321"])
66
+ test_cmd(["create", "release"], :release, :create)
67
+ test_cmd(["reset", "release"], :release, :reset)
68
+ test_cmd(["create", "package", "bla"], :package, :create, ["bla"])
69
+
70
+ test_cmd(["login", "admin", "12321"], :misc, :login, ["admin", "12321"])
71
+ test_cmd(["logout"], :misc, :logout)
72
+ test_cmd(["purge"], :misc, :purge_cache)
73
+
74
+ test_cmd(["init", "release"], :release, :init)
75
+ test_cmd(["init", "release", "/path"], :release, :init, ["/path"])
76
+
77
+ test_cmd(["upload", "release", "/path"], :release, :upload, ["/path"])
78
+ test_cmd(["upload", "release"], :release, :upload)
79
+ test_cmd(["upload", "stemcell", "/path"], :stemcell, :upload, ["/path"])
80
+
81
+ test_cmd(["generate", "package", "foo"], :package, :generate, ["foo"])
82
+ test_cmd(["generate", "job", "baz"], :job, :generate, ["baz"])
83
+
84
+ test_cmd(["verify", "release", "/path"], :release, :verify, ["/path"])
85
+ test_cmd(["verify", "stemcell", "/path"], :stemcell, :verify, ["/path"])
86
+
87
+ test_cmd(["stemcells"], :stemcell, :list)
88
+ test_cmd(["releases"], :release, :list)
89
+ test_cmd(["deployments"], :deployment, :list)
90
+
91
+ test_cmd(["tasks"], :task, :list_running)
92
+ test_cmd(["task", "500"], :task, :track, ["500"])
93
+ test_cmd(["tasks"], :task, :list_running)
94
+ test_cmd(["tasks", "recent"], :task, :list_recent)
95
+ test_cmd(["tasks", "recent", "42"], :task, :list_recent, ["42"])
96
+ end
97
+
98
+ it "cancels running task and quits when ctrl-c is issued " +
99
+ "and user agrees to quit" do
100
+ runner = Bosh::Cli::Runner.new(["any", "command"])
101
+ runner.runner = {}
102
+ runner.runner.stub(:task_running?).and_return(true)
103
+ runner.stub(:kill_current_task?).and_return(true)
104
+ runner.runner.should_receive(:cancel_current_task).once
105
+ lambda { runner.handle_ctrl_c }.should raise_error SystemExit
106
+ end
107
+
108
+ it "quits when ctrl-c is issued and there is no task running" do
109
+ runner = Bosh::Cli::Runner.new(["any", "command"])
110
+ runner.runner = {}
111
+ runner.runner.stub(:task_running?).and_return(false)
112
+ lambda { runner.handle_ctrl_c }.should raise_error SystemExit
113
+ end
114
+
115
+ it "doesn't quit when user issues ctrl-c but does not want to quit" do
116
+ runner = Bosh::Cli::Runner.new(["any", "command"])
117
+ runner.runner = {}
118
+ runner.runner.stub(:task_running?).and_return(true)
119
+ runner.stub(:kill_current_task?).and_return(false)
120
+ lambda { runner.handle_ctrl_c }.should_not raise_error SystemExit
121
+ end
122
+
123
+ it "loads custom plugins" do
124
+ plugin_path = spec_asset("plugins")
125
+ $:.unshift(plugin_path)
126
+
127
+ begin
128
+ test_cmd(["banner", "foo"], :echo, :banner, ["foo"])
129
+ test_cmd(["say", "bar"], :echo, :say_color, ["bar"])
130
+ test_cmd(["say", "baz", "--color", "red"],
131
+ :echo, :say_color, ["baz", "--color", "red"])
132
+
133
+ test_cmd(["ruby", "version"], :ruby, :ruby_version)
134
+ test_cmd(["ruby", "config", "arch"], :ruby, :ruby_config, ["arch"])
135
+ ensure
136
+ $:.shift.should == plugin_path
137
+ end
138
+ end
139
+
140
+ end
@@ -0,0 +1,78 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::Command::Base do
6
+
7
+ before :all do
8
+ @public_key = File.join(Dir.mktmpdir, "public_key")
9
+ File.open(@public_key, "w+") do |f|
10
+ f.write("PUBLIC_KEY")
11
+ end
12
+ end
13
+
14
+ describe Bosh::Cli::Command::Ssh do
15
+ it "should get the public key" do
16
+ ssh = Bosh::Cli::Command::Ssh.new
17
+ public_key = ssh.get_public_key("public_key" => @public_key)
18
+ public_key.should == "PUBLIC_KEY"
19
+ end
20
+
21
+ it "should get the public key from users home directory " +
22
+ "or raise exception" do
23
+ ssh = Bosh::Cli::Command::Ssh.new
24
+ public_key = nil
25
+ begin
26
+ public_key = ssh.get_public_key({})
27
+ rescue Bosh::Cli::CliExit
28
+ public_key = "SOMETHING"
29
+ end
30
+ public_key.should_not be_nil
31
+ end
32
+
33
+ it "should contact director to setup ssh on the job" do
34
+ mock_director = mock(Object)
35
+ mock_director.stub(:setup_ssh).and_return([{ "status" => "success",
36
+ "ip" => "127.0.0.1" }])
37
+ mock_director.stub(:cleanup_ssh)
38
+ Bosh::Cli::Director.should_receive(:new).and_return(mock_director)
39
+ ssh = Bosh::Cli::Command::Ssh.new
40
+ ssh.stub(:prepare_deployment_manifest).and_return("test")
41
+ ssh.stub(:cleanup_ssh)
42
+ ssh.setup_ssh("dea", 0, "temp_pass",
43
+ { "public_key" => @public_key }) do |results, user|
44
+ results.each do |result|
45
+ result["status"].should == "success"
46
+ result["ip"].should == "127.0.0.1"
47
+ end
48
+ end
49
+ end
50
+
51
+ it "should try to setup interactive shell when a job index is given" do
52
+ ssh = Bosh::Cli::Command::Ssh.new
53
+ @interactive_shell = false
54
+ @execute_command = false
55
+ ssh.stub(:setup_interactive_shell) { @interactive_shell = true }
56
+ ssh.stub(:execute_command) { @execute_command = true }
57
+ ssh.shell("dea", "0")
58
+ @interactive_shell.should == true && @execute_command.should == false
59
+ end
60
+
61
+ it "should fail to setup interactive shell when a job index is not given" do
62
+ ssh = Bosh::Cli::Command::Ssh.new
63
+ lambda {
64
+ ssh.shell("dea")
65
+ }.should raise_error(Bosh::Cli::CliExit, "Please specify a job index")
66
+ end
67
+
68
+ it "should try to execute given command remotely" do
69
+ ssh = Bosh::Cli::Command::Ssh.new
70
+ @interactive_shell = false
71
+ @execute_command = false
72
+ ssh.stub(:setup_interactive_shell) { @interactive_shell = true }
73
+ ssh.stub(:execute_command) { @execute_command = true }
74
+ ssh.shell("dea", "ls -l")
75
+ @interactive_shell.should == false && @execute_command.should == true
76
+ end
77
+ end
78
+ end
@@ -0,0 +1,17 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::Stemcell do
6
+
7
+ describe "verifying a stemcell" do
8
+ it "verifies and reports a valid stemcell" do
9
+ sc = Bosh::Cli::Stemcell.new(spec_asset("valid_stemcell.tgz"),
10
+ Bosh::Cli::Cache.new(Dir.mktmpdir))
11
+ sc.should be_valid
12
+ end
13
+ end
14
+
15
+ # TODO: add whining on potential errors
16
+
17
+ end
@@ -0,0 +1,27 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::VersionCalc do
6
+
7
+ before :each do
8
+ @obj = Object.new.extend(Bosh::Cli::VersionCalc)
9
+ end
10
+
11
+ it "can compare versions" do
12
+ @obj.version_cmp("1.2", "1.2").should == 0
13
+ @obj.version_cmp("1.3", "1.2").should == 1
14
+ @obj.version_cmp("0.1.7", "0.9.2").should == -1
15
+ @obj.version_cmp("0.1.7.5", "0.1.7").should == 1
16
+ @obj.version_cmp("0.1.7.4.9.9", "0.1.7.5").should == -1
17
+
18
+ @obj.version_cmp(10, 11).should == -1
19
+ @obj.version_cmp(43, 42).should == 1
20
+ @obj.version_cmp(7, 7).should == 0
21
+
22
+ @obj.version_cmp("10.9-dev", "10.10-dev").should == -1
23
+ @obj.version_cmp("0.2.3", "0.2.3.0.8").should == -1
24
+ @obj.version_cmp("0.2.3-dev", "0.2.3.0.3-dev").should == -1
25
+ end
26
+
27
+ end
@@ -0,0 +1,132 @@
1
+ # Copyright (c) 2009-2012 VMware, Inc.
2
+
3
+ require "spec_helper"
4
+
5
+ describe Bosh::Cli::VersionsIndex do
6
+
7
+ before :each do
8
+ @dir = Dir.mktmpdir
9
+ @index_file = File.join(@dir, "index.yml")
10
+ @index = Bosh::Cli::VersionsIndex.new(@dir)
11
+ end
12
+
13
+ after :each do
14
+ FileUtils.rm_rf(@dir)
15
+ end
16
+
17
+ it "only creates directory structure on writes to index" do
18
+ File.exists?(@index_file).should be_false
19
+ @index.version_exists?(1).should be_false
20
+ @index["deadbeef"].should be_nil
21
+ @index.latest_version.should be_nil
22
+ File.exists?(@index_file).should be_false
23
+
24
+ @index.add_version("deadcafe", { "version" => 2 }, "payload2")
25
+ File.exists?(@index_file).should be_true
26
+ end
27
+
28
+ it "chokes on malformed index file" do
29
+ File.open(@index_file, "w") { |f| f.write("deadbeef") }
30
+
31
+ lambda {
32
+ @index = Bosh::Cli::VersionsIndex.new(@dir)
33
+ }.should raise_error(Bosh::Cli::InvalidIndex,
34
+ "Invalid versions index data type, " +
35
+ "String given, Hash expected")
36
+ end
37
+
38
+ it "doesn't choke on empty index file" do
39
+ File.open(@index_file, "w") { |f| f.write("") }
40
+ @index = Bosh::Cli::VersionsIndex.new(@dir)
41
+ @index.latest_version.should be_nil
42
+ end
43
+
44
+ it "can be used to add versioned payloads to index" do
45
+ item1 = { "a" => 1, "b" => 2, "version" => 1 }
46
+ item2 = { "a" => 3, "b" => 4, "version" => 2 }
47
+ @index.add_version("deadbeef", item1, "payload1")
48
+ @index.add_version("deadcafe", item2, "payload2")
49
+
50
+ @index.latest_version.should == 2
51
+ @index["deadbeef"].should ==
52
+ item1.merge("sha1" => Digest::SHA1.hexdigest("payload1"))
53
+ @index["deadcafe"].should ==
54
+ item2.merge("sha1" => Digest::SHA1.hexdigest("payload2"))
55
+ @index.version_exists?(1).should be_true
56
+ @index.version_exists?(2).should be_true
57
+ @index.version_exists?(3).should be_false
58
+
59
+ @index.filename(1).should == File.join(@dir, "1.tgz")
60
+ @index.filename(2).should == File.join(@dir, "2.tgz")
61
+ end
62
+
63
+ it "you shall not pass without version" do
64
+ item_noversion = { "a" => 1, "b" => 2 }
65
+ lambda {
66
+ @index.add_version("deadbeef", item_noversion, "payload1")
67
+ }.should raise_error(Bosh::Cli::InvalidIndex,
68
+ "Cannot save index entry without knowing its version")
69
+ end
70
+
71
+ it "latest version only gets updated if it's greater than current latest" do
72
+ item1 = { "a" => 1, "b" => 2, "version" => 1 }
73
+ item2 = { "a" => 3, "b" => 4, "version" => 2 }
74
+ item3 = { "a" => 3, "b" => 4, "version" => 3 }
75
+
76
+ @index.add_version("deadbeef", item1, "payload1")
77
+ @index.add_version("deadcafe", item2, "payload2")
78
+ @index.latest_version.should == 2
79
+ @index.add_version("addedface", item3, "payload2")
80
+ @index.latest_version.should == 3
81
+ @index.add_version("facedbeef", item1.merge("version" => "1.5"), "payload3")
82
+ @index.latest_version.should == 3
83
+ end
84
+
85
+ it "supports dev versions and proper version comparison when updating latest version" do
86
+ item1 = { "a" => 1, "b" => 2, "version" => "1.9-dev" }
87
+ item2 = { "a" => 3, "b" => 4, "version" => "1.8-dev" }
88
+ item3 = { "a" => 3, "b" => 4, "version" => "1.10-dev" }
89
+
90
+ @index.add_version("deadbeef", item1, "payload1")
91
+ @index.add_version("deadcafe", item2, "payload2")
92
+ @index.latest_version.should == "1.9-dev"
93
+ @index.add_version("facedead", item3, "payload2")
94
+ @index.latest_version.should == "1.10-dev"
95
+ @index.add_version("badbed", item1.merge("version" => "2.15-dev"), "payload3")
96
+ @index.latest_version.should == "2.15-dev"
97
+ end
98
+
99
+ it "doesn't allow duplicate fingerprints or versions" do
100
+ item1 = { "a" => 1, "b" => 2, "version" => "1.9-dev" }
101
+ item2 = { "a" => 3, "b" => 4, "version" => "1.8-dev" }
102
+
103
+ @index.add_version("deadbeef", item1, "payload1")
104
+
105
+ lambda {
106
+ @index.add_version("deadcafe", item1, "payload3")
107
+ }.should raise_error("Trying to add duplicate version `1.9-dev' " +
108
+ "into index `#{File.join(@dir, "index.yml")}'")
109
+ end
110
+
111
+ it "supports finding entries by checksum" do
112
+ item1 = { "a" => 1, "b" => 2, "version" => 1 }
113
+ item2 = { "a" => 3, "b" => 4, "version" => 2 }
114
+
115
+ @index.add_version("deadbeef", item1, "payload1")
116
+ @index.add_version("deadcafe", item2, "payload2")
117
+
118
+ checksum1 = Digest::SHA1.hexdigest("payload1")
119
+ checksum2 = Digest::SHA1.hexdigest("payload2")
120
+
121
+ @index.find_by_checksum(checksum1).should == item1.merge("sha1" => checksum1)
122
+ @index.find_by_checksum(checksum2).should == item2.merge("sha1" => checksum2)
123
+ end
124
+
125
+ it "supports name prefix" do
126
+ item = { "a" => 1, "b" => 2, "version" => 1 }
127
+ @index = Bosh::Cli::VersionsIndex.new(@dir, "foobar")
128
+ @index.add_version("deadbeef", item, "payload1")
129
+ @index.filename(1).should == File.join(@dir, "foobar-1.tgz")
130
+ end
131
+
132
+ end