ssc 0.2.0 → 0.3.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.
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