ssc 0.1 → 0.2.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/Gemfile +14 -0
- data/Gemfile.lock +39 -0
- data/README.rdoc +22 -0
- data/Rakefile +53 -0
- data/VERSION +1 -0
- data/bin/ssc +4 -231
- data/lib/directory_manager.rb +194 -0
- data/lib/handlers/all.rb +33 -0
- data/lib/handlers/appliance.rb +74 -0
- data/lib/handlers/file.rb +102 -0
- data/lib/handlers/helper.rb +79 -0
- data/lib/handlers/package.rb +153 -0
- data/lib/handlers/repository.rb +109 -0
- data/lib/handlers/template.rb +25 -0
- data/lib/ssc.rb +18 -0
- data/test/handlers/test_appliance.rb +20 -0
- data/test/handlers/test_helper.rb +45 -0
- data/test/handlers/test_repository.rb +20 -0
- data/test/handlers/test_template.rb +27 -0
- data/test/helper.rb +19 -0
- data/test/test_argument_parser.rb +55 -0
- data/test/test_directory_manager.rb +40 -0
- data/test/test_ssc.rb +39 -0
- metadata +147 -31
- data/README +0 -1
- data/lib/appliancehandler.rb +0 -69
- data/lib/buildhandler.rb +0 -125
- data/lib/checkouthandler.rb +0 -322
- data/lib/commandhandler.rb +0 -38
- data/lib/request.rb +0 -29
@@ -0,0 +1,102 @@
|
|
1
|
+
require 'tempfile'
|
2
|
+
|
3
|
+
module SSC
|
4
|
+
module Handler
|
5
|
+
class OverlayFile < Base
|
6
|
+
|
7
|
+
|
8
|
+
no_tasks do
|
9
|
+
cattr_reader :local_source
|
10
|
+
@@local_source= 'files/'
|
11
|
+
end
|
12
|
+
|
13
|
+
# must be run in appliance directory
|
14
|
+
# takes the following argument:
|
15
|
+
# file_path => (relative positions("." and "..") allowed and ~ for home directory allowed)
|
16
|
+
# takes the following options:
|
17
|
+
# --path="/path/to/file_directory/" => optional (by default it is the path of the file on the local system)
|
18
|
+
# --name="file_name" => optional (by default it is the name of the file on the local system)
|
19
|
+
# --permissions="0766" => optional (default: 0755)
|
20
|
+
# --owner="user" => optional (default: root)
|
21
|
+
desc 'file create PATH', 'create a new overlay file'
|
22
|
+
require_appliance_id
|
23
|
+
allow_remote_option
|
24
|
+
method_option :path, :type => :string, :default => ''
|
25
|
+
method_option :name, :type => :string, :default => ''
|
26
|
+
method_option :permissions, :type => :string, :default => '0755'
|
27
|
+
method_option :owner, :type => :string, :default => 'root'
|
28
|
+
def create(path)
|
29
|
+
absolute_path= File.expand_path(path)
|
30
|
+
optional_file_params= {:permissions => options.permissions,
|
31
|
+
:owner => options.owner}
|
32
|
+
file_dir, file_name= File.split(absolute_path)
|
33
|
+
file_dir = options.path == '' ? file_dir : options.path
|
34
|
+
file_name = options.name == '' ? file_name : options.name
|
35
|
+
id= nil
|
36
|
+
if options.remote?
|
37
|
+
require_appliance do |appliance|
|
38
|
+
file_params= ({:path => file_dir, :filename => file_name})
|
39
|
+
file_params.merge!(optional_file_params)
|
40
|
+
File.open(absolute_path) do |file|
|
41
|
+
file= StudioApi::File.upload(file, appliance.id, file_params)
|
42
|
+
id= file.id.to_i
|
43
|
+
end
|
44
|
+
say "Overlay file saved. Id: #{id}"
|
45
|
+
end
|
46
|
+
end
|
47
|
+
local_copy= initiate_file(file_dir, file_name, id)
|
48
|
+
say "Created #{local_copy}"
|
49
|
+
end
|
50
|
+
|
51
|
+
desc 'file show FILE_NAME', 'show the contents of the file'
|
52
|
+
require_appliance_id
|
53
|
+
allow_remote_option
|
54
|
+
def show(file_name)
|
55
|
+
if options.remote?
|
56
|
+
id= find_file_id(file_name)
|
57
|
+
response= StudioApi::File.find(id)
|
58
|
+
say response.content
|
59
|
+
else
|
60
|
+
say show_file(file_name)
|
61
|
+
end
|
62
|
+
end
|
63
|
+
|
64
|
+
desc 'file diff FILE_NAME', 'show the diff of the remote file and the local one'
|
65
|
+
require_appliance_id
|
66
|
+
def diff(file_name)
|
67
|
+
begin
|
68
|
+
id= find_file_id(file_name)
|
69
|
+
file_content= StudioApi::File.find(id).content
|
70
|
+
rescue
|
71
|
+
say "unable to connect or not in appliance directory", :red
|
72
|
+
end
|
73
|
+
|
74
|
+
begin
|
75
|
+
tempfile=Tempfile.new('ssc_file')
|
76
|
+
tempfile.write(file_content)
|
77
|
+
say find_diff(tempfile.path, full_local_file_path(file_name))
|
78
|
+
tempfile.close; tempfile.unlink
|
79
|
+
rescue Errno::ENOENT
|
80
|
+
say "diff not installed", :red
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
desc 'file list', 'show all overlay files'
|
85
|
+
require_appliance_id
|
86
|
+
allow_remote_option
|
87
|
+
def list
|
88
|
+
require_appliance do |appliance|
|
89
|
+
out= if options.remote? || file_list_empty?
|
90
|
+
response= StudioApi::File.find(:all, :params => {:appliance_id => appliance.id})
|
91
|
+
response.collect do |file|
|
92
|
+
{file.filename => {"id" => id, "path" => file.path}}
|
93
|
+
end
|
94
|
+
else
|
95
|
+
list_local_files
|
96
|
+
end
|
97
|
+
say out.to_yaml
|
98
|
+
end
|
99
|
+
end
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
@@ -0,0 +1,79 @@
|
|
1
|
+
require 'yaml'
|
2
|
+
|
3
|
+
module SSC
|
4
|
+
module Handler
|
5
|
+
module Helper
|
6
|
+
|
7
|
+
def self.included(base)
|
8
|
+
base.extend ClassMethods
|
9
|
+
base.class_eval do
|
10
|
+
|
11
|
+
end
|
12
|
+
base.send :include, InstanceMethods
|
13
|
+
end
|
14
|
+
|
15
|
+
module ClassMethods
|
16
|
+
def require_authorization
|
17
|
+
config= get_config
|
18
|
+
method_option :username, :type => :string, :required => true,
|
19
|
+
:default => config["username"]
|
20
|
+
method_option :password, :type => :string, :required => true,
|
21
|
+
:default => config["password"]
|
22
|
+
method_option :proxy, :type => :string
|
23
|
+
method_option :timeout, :type => :string
|
24
|
+
end
|
25
|
+
|
26
|
+
def require_appliance_id
|
27
|
+
require_authorization
|
28
|
+
config= get_config
|
29
|
+
method_option :appliance_id, :type => :numeric, :required => true,
|
30
|
+
:default => config["appliance_id"]
|
31
|
+
end
|
32
|
+
|
33
|
+
def allow_remote_option
|
34
|
+
method_option :remote, :type => :boolean, :default => false
|
35
|
+
end
|
36
|
+
|
37
|
+
def get_config
|
38
|
+
begin
|
39
|
+
YAML::load File.read(File.join('.', '.sscrc'))
|
40
|
+
rescue Errno::ENOENT
|
41
|
+
return {'username' => nil, 'password' => nil, 'appliance_id' => nil}
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
|
46
|
+
module InstanceMethods
|
47
|
+
|
48
|
+
# Establish connection to Suse Studio with username, password
|
49
|
+
def connect(user, pass, connection_options)
|
50
|
+
@connection= StudioApi::Connection.new(user, pass, self.class::API_URL, connection_options)
|
51
|
+
StudioApi::Util.configure_studio_connection @connection
|
52
|
+
end
|
53
|
+
|
54
|
+
def filter_options(options, keys)
|
55
|
+
keys.inject({}) do |out, key|
|
56
|
+
(options.respond_to?(key) && options.send(key)) ? out.merge({ key => options.send(key) }) : out
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
60
|
+
def say_array(array, color= nil)
|
61
|
+
# NOTE
|
62
|
+
# Included for those methods that still return arrays for printing
|
63
|
+
# Can be removed eventually
|
64
|
+
# Still seems to be a nice way to format the text output of methods
|
65
|
+
say array.join("\n"), color
|
66
|
+
end
|
67
|
+
|
68
|
+
def require_appliance
|
69
|
+
if options.appliance_id
|
70
|
+
yield(StudioApi::Appliance.find(options.appliance_id))
|
71
|
+
else
|
72
|
+
raise "Unable to find the appliance"
|
73
|
+
end
|
74
|
+
end
|
75
|
+
end
|
76
|
+
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
@@ -0,0 +1,153 @@
|
|
1
|
+
module SSC
|
2
|
+
module Handler
|
3
|
+
class Package < Base
|
4
|
+
|
5
|
+
# Structure of the 'software' file:
|
6
|
+
#
|
7
|
+
# ---
|
8
|
+
# list:
|
9
|
+
# installed:
|
10
|
+
# <name>:
|
11
|
+
# version: <package.version>
|
12
|
+
# .
|
13
|
+
# .
|
14
|
+
# .
|
15
|
+
# selected:
|
16
|
+
# <name>:
|
17
|
+
# .
|
18
|
+
# .
|
19
|
+
# .
|
20
|
+
# add:
|
21
|
+
# <name>
|
22
|
+
# .
|
23
|
+
# .
|
24
|
+
# .
|
25
|
+
# remove:
|
26
|
+
# <name>
|
27
|
+
# .
|
28
|
+
# .
|
29
|
+
# .
|
30
|
+
# ban:
|
31
|
+
# <name>
|
32
|
+
# .
|
33
|
+
# .
|
34
|
+
# .
|
35
|
+
# unban:
|
36
|
+
# <name>
|
37
|
+
# .
|
38
|
+
# .
|
39
|
+
# .
|
40
|
+
|
41
|
+
no_tasks do
|
42
|
+
cattr_reader :local_source
|
43
|
+
@@local_source= 'software'
|
44
|
+
end
|
45
|
+
|
46
|
+
desc 'package search SEARCH_STRING', 'search available packages and patterns'
|
47
|
+
require_appliance_id
|
48
|
+
method_option :all_repos, :type => :boolean, :default => true
|
49
|
+
def search(search_string)
|
50
|
+
require_appliance_id(@options) do |appliance|
|
51
|
+
params= {:all_repos => options.all_repos} if options.all_repos
|
52
|
+
software= appliance.search_software(search_string, params)
|
53
|
+
say_array software.collect do |software|
|
54
|
+
"#{software.name} v#{software.version}. Repo Id: #{software.repository_id}"
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
desc 'package list [selected|installed]', 'list all selected or installed packages'
|
60
|
+
require_appliance_id
|
61
|
+
allow_remote_option
|
62
|
+
method_option :build_id, :type => :numeric
|
63
|
+
def list(type)
|
64
|
+
say("installed | selected package only", :red) unless ['installed', 'selected'].include?(type)
|
65
|
+
out= if options.remote? || no_local_list?
|
66
|
+
require_appliance do |appliance|
|
67
|
+
params= {:build_id => options.build_id} if options.build_id
|
68
|
+
software= appliance.send("#{type}_software")
|
69
|
+
formatted_list= software.collect do |package|
|
70
|
+
version= package.version ? { "version" => package.version } : nil
|
71
|
+
{package.name => version}
|
72
|
+
end
|
73
|
+
save(type, formatted_list)
|
74
|
+
formatted_list
|
75
|
+
end
|
76
|
+
else
|
77
|
+
read(type)
|
78
|
+
end
|
79
|
+
say out.to_yaml
|
80
|
+
end
|
81
|
+
|
82
|
+
|
83
|
+
desc 'package add NAME', 'add a package to the appliance'
|
84
|
+
require_appliance_id
|
85
|
+
allow_remote_option
|
86
|
+
def add(name)
|
87
|
+
if options.remote?
|
88
|
+
require_appliance do |appliance|
|
89
|
+
response= appliance.add_package(name)
|
90
|
+
say case response['state']
|
91
|
+
when "fixed"
|
92
|
+
"Package Added. State: #{response['state']}"
|
93
|
+
when "equal"
|
94
|
+
"Package Not Added."
|
95
|
+
when "broken"
|
96
|
+
"Package Added. State: #{response['state']}. Please resolve dependencies"
|
97
|
+
else
|
98
|
+
"unknown code"
|
99
|
+
end
|
100
|
+
end
|
101
|
+
else
|
102
|
+
save("add", [ name ])
|
103
|
+
say "#{name} marked for addition"
|
104
|
+
end
|
105
|
+
end
|
106
|
+
|
107
|
+
desc 'package remove NAME', 'remove a package from the appliance'
|
108
|
+
require_appliance_id
|
109
|
+
allow_remote_option
|
110
|
+
def remove(name)
|
111
|
+
if options.remote?
|
112
|
+
require_appliance do |appliance|
|
113
|
+
response= appliance.remove_package(name)
|
114
|
+
say "State: #{response['state']}"
|
115
|
+
end
|
116
|
+
else
|
117
|
+
save("remove", [ name ])
|
118
|
+
say "#{name} marked for removal"
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
desc 'package ban NAME', 'ban a package from the appliance'
|
123
|
+
require_appliance_id
|
124
|
+
allow_remote_option
|
125
|
+
def ban(name)
|
126
|
+
if options.remote?
|
127
|
+
require_appliance do |appliance|
|
128
|
+
response= appliance.ban_package(name)
|
129
|
+
response.collect{|key, val| "#{key}: #{val}"}
|
130
|
+
end
|
131
|
+
else
|
132
|
+
save("ban", [ name ])
|
133
|
+
say "#{name} marked to be banned"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
|
137
|
+
desc 'package unban NAME', 'unban a package for the appliance'
|
138
|
+
require_appliance_id
|
139
|
+
allow_remote_option
|
140
|
+
def unban(name)
|
141
|
+
if options.remote?
|
142
|
+
require_appliance do |appliance|
|
143
|
+
response= appliance.unban_package(name)
|
144
|
+
response.collect{|key, val| "#{key}: #{val}"}
|
145
|
+
end
|
146
|
+
else
|
147
|
+
save("unban", [ name ])
|
148
|
+
say "#{name} marked to be unbanned"
|
149
|
+
end
|
150
|
+
end
|
151
|
+
end
|
152
|
+
end
|
153
|
+
end
|
@@ -0,0 +1,109 @@
|
|
1
|
+
module SSC
|
2
|
+
module Handler
|
3
|
+
class Repository < Base
|
4
|
+
|
5
|
+
# Structure of the 'repositories' file:
|
6
|
+
#
|
7
|
+
# ---
|
8
|
+
# list:
|
9
|
+
# <id>:
|
10
|
+
# name: <repo.name>
|
11
|
+
# type: <repo.type>
|
12
|
+
# base_system: <repo.base_url>
|
13
|
+
# .
|
14
|
+
# .
|
15
|
+
# .
|
16
|
+
# add:
|
17
|
+
# <id>
|
18
|
+
# .
|
19
|
+
# .
|
20
|
+
# .
|
21
|
+
# remove:
|
22
|
+
# <id>
|
23
|
+
# .
|
24
|
+
# .
|
25
|
+
# .
|
26
|
+
# import:
|
27
|
+
# name: <name>
|
28
|
+
# url: <url>
|
29
|
+
no_tasks do
|
30
|
+
cattr_reader :local_source
|
31
|
+
@@local_source= 'repositories'
|
32
|
+
end
|
33
|
+
|
34
|
+
desc "repository search SEARCH_STRING", "search all available repositories"
|
35
|
+
require_authorization
|
36
|
+
method_option :base_system, :type => :string
|
37
|
+
def search(search_string)
|
38
|
+
params= {:filter => search_string}
|
39
|
+
params= params.merge({:base_system => options.base_system}) if options.base_system
|
40
|
+
repos= StudioApi::Repository.find(:all, :params => params)
|
41
|
+
say_array(repos.collect do |repo|
|
42
|
+
"#{repo.id}.) #{repo.name}: #{repo.base_url}
|
43
|
+
#{[repo.matches.software_name].flatten.join(', ')}\n"
|
44
|
+
end)
|
45
|
+
end
|
46
|
+
|
47
|
+
desc "repository list", "list all repositories in a given appliance"
|
48
|
+
require_appliance_id
|
49
|
+
allow_remote_option
|
50
|
+
def list
|
51
|
+
list= if options.remote? || no_local_list?
|
52
|
+
require_appliance do |appliance|
|
53
|
+
appliance.repositories.collect do |repo|
|
54
|
+
{ repo.id => { 'name' => repo.name,
|
55
|
+
'type' => repo.type,
|
56
|
+
'base_system' => repo.base_system}}
|
57
|
+
end
|
58
|
+
end
|
59
|
+
else
|
60
|
+
read('list')
|
61
|
+
end
|
62
|
+
save('list', list) unless options.remote?
|
63
|
+
say list.to_yaml
|
64
|
+
end
|
65
|
+
|
66
|
+
desc 'repository add REPO_IDS', 'add existing repositories to the appliance'
|
67
|
+
require_appliance_id
|
68
|
+
allow_remote_option
|
69
|
+
def add(*repo_ids)
|
70
|
+
if options.remote?
|
71
|
+
require_appliance do |appliance|
|
72
|
+
response= appliance.add_repository(repo_ids)
|
73
|
+
say "Added"+( response.collect{|repos| repos.name} ).join(", ")
|
74
|
+
end
|
75
|
+
else
|
76
|
+
save('add', repo_ids)
|
77
|
+
say "Marked the following for addition #{repo_ids.join(", ")}"
|
78
|
+
end
|
79
|
+
end
|
80
|
+
|
81
|
+
desc 'repository remove REPO_IDS', 'remove existing repositories from appliance'
|
82
|
+
require_appliance_id
|
83
|
+
allow_remote_option
|
84
|
+
def remove(*repo_ids)
|
85
|
+
if options.remote?
|
86
|
+
require_appliance do |appliance|
|
87
|
+
response= appliance.remove_repository(repo_ids)
|
88
|
+
say "Removed #{repo_ids.join(", ")}"
|
89
|
+
end
|
90
|
+
else
|
91
|
+
save('remove', repo_ids)
|
92
|
+
say "Marked the following for removal #{repo_ids.join(", ")}"
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
desc 'repository import URL NAME', 'import a 3rd party repository into appliance'
|
97
|
+
allow_remote_option
|
98
|
+
def import(url, name)
|
99
|
+
if options.remote?
|
100
|
+
repository= StudioApi::Repository.import(url, name)
|
101
|
+
say "Added #{repository.name} at #{url}"
|
102
|
+
else
|
103
|
+
save("import", [{"name" => name, "url" => url}])
|
104
|
+
say "Marked #{name} for import"
|
105
|
+
end
|
106
|
+
end
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
@@ -0,0 +1,25 @@
|
|
1
|
+
module SSC
|
2
|
+
module Handler
|
3
|
+
class Template < Base
|
4
|
+
|
5
|
+
desc 'template list_sets', 'list all available template sets'
|
6
|
+
require_authorization
|
7
|
+
def list_sets
|
8
|
+
templates= StudioApi::TemplateSet.find(:all)
|
9
|
+
say_array templates.collect {|template| template.name}
|
10
|
+
end
|
11
|
+
|
12
|
+
desc 'template list SET_NAME', 'show details of a particular template set'
|
13
|
+
require_authorization
|
14
|
+
def list(name)
|
15
|
+
template_set= StudioApi::TemplateSet.find(name)
|
16
|
+
out = [template_set.name+' : '+template_set.description]
|
17
|
+
out += template_set.template.collect do |appliance|
|
18
|
+
"#{appliance.appliance_id}: #{appliance.name}"
|
19
|
+
end
|
20
|
+
say_array out
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
data/lib/ssc.rb
ADDED
@@ -0,0 +1,18 @@
|
|
1
|
+
module SSC
|
2
|
+
end
|
3
|
+
|
4
|
+
require 'thor'
|
5
|
+
require 'thor/group'
|
6
|
+
require 'directory_manager'
|
7
|
+
require 'handlers/all'
|
8
|
+
require 'yaml'
|
9
|
+
|
10
|
+
module SSC
|
11
|
+
class Base < Thor
|
12
|
+
register Handler::Appliance, :appliance, "appliance", "manage appliances"
|
13
|
+
register Handler::Repository, :repository, "repository","manage repositories"
|
14
|
+
register Handler::Package, :package, "package", "manage packages"
|
15
|
+
register Handler::Template, :template, "template", "manage templates"
|
16
|
+
register Handler::OverlayFile, :file, "file", "manage files"
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHandlerAppliance < Test::Unit::TestCase
|
4
|
+
context "SSC::Handler::Template" do
|
5
|
+
context "#list" do
|
6
|
+
setup do
|
7
|
+
@handler= SSC::Handler::Appliance.new()
|
8
|
+
@handler.stubs(:connect)
|
9
|
+
end
|
10
|
+
|
11
|
+
should "call find(:all) on StudioApi::Appliance" do
|
12
|
+
mock_app_list= mock('appliance list')
|
13
|
+
mock_app_list.stubs(:collect)
|
14
|
+
mock_app_list.stubs(:empty?)
|
15
|
+
StudioApi::Appliance.expects(:find).with(:all).returns(mock_app_list)
|
16
|
+
@handler.list
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,45 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHandlerHelper < Test::Unit::TestCase
|
4
|
+
context "SSC::Handler::Helper" do
|
5
|
+
setup do
|
6
|
+
class TestObject
|
7
|
+
include SSC::Handler::Helper
|
8
|
+
end
|
9
|
+
|
10
|
+
@objekt= TestObject.new
|
11
|
+
end
|
12
|
+
|
13
|
+
context "#connect" do
|
14
|
+
should "create connection and configure StudioApi to use it" do
|
15
|
+
mock_connection= mock('connection')
|
16
|
+
StudioApi::Connection.expects(:new)
|
17
|
+
.with('user', 'pass', 'https://susestudio.com/api/v1/user',
|
18
|
+
{:proxy => 'proxy'})
|
19
|
+
.returns(mock_connection)
|
20
|
+
StudioApi::Util.expects(:configure_studio_connection).with(mock_connection)
|
21
|
+
@objekt.connect('user', 'pass', {:proxy => 'proxy', :another_option => 'value'})
|
22
|
+
end
|
23
|
+
end
|
24
|
+
|
25
|
+
context "#filter_options" do
|
26
|
+
should "return a hash of only the specified keys" do
|
27
|
+
out= @objekt.filter_options({:a => 'a', :b => 'b'}, [:a])
|
28
|
+
assert_equal({:a => 'a'}, out)
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
context "#require_appliance_id" do
|
33
|
+
should "raise and error if the appliance id option is not passed" do
|
34
|
+
assert_raise(RuntimeError) { @objekt.require_appliance_id({}) }
|
35
|
+
end
|
36
|
+
|
37
|
+
should "not raise error if appliance id is provided" do
|
38
|
+
StudioApi::Appliance.expects(:find).with(1).returns(nil)
|
39
|
+
assert_nothing_raised do
|
40
|
+
@objekt.require_appliance_id(:appliance_id=>1) {|i| i}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestHandlerRepository < Test::Unit::TestCase
|
4
|
+
context "SSC::Handler::Repository" do
|
5
|
+
setup do
|
6
|
+
@handler= SSC::Handler::Repository.new()
|
7
|
+
@handler.stubs(:connect)
|
8
|
+
end
|
9
|
+
context "#search" do
|
10
|
+
|
11
|
+
should "call .find(:all, params_hash) on StudioApi::Repository" do
|
12
|
+
mock_collection= mock('collection')
|
13
|
+
mock_collection.stubs(:collect)
|
14
|
+
StudioApi::Repository.expects(:find).with(:all, :params => {:filter => 'chess', :base_system => '11.1'}).returns(mock_collection)
|
15
|
+
@handler.instance_variable_set('@options', {:base_system => '11.1'})
|
16
|
+
@handler.search('chess')
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
@@ -0,0 +1,27 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestTemplateHandler < Test::Unit::TestCase
|
4
|
+
context "SSC::Handler::Template" do
|
5
|
+
context "#list" do
|
6
|
+
setup do
|
7
|
+
@handler= SSC::Handler::Template.new()
|
8
|
+
@handler.stubs(:connect)
|
9
|
+
end
|
10
|
+
|
11
|
+
should "call .find(:all) on StudioApi::TemplateSet" do
|
12
|
+
mock_template= mock('template_list')
|
13
|
+
mock_template.stubs(:collect)
|
14
|
+
StudioApi::TemplateSet.expects(:find).with(:all).returns(mock_template)
|
15
|
+
@handler.list
|
16
|
+
end
|
17
|
+
|
18
|
+
should "return a list of strings of type 'template.id: template.name'" do
|
19
|
+
mock_template= StudioApi::TemplateSet.new(:name => 'Template Name')
|
20
|
+
StudioApi::TemplateSet.stubs(:find).with(:all).returns([mock_template])
|
21
|
+
assert_equal ["Template Name"],
|
22
|
+
@handler.list
|
23
|
+
end
|
24
|
+
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,19 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'bundler'
|
3
|
+
begin
|
4
|
+
Bundler.setup(:default, :development)
|
5
|
+
rescue Bundler::BundlerError => e
|
6
|
+
$stderr.puts e.message
|
7
|
+
$stderr.puts "Run `bundle install` to install missing gems"
|
8
|
+
exit e.status_code
|
9
|
+
end
|
10
|
+
require 'test/unit'
|
11
|
+
require 'shoulda'
|
12
|
+
require 'mocha'
|
13
|
+
|
14
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
15
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
16
|
+
require 'ssc'
|
17
|
+
|
18
|
+
class Test::Unit::TestCase
|
19
|
+
end
|
@@ -0,0 +1,55 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class TestArgumentParser < Test::Unit::TestCase
|
4
|
+
context "SSC::ArgumentParser" do
|
5
|
+
|
6
|
+
context "when arguments are good" do
|
7
|
+
setup do
|
8
|
+
@parser= SSC::ArgumentParser.new(['appliance', 'create', 'act_arg1', 'act_arg2', '--option', 'value', '-o', 'v', '--flag', '-f'])
|
9
|
+
end
|
10
|
+
|
11
|
+
should "set @klass to Appliance" do
|
12
|
+
assert_equal SSC::Handler::Appliance, @parser.klass
|
13
|
+
end
|
14
|
+
|
15
|
+
should "set @action to create" do
|
16
|
+
assert_equal 'create', @parser.action
|
17
|
+
end
|
18
|
+
|
19
|
+
should "set @options to option hash" do
|
20
|
+
assert_equal({:option => 'value',
|
21
|
+
:o => 'v',
|
22
|
+
:flag => true,
|
23
|
+
:f => true }, @parser.options)
|
24
|
+
end
|
25
|
+
|
26
|
+
should "set @action_arguments to argument array" do
|
27
|
+
#only one of the arguments must be taken since create take only one argument
|
28
|
+
assert_equal(['act_arg1'], @parser.action_arguments)
|
29
|
+
end
|
30
|
+
|
31
|
+
should "have the entire list if arity of the method is -1(splat)" do
|
32
|
+
parser= SSC::ArgumentParser.new(['repository', 'add', 'act_arg1', 'act_arg2'])
|
33
|
+
assert_equal(['act_arg1', 'act_arg2'], parser.action_arguments )
|
34
|
+
end
|
35
|
+
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
context "when handler is unknown" do
|
40
|
+
should "raise UnkownOptionError" do
|
41
|
+
assert_raise(SSC::UnkownOptionError) do
|
42
|
+
SSC::ArgumentParser.new(['apliance', 'create'])
|
43
|
+
end
|
44
|
+
end
|
45
|
+
end
|
46
|
+
|
47
|
+
context "when handler method is unknown" do
|
48
|
+
should "raise UnkownOptionError" do
|
49
|
+
assert_raise(SSC::UnkownOptionError) do
|
50
|
+
SSC::ArgumentParser.new(['appliance', 'unkown_method'])
|
51
|
+
end
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
end
|