ssc 0.2.0 → 0.3.0

Sign up to get free protection for your applications and to get access to all the features.
data/ssc.gemspec ADDED
@@ -0,0 +1,82 @@
1
+ # Generated by jeweler
2
+ # DO NOT EDIT THIS FILE DIRECTLY
3
+ # Instead, edit Jeweler::Tasks in Rakefile, and run 'rake gemspec'
4
+ # -*- encoding: utf-8 -*-
5
+
6
+ Gem::Specification.new do |s|
7
+ s.name = %q{ssc}
8
+ s.version = "0.3.0"
9
+
10
+ s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
11
+ s.authors = ["Ratan Sebastian"]
12
+ s.date = %q{2011-08-15}
13
+ s.default_executable = %q{ssc}
14
+ s.description = %q{Command-line client for Suse Studio}
15
+ s.email = %q{rjsvaljean@gmail.com}
16
+ s.executables = ["ssc"]
17
+ s.extra_rdoc_files = [
18
+ "README.rdoc"
19
+ ]
20
+ s.files = [
21
+ "Gemfile",
22
+ "Gemfile.lock",
23
+ "README.rdoc",
24
+ "Rakefile",
25
+ "VERSION",
26
+ "bin/ssc",
27
+ "lib/directory_manager.rb",
28
+ "lib/handlers/all.rb",
29
+ "lib/handlers/appliance.rb",
30
+ "lib/handlers/build.rb",
31
+ "lib/handlers/file.rb",
32
+ "lib/handlers/helper.rb",
33
+ "lib/handlers/package.rb",
34
+ "lib/handlers/repository.rb",
35
+ "lib/handlers/template.rb",
36
+ "lib/ssc.rb",
37
+ "ssc.gemspec",
38
+ "test/helper.rb",
39
+ "test/integration/test_appliance.rb",
40
+ "test/integration/test_file.rb",
41
+ "test/integration/test_package.rb",
42
+ "test/integration/test_repository.rb",
43
+ "test/unit/test_directory_manager.rb"
44
+ ]
45
+ s.homepage = %q{http://github.com/rjsvaljean/ssc}
46
+ s.licenses = ["MIT"]
47
+ s.require_paths = ["lib"]
48
+ s.rubygems_version = %q{1.3.7}
49
+ s.summary = %q{Command-line client for Suse Studio}
50
+
51
+ if s.respond_to? :specification_version then
52
+ current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
53
+ s.specification_version = 3
54
+
55
+ if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
56
+ s.add_runtime_dependency(%q<studio_api>, [">= 3.1.2"])
57
+ s.add_runtime_dependency(%q<thor>, [">= 0.14.6"])
58
+ s.add_development_dependency(%q<shoulda>, [">= 0"])
59
+ s.add_development_dependency(%q<mocha>, [">= 0"])
60
+ s.add_development_dependency(%q<bundler>, ["~> 1.0.0"])
61
+ s.add_development_dependency(%q<jeweler>, ["~> 1.6.0"])
62
+ s.add_development_dependency(%q<rcov>, [">= 0"])
63
+ else
64
+ s.add_dependency(%q<studio_api>, [">= 3.1.2"])
65
+ s.add_dependency(%q<thor>, [">= 0.14.6"])
66
+ s.add_dependency(%q<shoulda>, [">= 0"])
67
+ s.add_dependency(%q<mocha>, [">= 0"])
68
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
69
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
70
+ s.add_dependency(%q<rcov>, [">= 0"])
71
+ end
72
+ else
73
+ s.add_dependency(%q<studio_api>, [">= 3.1.2"])
74
+ s.add_dependency(%q<thor>, [">= 0.14.6"])
75
+ s.add_dependency(%q<shoulda>, [">= 0"])
76
+ s.add_dependency(%q<mocha>, [">= 0"])
77
+ s.add_dependency(%q<bundler>, ["~> 1.0.0"])
78
+ s.add_dependency(%q<jeweler>, ["~> 1.6.0"])
79
+ s.add_dependency(%q<rcov>, [">= 0"])
80
+ end
81
+ end
82
+
data/test/helper.rb CHANGED
@@ -10,10 +10,21 @@ end
10
10
  require 'test/unit'
11
11
  require 'shoulda'
12
12
  require 'mocha'
13
+ require 'yaml'
13
14
 
14
15
  $LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
15
16
  $LOAD_PATH.unshift(File.dirname(__FILE__))
16
- require 'ssc'
17
17
 
18
+ require 'ssc'
18
19
  class Test::Unit::TestCase
20
+ # To prevent printing of command line output
21
+ class Thor::Shell::Basic
22
+ def say(*args)
23
+ args[0]
24
+ end
25
+
26
+ def print_table(*args)
27
+ args[0]
28
+ end
29
+ end
19
30
  end
@@ -0,0 +1,82 @@
1
+ require 'helper'
2
+
3
+ class TestAppliance < Test::Unit::TestCase
4
+ context "appliance" do
5
+ setup do
6
+ @client= SSC::Client.new
7
+ @auth_params= {:username => 'user', :password => 'pass'}
8
+ @default_mock_appliance= StudioApi::Appliance.new(:id => 5678, :name => 'test_appliance', :description => 'test description')
9
+ end
10
+ context "create" do
11
+
12
+ setup do
13
+ StudioApi::Appliance.expects(:clone).with(1234, has_entry(:name=>'test_appliance')).returns(@default_mock_appliance)
14
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
15
+ end
16
+
17
+ should "create an appliance directory" do
18
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
19
+ assert Dir.exists?('./test_appliance')
20
+ end
21
+
22
+ should "have the software, repository and file_list files" do
23
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
24
+ assert File.exists?("./test_appliance/software")
25
+ assert File.exists?("./test_appliance/repositories")
26
+ assert File.exists?("./test_appliance/files/.file_list")
27
+ end
28
+ end
29
+
30
+ context "list" do
31
+ setup do
32
+ StudioApi::Appliance.expects(:find).with(:all).returns([@default_mock_appliance])
33
+ end
34
+ should "return a list of all user's appliances" do
35
+ @client.invoke('s_s_c:handler:appliance:list', [], @auth_params)
36
+ end
37
+ end
38
+
39
+ context "info" do
40
+ setup do
41
+ appliance= @default_mock_appliance.clone
42
+ parent_mock= @default_mock_appliance.clone
43
+ builds_mock= []
44
+ appliance.expects(:parent).twice.returns(parent_mock)
45
+ appliance.expects(:builds).returns(builds_mock)
46
+ StudioApi::Appliance.expects(:find).with(5678).returns(appliance)
47
+ end
48
+ should "display information on a given appliance" do
49
+ @client.invoke('s_s_c:handler:appliance:info', [], @auth_params.merge({:appliance_id => 5678}))
50
+ end
51
+ end
52
+
53
+ context "destroy" do
54
+ setup do
55
+ appliance= @default_mock_appliance.clone
56
+ appliance.expects(:destroy).returns(stub(:code_type => Net::HTTPOK))
57
+ StudioApi::Appliance.expects(:find).with(5678).returns(appliance)
58
+ end
59
+
60
+ should "destroy the appliance" do
61
+ @client.invoke('s_s_c:handler:appliance:destroy', [], @auth_params.merge({:appliance_id => 5678}))
62
+ end
63
+ end
64
+
65
+ context "status" do
66
+ setup do
67
+ appliance= @default_mock_appliance.clone
68
+ status= mock(); status.expects(:state).returns('ok')
69
+ appliance.expects(:status).returns(status)
70
+ StudioApi::Appliance.expects(:find).with(5678).returns(appliance)
71
+ end
72
+
73
+ should "give the status of the appliance" do
74
+ @client.invoke('s_s_c:handler:appliance:status', [], @auth_params.merge({:appliance_id => 5678}))
75
+ end
76
+ end
77
+ end
78
+
79
+ def teardown
80
+ FileUtils.rmdir('test_appliance')
81
+ end
82
+ end
@@ -0,0 +1,86 @@
1
+ require 'helper'
2
+
3
+ class TestOverlayFile < Test::Unit::TestCase
4
+ context "file" do
5
+ setup do
6
+ @client= SSC::Client.new
7
+ @auth_params= {:username => 'user', :password => 'pass'}
8
+ @appliance_params= @auth_params.merge(:appliance_id => 5678)
9
+ @default_mock_appliance= StudioApi::Appliance.new(:id => 5678, :name => 'test_appliance', :description => 'test description')
10
+ StudioApi::Appliance.stubs(:clone).returns(@default_mock_appliance)
11
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
12
+ @default_mock_package= StudioApi::Package.new('test_package', :version => '1', :repository_id => 9876)
13
+ StudioApi::Appliance.stubs(:find).with(5678).returns(@default_mock_appliance)
14
+ end
15
+ context "add" do
16
+ setup do
17
+ @test_file_path= File.join(ENV["HOME"], '.test_file.config')
18
+ FileUtils.touch(@test_file_path)
19
+ end
20
+ context "when in the appliance directory" do
21
+ setup do
22
+ Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
23
+ end
24
+ context "when the remote flag is set" do
25
+ should "upload file and create a new file locally" do
26
+ StudioApi::File.expects(:upload).returns(stub(:id => 1))
27
+ mock_file_list= mock()
28
+ SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
29
+ mock_file_list.expects(:initiate_file).with(@test_file_path, anything)
30
+ @client.invoke('s_s_c:handler:overlay_file:add', [@test_file_path], {:remote => true, :appliance_id => 5678})
31
+ end
32
+ end
33
+ context "when the remote flag is not set" do
34
+ should "just add the file to the file_list in the add section" do
35
+ mock_file_list= mock()
36
+ SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
37
+ mock_file_list.expects(:initiate_file).with(@test_file_path, anything)
38
+ @client.invoke('s_s_c:handler:overlay_file:add', [@test_file_path], {:appliance_id => 5678})
39
+ end
40
+ end
41
+ end
42
+ context "when not in the appliance directory" do
43
+ setup do
44
+ Dir.chdir('..') if File.exist?('./.sscrc')
45
+ SSC::DirectoryManager::ApplianceDirectory.any_instance.stubs(:valid).returns(false)
46
+ end
47
+ context "when the remote flag is set" do
48
+ should "just upload the file" do
49
+ StudioApi::File.expects(:upload).returns(stub(:id => 1))
50
+ @client.invoke('s_s_c:handler:overlay_file:add', [@test_file_path], {:appliance_id => 5678, :remote => true})
51
+ end
52
+ end
53
+ end
54
+ end
55
+
56
+ context "remove" do
57
+ context "when the remote flag is set" do
58
+ should "destroy the file remotely" do
59
+ SSC::DirectoryManager::FileListFile.any_instance.stubs(:is_uploaded?).returns(:id)
60
+ mock_file_object= mock()
61
+ mock_file_object.expects(:destroy)
62
+ StudioApi::File.expects(:find).with(:id).returns(mock_file_object)
63
+ @client.invoke('s_s_c:handler:overlay_file:remove', ["test_file"], {:remote => true})
64
+ end
65
+ end
66
+
67
+ context "when the remote flag is not set" do
68
+ should "add the filename to the remove list in file_list" do
69
+ mock_file_list= mock()
70
+ mock_file_list.stubs(:is_uploaded?).returns(:id)
71
+ mock_file_list.expects(:push).with('remove', has_key('test_file'))
72
+ mock_file_list.expects(:save)
73
+ SSC::DirectoryManager::FileListFile.stubs(:new).returns(mock_file_list)
74
+ @client.invoke('s_s_c:handler:overlay_file:remove', ["test_file"], {})
75
+ end
76
+ end
77
+ end
78
+ end
79
+
80
+
81
+ def teardown
82
+ Dir.chdir("..") unless Dir.exists?('test_appliance')
83
+ FileUtils.rm_r('test_appliance')
84
+ FileUtils.rm @test_file_path if @test_file_path && File.exists?(@test_file_path)
85
+ end
86
+ end
@@ -0,0 +1,75 @@
1
+ require 'helper'
2
+
3
+ class TestPackage < Test::Unit::TestCase
4
+
5
+ context "package" do
6
+ setup do
7
+ @client= SSC::Client.new
8
+ @auth_params= {:username => 'user', :password => 'pass'}
9
+ @appliance_params= @auth_params.merge(:appliance_id => 5678)
10
+ @default_mock_appliance= StudioApi::Appliance.new(:id => 5678, :name => 'test_appliance', :description => 'test description')
11
+ StudioApi::Appliance.stubs(:clone).returns(@default_mock_appliance)
12
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
13
+ @default_mock_package= StudioApi::Package.new('test_package', :version => '1', :repository_id => 9876)
14
+ StudioApi::Appliance.stubs(:find).with(5678).returns(@default_mock_appliance)
15
+ Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
16
+ end
17
+
18
+ context "search" do
19
+ setup do
20
+ @default_mock_appliance.expects(:search_software).returns([@default_mock_package])
21
+ end
22
+ should "search all repos" do
23
+ @client.invoke('s_s_c:handler:package:search', ['search_string'], @appliance_params.merge(:all_repos => false))
24
+ end
25
+ end
26
+
27
+ context "list" do
28
+ ["selected", "installed"].each do |type|
29
+ context type do
30
+ setup do
31
+ @default_mock_appliance.expects("#{type}_software".to_sym).returns([@default_mock_package])
32
+ end
33
+ should "list all #{type} packages and patterns in the appliance" do
34
+ @client.invoke('s_s_c:handler:package:list', [type], @appliance_params)
35
+ end
36
+ end
37
+ end
38
+ end
39
+
40
+ ["add", "remove", "ban", "unban"].each do |action|
41
+ context action do
42
+ context "when the remote flag is on" do
43
+ should "make the '#{ action }' on studio" do
44
+ @default_mock_appliance.expects("#{action}_package".to_sym).with('test_package').returns({'state' => 'fixed'})
45
+ @client.invoke("s_s_c:handler:package:#{action}", ['test_package'], @appliance_params.merge(:remote => true))
46
+ end
47
+ end
48
+ context "when the remote flag is off" do
49
+ context "when in the appliance directory" do
50
+ should "make the '#{action}' in the package file" do
51
+ @client.invoke("s_s_c:handler:package:#{action}", ['test_package'], @appliance_params.merge(:remote =>false))
52
+ file= File.join(Dir.pwd, 'software')
53
+ assert YAML::load(File.read(file))[action].include?('test_package')
54
+ end
55
+ end
56
+ context "when outside of the appliance directory" do
57
+ setup do
58
+ Dir.chdir('..')
59
+ end
60
+ should "raise and error" do
61
+ assert_raise(Errno::ENOENT) do
62
+ @client.invoke("s_s_c:handler:package:#{action}", ['test_package'], @appliance_params.merge(:remote =>false))
63
+ end
64
+ end
65
+ end
66
+ end
67
+ end
68
+ end
69
+ end
70
+
71
+ def teardown
72
+ Dir.chdir("..") unless Dir.exists?('test_appliance')
73
+ FileUtils.rm_r('test_appliance')
74
+ end
75
+ end
@@ -0,0 +1,78 @@
1
+ require 'helper'
2
+
3
+ class TestRepository < Test::Unit::TestCase
4
+
5
+ context "repository" do
6
+ setup do
7
+ @client= SSC::Client.new
8
+ @auth_params= {:username => 'user', :password => 'pass'}
9
+ @appliance_params= @auth_params.merge(:appliance_id => 5678)
10
+ @default_mock_appliance= StudioApi::Appliance.new(:id => 5678, :name => 'test_appliance', :description => 'test description')
11
+ StudioApi::Appliance.stubs(:find).with(5678).returns(@default_mock_appliance)
12
+ StudioApi::Appliance.stubs(:clone).returns(@default_mock_appliance)
13
+ @client.invoke('s_s_c:handler:appliance:create', ['test_appliance'], {:source_id => 1234}.merge(@auth_params))
14
+ Dir.chdir('test_appliance') if Dir.exists?('test_appliance')
15
+ @default_mock_repo= StudioApi::Repository.new(:id => 3070,
16
+ :base_url => 'http://ftp.suse.de/repo/path',
17
+ :base_system => '11.3',
18
+ :name => 'test_repo',
19
+ :type => 'rpm-md')
20
+ end
21
+
22
+ context "search" do
23
+ setup do
24
+ @default_mock_repo.stubs(:matches).returns(stub(:software_name => ''))
25
+ StudioApi::Repository.expects(:find).with(:all, has_entry(:params, {:filter => 'search_string'})).returns([@default_mock_repo])
26
+ end
27
+ should "search all repos" do
28
+ @client.invoke('s_s_c:handler:repository:search', ['search_string'], @auth_params)
29
+ end
30
+ end
31
+
32
+ context "list" do
33
+ context "when remote option is on" do
34
+ setup do
35
+ @default_mock_appliance.expects(:repositories).returns([@default_mock_repo])
36
+ end
37
+ should "list all repositories in the appliance" do
38
+ @client.invoke('s_s_c:handler:repository:list', [], @appliance_params)
39
+ end
40
+ end
41
+ end
42
+
43
+ ["add", "remove"].each do |action|
44
+ context action do
45
+ context "when the remote flag is on" do
46
+ should "make the '#{ action }' on studio" do
47
+ @default_mock_appliance.expects("#{action}_repository".to_sym).with([ 3070 ]).returns(stub(:collect=> [""]))
48
+ @client.invoke("s_s_c:handler:repository:#{action}", [3070], @appliance_params.merge(:remote => true))
49
+ end
50
+ end
51
+ context "when the remote flag is off" do
52
+ context "when in the appliance directory" do
53
+ should "make the '#{action}' in the repository file" do
54
+ @client.invoke("s_s_c:handler:repository:#{action}", ['test_repository'], @appliance_params.merge(:remote =>false))
55
+ file= File.join(Dir.pwd, 'repositories')
56
+ assert YAML::load(File.read(file))[action].include?('test_repository')
57
+ end
58
+ end
59
+ context "when outside of the appliance directory" do
60
+ setup do
61
+ Dir.chdir('..')
62
+ end
63
+ should "raise and error" do
64
+ assert_raise(Errno::ENOENT) do
65
+ @client.invoke("s_s_c:handler:repository:#{action}", ['test_repository'], @appliance_params.merge(:remote =>false))
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end
71
+ end
72
+ end
73
+
74
+ def teardown
75
+ Dir.chdir("..") unless Dir.exists?('test_appliance')
76
+ FileUtils.rm_r('test_appliance')
77
+ end
78
+ end
@@ -0,0 +1,100 @@
1
+ require 'helper'
2
+
3
+ class TestDirectoryManager < Test::Unit::TestCase
4
+ include SSC::DirectoryManager
5
+
6
+ def setup
7
+ File.open(File.join(Dir.pwd, 'test_local_storage_file'), 'w') do |f|
8
+ @data = {"list" => [{"sub" => {1 => "one", 2 => "two"}}, 2, 3, 4],
9
+ "add" => [{"sub" => {1 => "one", 2 => "two"}}, 2, 3, 4],
10
+ "remove" => [{"sub" => {1 => "one", 2 => "two"}}, 2, 3, 4]}
11
+ f.write(@data.to_yaml)
12
+ end
13
+ end
14
+
15
+ context "when file is available" do
16
+ setup do
17
+ @file= LocalStorageFile.new('test_local_storage_file')
18
+ @location= File.join(Dir.pwd, 'test_local_storage_file')
19
+ end
20
+
21
+ should "initialize with the correct location" do
22
+ assert_equal @location, @file.instance_variable_get('@location')
23
+ end
24
+
25
+ context "and when the path is provided" do
26
+ should "initialize with the correct location" do
27
+ @file= LocalStorageFile.new('test_local_storage_file', Dir.pwd)
28
+ assert_equal @location, @file.instance_variable_get('@location')
29
+ end
30
+ end
31
+
32
+ context "#valid?" do
33
+ should "be true" do
34
+ assert @file.valid?
35
+ end
36
+ end
37
+
38
+ context "#pop" do
39
+ should "return the latest entry in a given section" do
40
+ assert_equal 4, @file.pop('add')
41
+ assert !@file.instance_variable_get('@parsed_file')["add"].include?(4)
42
+ end
43
+ end
44
+
45
+ context "#push" do
46
+ context "when section is already populated" do
47
+ should "push the item onto the give section's list" do
48
+ @file.push("add", 4)
49
+ assert @file.instance_variable_get('@parsed_file')["add"].include?(4)
50
+ end
51
+ end
52
+
53
+ context "when the section has not been initialized" do
54
+ should "create and add item to the section" do
55
+ @file.push("empty_section", 1)
56
+ assert @file.instance_variable_get('@parsed_file')["empty_section"] == [1]
57
+ end
58
+ end
59
+ end
60
+
61
+ context "#read" do
62
+ should "return the parsed contents of the file if the file is available" do
63
+ assert @file.read.is_a?(Hash)
64
+ assert @file.read == @data
65
+ end
66
+
67
+ should "raise a file not found error if the file is unavilable" do
68
+ assert_raise(Errno::ENOENT) do
69
+ @file.instance_variable_set('@location', '/unknown/path/')
70
+ @file.read
71
+ end
72
+ end
73
+ end
74
+
75
+ context "#save" do
76
+ should "write the modifiied data to the file" do
77
+ @file.push('empty_section', 'random_data')
78
+ @file.save
79
+ assert @file.read.keys.include?('empty_section')
80
+ end
81
+ end
82
+
83
+ context "#empty_list?" do
84
+ should "return false if the 'list' section is non-empty" do
85
+ assert !@file.empty_list?
86
+ end
87
+
88
+ should "return true if the 'list' section is empty" do
89
+ [[], {}, nil].each do |item|
90
+ @file.instance_variable_set('@parsed_file', {"list" => item})
91
+ assert @file.empty_list?
92
+ end
93
+ end
94
+ end
95
+ end
96
+
97
+ def teardown
98
+ FileUtils.rm('./test_local_storage_file')
99
+ end
100
+ end