ruby-jss 1.0.0b2 → 1.0.0b6
Sign up to get free protection for your applications and to get access to all the features.
Potentially problematic release.
This version of ruby-jss might be problematic. Click here for more details.
- checksums.yaml +5 -5
- data/.yardopts +1 -1
- data/CHANGES.md +46 -8
- data/README.md +26 -27
- data/bin/cgrouper +2 -2
- data/bin/jamfHelperBackgrounder +0 -2
- data/bin/netseg-update +3 -4
- data/data/ruby-jss.conf.example +2 -8
- data/lib/jss/api_connection.rb +6 -3
- data/lib/jss/api_object/advanced_search.rb +1 -1
- data/lib/jss/api_object/computer_invitation.rb +1 -1
- data/lib/jss/api_object/criteriable.rb +1 -1
- data/lib/jss/api_object/ebook.rb +25 -0
- data/lib/jss/api_object/group.rb +1 -1
- data/lib/jss/api_object/mobile_device_application.rb +1 -1
- data/lib/jss/api_object/patch_title.rb +98 -46
- data/lib/jss/api_object/peripheral.rb +2 -2
- data/lib/jss/api_object/sitable.rb +1 -1
- data/lib/jss/api_object.rb +2 -2
- data/lib/jss/client/management_action.rb +2 -2
- data/lib/jss/utility.rb +1 -1
- data/lib/jss/validate.rb +32 -29
- data/lib/jss/version.rb +1 -1
- data/test/README.md +149 -0
- data/test/bin/runtests +290 -0
- data/test/lib/testhelper/auth.rb +275 -0
- data/test/lib/testhelper/patch_mgmt.rb +123 -0
- data/test/lib/testhelper.rb +69 -0
- data/test/specs/api_connection_spec.rb +57 -0
- data/test/specs/patch01_source_spec.rb +54 -0
- data/test/specs/patch02_internal_source_spec.rb +88 -0
- data/test/specs/patch03_external_source_spec.rb +120 -0
- data/test/specs/patch04_titles_spec.rb +207 -0
- data/test/specs/patch05_policies_spec.rb +119 -0
- data/test/specs/patch06_cleanup_spec.rb +52 -0
- data/test/specs/policy_spec.rb +112 -0
- metadata +16 -3
@@ -148,7 +148,7 @@ module JSS
|
|
148
148
|
@init_data[:general][:fields].each{|f| @fields[f[:name]] = f[:value] }
|
149
149
|
|
150
150
|
### get the field defs for this PeriphType, omitting the leading nil
|
151
|
-
@field_defs ||= JSS::PeripheralType.
|
151
|
+
@field_defs ||= JSS::PeripheralType.fetch(:name => @type).fields.compact
|
152
152
|
|
153
153
|
|
154
154
|
end # initialize
|
@@ -269,7 +269,7 @@ module JSS
|
|
269
269
|
###
|
270
270
|
def check_field(field, value)
|
271
271
|
### get the field defs for this PeriphType, omitting the leading nil
|
272
|
-
@field_defs ||= JSS::PeripheralType.
|
272
|
+
@field_defs ||= JSS::PeripheralType.fetch(:name => @type, api: @api).fields.compact
|
273
273
|
|
274
274
|
### we must have the right number of fields, and they must have the same names
|
275
275
|
### as the definition
|
data/lib/jss/api_object.rb
CHANGED
@@ -295,7 +295,7 @@ module JSS
|
|
295
295
|
return identifier if all_ids(refresh, api: api).include? identifier
|
296
296
|
all_lookup_keys.keys.each do |key|
|
297
297
|
next if key == :id
|
298
|
-
id = map_all_ids_to(key).invert[identifier]
|
298
|
+
id = map_all_ids_to(key, api: api).invert[identifier]
|
299
299
|
return id if id
|
300
300
|
end # do key
|
301
301
|
nil
|
@@ -996,7 +996,7 @@ module JSS
|
|
996
996
|
|
997
997
|
raise JSS::MissingDataError, "Args must include a lookup key, one of: :#{lookup_keys.join(', :')}" unless lookup_key
|
998
998
|
|
999
|
-
vid = self.class.valid_id args[lookup_key], :refresh
|
999
|
+
vid = self.class.valid_id args[lookup_key], :refresh, api: args[:api]
|
1000
1000
|
|
1001
1001
|
raise NoSuchItemError, "No #{self.class::RSRC_OBJECT_KEY} found with #{lookup_key} '#{args[lookup_key]}'" unless vid
|
1002
1002
|
|
@@ -63,8 +63,8 @@ module JSS
|
|
63
63
|
|
64
64
|
# Skipping all the force-alerts stuff until we figure out cleaner
|
65
65
|
# ways to do it in 10.13+
|
66
|
-
# The plan is to make the NotificationCenter notification
|
67
|
-
# 'alert' (which stays visible til the user clicks)
|
66
|
+
# The plan is to be able to make the NotificationCenter notification be an
|
67
|
+
# 'alert' (which stays visible til the user clicks) or a
|
68
68
|
# 'banner' (which vanishes in a few seconds), regardless of the user's
|
69
69
|
# setting in the NC prefs.
|
70
70
|
|
data/lib/jss/utility.rb
CHANGED
@@ -211,7 +211,7 @@ module JSS
|
|
211
211
|
# if we're here, its a Pathname
|
212
212
|
raise JSS::MissingDataError, "No such file: #{plist}" unless plist.file?
|
213
213
|
|
214
|
-
Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape(plist.to_s)}
|
214
|
+
Plist.parse_xml `/usr/libexec/PlistBuddy -x -c print #{Shellwords.escape(plist.to_s)}`.force_encoding('UTF-8')
|
215
215
|
end # parse_plist
|
216
216
|
|
217
217
|
# Converts anything that responds to #to_s to a Time, or nil
|
data/lib/jss/validate.rb
CHANGED
@@ -42,10 +42,13 @@ module JSS
|
|
42
42
|
#
|
43
43
|
# @param val[String] The value to validate
|
44
44
|
#
|
45
|
+
# @param msg[String] A custom error message when the value is invalid
|
46
|
+
#
|
45
47
|
# @return [String] The valid value
|
46
48
|
#
|
47
|
-
def self.mac_address(val)
|
48
|
-
|
49
|
+
def self.mac_address(val, msg = nil)
|
50
|
+
msg ||= "Not a valid MAC address: '#{val}'"
|
51
|
+
raise JSS::InvalidDataError, msg unless val =~ MAC_ADDR_RE
|
49
52
|
val
|
50
53
|
end
|
51
54
|
|
@@ -53,14 +56,17 @@ module JSS
|
|
53
56
|
#
|
54
57
|
# @param val[String] The value to validate
|
55
58
|
#
|
59
|
+
# @param msg[String] A custom error message when the value is invalid
|
60
|
+
#
|
56
61
|
# @return [String] The valid value
|
57
62
|
#
|
58
|
-
def self.ip_address(val)
|
63
|
+
def self.ip_address(val, msg = nil)
|
64
|
+
msg ||= "Not a valid IPv4 address: '#{val}'"
|
59
65
|
ok = true
|
60
66
|
parts = val.strip.split '.'
|
61
67
|
ok = false unless parts.size == 4
|
62
68
|
parts.each { |p| ok = false unless p.jss_integer? && p.to_i < 256 && p.to_i >= 0 }
|
63
|
-
raise JSS::InvalidDataError,
|
69
|
+
raise JSS::InvalidDataError, msg unless ok
|
64
70
|
val
|
65
71
|
end
|
66
72
|
|
@@ -77,11 +83,16 @@ module JSS
|
|
77
83
|
#
|
78
84
|
# @param val[Object] The value to check for uniqueness
|
79
85
|
#
|
86
|
+
# @param msg[String] A custom error message when the value is invalid
|
87
|
+
#
|
88
|
+
# @param api[JSS::APIConnection] The api connection to use for validation
|
89
|
+
#
|
80
90
|
# @return [Object] the validated unique value
|
81
91
|
#
|
82
|
-
def self.unique_identifier(klass, identifier, val, api: JSS.api)
|
92
|
+
def self.unique_identifier(klass, identifier, val, msg = nil, api: JSS.api)
|
93
|
+
msg ||= "A #{klass} already exists with #{identifier} '#{val}'"
|
83
94
|
return val unless klass.all(:refresh, api: api).map { |i| i[identifier] }.include? val
|
84
|
-
raise JSS::AlreadyExistsError,
|
95
|
+
raise JSS::AlreadyExistsError, msg
|
85
96
|
end
|
86
97
|
|
87
98
|
# Confirm that the given value is a boolean value, accepting
|
@@ -93,13 +104,16 @@ module JSS
|
|
93
104
|
#
|
94
105
|
# @param bool [Boolean,String,Symbol] The value to validate
|
95
106
|
#
|
107
|
+
# @param msg[String] A custom error message when the value is invalid
|
108
|
+
#
|
96
109
|
# @return [Boolean] the valid boolean
|
97
110
|
#
|
98
|
-
def self.boolean(bool)
|
111
|
+
def self.boolean(bool, msg = nil)
|
112
|
+
msg ||= 'Value must be boolean true or false'
|
99
113
|
return bool if JSS::TRUE_FALSE.include? bool
|
100
114
|
return true if bool.to_s =~ /^(true|yes)$/i
|
101
115
|
return false if bool.to_s =~ /^(false|no)$/i
|
102
|
-
raise JSS::InvalidDataError,
|
116
|
+
raise JSS::InvalidDataError, msg
|
103
117
|
end
|
104
118
|
|
105
119
|
# Confirm that a value is an integer or a string representation of an
|
@@ -109,11 +123,14 @@ module JSS
|
|
109
123
|
#
|
110
124
|
# @param val[Object] the value to validate
|
111
125
|
#
|
126
|
+
# @param msg[String] A custom error message when the value is invalid
|
127
|
+
#
|
112
128
|
# @return [void]
|
113
129
|
#
|
114
|
-
def self.integer(val)
|
130
|
+
def self.integer(val, msg = nil)
|
131
|
+
msg ||= 'Value must be an integer'
|
115
132
|
val = val.to_i if val.is_a?(String) && val.jss_integer?
|
116
|
-
raise JSS::InvalidDataError,
|
133
|
+
raise JSS::InvalidDataError, msg unless val.is_a? Integer
|
117
134
|
val
|
118
135
|
end
|
119
136
|
|
@@ -121,30 +138,16 @@ module JSS
|
|
121
138
|
#
|
122
139
|
# @param val [Object] the thing to validate
|
123
140
|
#
|
141
|
+
# @param msg[String] A custom error message when the value is invalid
|
142
|
+
#
|
124
143
|
# @return [String] the valid non-empty string
|
125
144
|
#
|
126
|
-
def self.non_empty_string(val)
|
127
|
-
|
145
|
+
def self.non_empty_string(val, msg = nil)
|
146
|
+
msg ||= 'value must be a non-empty String'
|
147
|
+
raise JSS::InvalidDataError, msg unless val.is_a?(String) && !val.empty?
|
128
148
|
val
|
129
149
|
end
|
130
150
|
|
131
|
-
# Confirm that the given value is a boolean value, accepting
|
132
|
-
# strings and symbols and returning real booleans as needed
|
133
|
-
# Accepts: true, false, 'true', 'false', :true, :false, 'yes', 'no', :yes,
|
134
|
-
# or :no (all Strings and Symbols are case insensitive)
|
135
|
-
#
|
136
|
-
#
|
137
|
-
# @param bool [Boolean,String,Symbol] The value to validate
|
138
|
-
#
|
139
|
-
# @return [Boolean] the valid boolean
|
140
|
-
#
|
141
|
-
def self.boolean(bool)
|
142
|
-
return bool if JSS::TRUE_FALSE.include? bool
|
143
|
-
return true if bool.to_s =~ /^(true|yes)$/i
|
144
|
-
return false if bool.to_s =~ /^(false|no)$/i
|
145
|
-
raise JSS::InvalidDataError, 'Value must be boolean true or false'
|
146
|
-
end
|
147
|
-
|
148
151
|
end # module validate
|
149
152
|
|
150
153
|
end # module JSS
|
data/lib/jss/version.rb
CHANGED
data/test/README.md
ADDED
@@ -0,0 +1,149 @@
|
|
1
|
+
# About the ruby-jss test suite
|
2
|
+
|
3
|
+
For years, I've attempted to use some ruby testing framework to automate testing of ruby-jss.
|
4
|
+
|
5
|
+
Every time I've run into walls because unit testing suites are designed for unit testing, and that's not really what we need to do. Yes we need to test individual methods of classes and so on, but when working with a REST API, there's a lot of
|
6
|
+
scaffolding that needs to happen before tests can even start - and that scaffolding itself is testing the code. And the details of the scaffolding will vary in different environments.
|
7
|
+
|
8
|
+
For example, the tests *must* be very interactive from the start - you have to tell them what server to connect with, what credentials to use, and so on.
|
9
|
+
|
10
|
+
Once connected, objects have to be created before they can be listed, fetched, updated, or deleted - so test order matters.
|
11
|
+
|
12
|
+
Also, you need to be able to have later tests refer to the same objects you created in earlier tests. Once I've tested that I can create an object on the server and re-fetch it once, I shuold be able to use that object for all future tests without fetching every time.
|
13
|
+
|
14
|
+
Reading most tutorials about ruby testing just leads you in circles when you consider needs such as these.
|
15
|
+
|
16
|
+
Many propnents of unit testing might find this suite odd. Thats ok. Any functional testing suite is better than none and I'm open to suggestions for improvement.
|
17
|
+
|
18
|
+
### Here's how to use it:
|
19
|
+
|
20
|
+
tldr:
|
21
|
+
|
22
|
+
`/path/to/your/ruby-jss/gem/installation/test/bin/runtests --server myjss.company.com --user myjssusername`
|
23
|
+
|
24
|
+
Must be run on a mac, it uses your keychain to store connection data and credentials, so you only have to provide them the first time or when changing them.
|
25
|
+
|
26
|
+
See below for the help output
|
27
|
+
|
28
|
+
### Here's how this thing works:
|
29
|
+
|
30
|
+
- The tests are ultimatly MiniTest::Spec specifications, defined in files in the 'specs' folder.
|
31
|
+
- See http://ruby-doc.org/stdlib-2.0.0/libdoc/minitest/rdoc/MiniTest.html
|
32
|
+
- also, google around for help with minitest specs
|
33
|
+
|
34
|
+
|
35
|
+
- They do NOT use minitest/autorun. Instead, the 'runtests' executable handles loading and running them
|
36
|
+
- See below for the help output
|
37
|
+
|
38
|
+
|
39
|
+
- The runtests command, via methods in the JSSTestHelper module, handles connecting to servers.
|
40
|
+
- it takes options to define connection parameters.
|
41
|
+
- At the moment they are limited to user, hostname and port, but will be expanded eventually
|
42
|
+
- it prompts for passwords as needed
|
43
|
+
- it must be run on a Mac! It stores connection parameters in your keychain.
|
44
|
+
- it uses connection parameters from your keychain if they are present. meaning after the first use,
|
45
|
+
it will connect to the same server as the same user with no commandline options.
|
46
|
+
- If any commandline options are different from whats in the keychain, the keychain will be updated,
|
47
|
+
prompting for new passwords if needed.
|
48
|
+
|
49
|
+
- The JSSTestHelper module also provides ways for tests to share data.
|
50
|
+
|
51
|
+
- The runtests command will run the spec files listed on the command line, or all of them if none are listed.
|
52
|
+
- The tests are run verbosely, so you can see what tests are being run.
|
53
|
+
- Some tests are interactive - they will ask you to make choices about what's happening.
|
54
|
+
|
55
|
+
WARNING: **Be very careful about running these tests on your production JSS !!!**
|
56
|
+
|
57
|
+
These tests create and delete objects in the JSS. While they _shouldn't_ hurt any of the existing data - we cannot make any guarantees that they won't hurt something you care about.
|
58
|
+
|
59
|
+
As the license text for ruby-jss states:
|
60
|
+
|
61
|
+
```
|
62
|
+
Unless required by applicable law or agreed to in writing, software
|
63
|
+
distributed under the Apache License with the above modification is
|
64
|
+
distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
65
|
+
KIND, either express or implied.
|
66
|
+
```
|
67
|
+
|
68
|
+
As a reminder, if you connect to the same server that's listed in your /etc/ruby-jss.conf, you'll be asked for confirmation before the tests are run.
|
69
|
+
|
70
|
+
|
71
|
+
### The Spec Files
|
72
|
+
|
73
|
+
Each spec file defines one or more MiniTest::Spec's, each one being a 'describe SomeClass' block, containing methods and individual tests in 'it' blocks.
|
74
|
+
|
75
|
+
If you plan to write any tests, please read up on how to write MiniTest Specs.
|
76
|
+
|
77
|
+
However, here's some info that wasn't obvious when I first started, and makes life much easier when writing specs:
|
78
|
+
|
79
|
+
- the 'describe' blocks eventually become classes
|
80
|
+
- you can do anything inside them that you would do in a class definition.
|
81
|
+
- the 'it' blocks become methods in the class defined by the 'describe' block.
|
82
|
+
- the 'it' blocks are run one at a time, each in a separate instance of the class defined by the 'describe' block.
|
83
|
+
- by default, the 'it' blocks are run in a random order. See below if you need them to run in the defined order.
|
84
|
+
|
85
|
+
All of the above means that you can use constants, class methods, class-instance variables and instance methods in concert for processing and passing things between the individual tests.
|
86
|
+
|
87
|
+
### Running tests in order
|
88
|
+
|
89
|
+
The individual spec files are run in the order given on the command line. If none are given on the command line, all files are run in alphabetical order.
|
90
|
+
|
91
|
+
If you define multiple 'describe' blocks in a file, they will be run in random order.
|
92
|
+
|
93
|
+
The individual tests in a describe block are also run in random order, by default.
|
94
|
+
|
95
|
+
If you need the tests to run in order within a 'describe' block, then define this class method somewhere inside it:
|
96
|
+
|
97
|
+
def self.test_order
|
98
|
+
:alpha
|
99
|
+
end
|
100
|
+
|
101
|
+
The presence of that method will cause MiniTest to run them in the order defined.
|
102
|
+
|
103
|
+
### Help output from 'runtests -H'
|
104
|
+
|
105
|
+
|
106
|
+
```
|
107
|
+
Usage: runtests [options] [spec [spec ...]]
|
108
|
+
|
109
|
+
Runs one or more specification tests of ruby-jss.
|
110
|
+
|
111
|
+
The specifications are files in the directory:
|
112
|
+
/Users/chrisl/git/gemdev/ruby-jss/test/specs
|
113
|
+
|
114
|
+
The files must have a _spec.rb suffix, however you need not use the suffix when
|
115
|
+
listing tests to run on the command line, e.g. 'patch_source' will run
|
116
|
+
'patch_source_spec.rb'
|
117
|
+
|
118
|
+
If no specs files are listed on the command line, all will be run, in
|
119
|
+
alphabetical order.
|
120
|
+
|
121
|
+
By default, JSS connection settings are used from your /etc/ruby-jss.conf file
|
122
|
+
and/or ~/.ruby-jss.conf. Connection settings from the command line will be used
|
123
|
+
if provided.
|
124
|
+
|
125
|
+
WARNING: These tests create, modify, and delete objects in the JSS.
|
126
|
+
While no existing objects should be changed, * Be Careful * running them on
|
127
|
+
a production server.
|
128
|
+
If the server you're connecting to matches one defined in /etc/ruby-jss.conf
|
129
|
+
you will be asked for confirmation before proceding.
|
130
|
+
|
131
|
+
The first time you connect from this machine to a given server, you must provide
|
132
|
+
a username for the connection with --user, and will be prompted for the password.
|
133
|
+
Once authenticated, credentials for the server are saved in your keychain, and
|
134
|
+
future connections to that server will read the user & password from there.
|
135
|
+
If a different user is later specified for that server, you'll be prompted again
|
136
|
+
for a password, and the keychain will be updated.
|
137
|
+
|
138
|
+
Options
|
139
|
+
--server, -s <host> the hostname for the JSS API connection
|
140
|
+
--port, -p <port> the port for the API connection
|
141
|
+
--user, -u <user> the API username for the connection
|
142
|
+
NOTE: must have permissions to perform the tests!
|
143
|
+
--db-server, -S <host> the hostname for the JSS API connection
|
144
|
+
--db-port, -P <port> the port for the API connectino
|
145
|
+
--db-user, -U <user> the API username for the connection
|
146
|
+
--gem-dir, -g, -i <path> the path from which to require ruby-jss
|
147
|
+
(sets GEM_HOME to this path before requiring)
|
148
|
+
--help, -h, -H show this help
|
149
|
+
```
|
data/test/bin/runtests
ADDED
@@ -0,0 +1,290 @@
|
|
1
|
+
#!/usr/bin/ruby
|
2
|
+
|
3
|
+
### Copyright 2018 Pixar
|
4
|
+
|
5
|
+
###
|
6
|
+
### Licensed under the Apache License, Version 2.0 (the "Apache License")
|
7
|
+
### with the following modification; you may not use this file except in
|
8
|
+
### compliance with the Apache License and the following modification to it:
|
9
|
+
### Section 6. Trademarks. is deleted and replaced with:
|
10
|
+
###
|
11
|
+
### 6. Trademarks. This License does not grant permission to use the trade
|
12
|
+
### names, trademarks, service marks, or product names of the Licensor
|
13
|
+
### and its affiliates, except as required to comply with Section 4(c) of
|
14
|
+
### the License and to reproduce the content of the NOTICE file.
|
15
|
+
###
|
16
|
+
### You may obtain a copy of the Apache License at
|
17
|
+
###
|
18
|
+
### http://www.apache.org/licenses/LICENSE-2.0
|
19
|
+
###
|
20
|
+
### Unless required by applicable law or agreed to in writing, software
|
21
|
+
### distributed under the Apache License with the above modification is
|
22
|
+
### distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
|
23
|
+
### KIND, either express or implied. See the Apache License for the specific
|
24
|
+
### language governing permissions and limitations under the Apache License.
|
25
|
+
###
|
26
|
+
###
|
27
|
+
|
28
|
+
# Uses the MiniTest::Spec infrastructure to run one or tests of ruby-jss
|
29
|
+
#
|
30
|
+
# We do not use minitest/autorun, so that we have more control over which tests
|
31
|
+
# are run and how. But the individual spec files are standard MiniTest::Spec
|
32
|
+
# 'describe' blocks
|
33
|
+
#
|
34
|
+
# Those blocks become classes when the tests are run, and for each test,
|
35
|
+
# an instance of the class is created.
|
36
|
+
# As such, the interior of the blocks can be treated like class definitions,
|
37
|
+
# defining constants, class methods, instance methods and so on.
|
38
|
+
#
|
39
|
+
# As well as that class-based infratructure, this tool includes a JSSTestHelper
|
40
|
+
# module which defines usefule constants and helper methods, accessible from
|
41
|
+
# anywhere via the module name.
|
42
|
+
#
|
43
|
+
|
44
|
+
require 'pathname'
|
45
|
+
require 'getoptlong'
|
46
|
+
require 'keychain'
|
47
|
+
require 'minitest/spec'
|
48
|
+
# require 'minitest/autorun' # DO NOT REQUIRE AUTORUN - we manually run each file below.
|
49
|
+
|
50
|
+
# app
|
51
|
+
class App
|
52
|
+
|
53
|
+
SPEC_SUFFIX = '_spec.rb'.freeze
|
54
|
+
|
55
|
+
# Server and port come from CLI opts or ruby-jss.conf
|
56
|
+
#
|
57
|
+
# User comes from CLI opt or keychain
|
58
|
+
#
|
59
|
+
# pw come from keychain, or is prompted and stored
|
60
|
+
# in keychain with user.
|
61
|
+
#
|
62
|
+
# TODO: support for other APIConnection options
|
63
|
+
#
|
64
|
+
OPTS = GetoptLong.new(
|
65
|
+
['--server', '-s', GetoptLong::REQUIRED_ARGUMENT],
|
66
|
+
['--port', '-p', GetoptLong::REQUIRED_ARGUMENT],
|
67
|
+
['--user', '-u', GetoptLong::REQUIRED_ARGUMENT],
|
68
|
+
['--db-server', '-S', GetoptLong::REQUIRED_ARGUMENT],
|
69
|
+
['--db-port', '-P', GetoptLong::REQUIRED_ARGUMENT],
|
70
|
+
['--db-user', '-U', GetoptLong::REQUIRED_ARGUMENT],
|
71
|
+
['--gem-dir', '-g', '-i', GetoptLong::REQUIRED_ARGUMENT],
|
72
|
+
['--saved-data', '-d', GetoptLong::NO_ARGUMENT],
|
73
|
+
['--help', '-h', '-H', GetoptLong::NO_ARGUMENT]
|
74
|
+
)
|
75
|
+
|
76
|
+
# Setup
|
77
|
+
def initialize
|
78
|
+
load_ruby_jss
|
79
|
+
parse_opts
|
80
|
+
|
81
|
+
@bindir = Pathname.new File.dirname(__FILE__)
|
82
|
+
@appdir = @bindir.parent
|
83
|
+
@libdir = @appdir + 'lib'
|
84
|
+
@specdir = @appdir + 'specs'
|
85
|
+
|
86
|
+
@tests_to_run = ARGV.dup
|
87
|
+
@tests_to_run = @specdir.children.map { |c| c.basename.to_s }.sort if @tests_to_run .empty?
|
88
|
+
|
89
|
+
@minitest_opts = ['--verbose']
|
90
|
+
|
91
|
+
helper_module = @libdir + 'testhelper.rb'
|
92
|
+
load helper_module.to_s
|
93
|
+
end # init
|
94
|
+
|
95
|
+
# Load the gem
|
96
|
+
def load_ruby_jss
|
97
|
+
if @custom_gem_dir
|
98
|
+
ENV['GEM_HOME'] = @custom_gem_dir
|
99
|
+
ENV['GEM_PATH'] = "#{@custom_gem_dir}:#{ENV['GEM_PATH']}"
|
100
|
+
Gem.paths = ENV
|
101
|
+
end
|
102
|
+
require 'ruby-jss'
|
103
|
+
end
|
104
|
+
|
105
|
+
# Parse ARGV
|
106
|
+
def parse_opts
|
107
|
+
OPTS.each do |opt, arg|
|
108
|
+
case opt
|
109
|
+
when '--server'
|
110
|
+
@api_server = arg
|
111
|
+
when '--user'
|
112
|
+
@api_user = arg
|
113
|
+
when '--port'
|
114
|
+
@api_port = arg
|
115
|
+
when '--db-server'
|
116
|
+
@db_server = arg
|
117
|
+
when '--db-user'
|
118
|
+
@db_user = arg
|
119
|
+
when '--db-port'
|
120
|
+
@db_port = arg
|
121
|
+
when '--gem-dir'
|
122
|
+
@custom_gem_dir = arg
|
123
|
+
when '--saved-data'
|
124
|
+
@show_saved_data = true
|
125
|
+
when '--help'
|
126
|
+
@show_help = true
|
127
|
+
end # case
|
128
|
+
end # opts.each
|
129
|
+
end
|
130
|
+
|
131
|
+
# the default values
|
132
|
+
def apply_defaults
|
133
|
+
@api_server ||= JSS::CONFIG.api_server_name
|
134
|
+
@api_port ||= JSS::CONFIG.api_server_port
|
135
|
+
@db_server ||= JSS::CONFIG.db_server_name
|
136
|
+
@db_port ||= JSS::CONFIG.db_server_port
|
137
|
+
end
|
138
|
+
|
139
|
+
def run
|
140
|
+
return if show_help
|
141
|
+
return if show_saved_data
|
142
|
+
connect_to_servers
|
143
|
+
return unless prod_server_confirmed_if_needed?
|
144
|
+
run_tests
|
145
|
+
end
|
146
|
+
|
147
|
+
# if @api_server == matches the one in /etc/ruby-jss.conf
|
148
|
+
# get confirmation before running tests on the production server.
|
149
|
+
# If a local ~/.ruby-jss.conf defines a diferent server,
|
150
|
+
# or a different server if given with --server, no confirmation is needed
|
151
|
+
def prod_server_confirmed_if_needed?
|
152
|
+
conf = Pathname.new '/etc/ruby-jss.conf'
|
153
|
+
return true unless conf.file?
|
154
|
+
|
155
|
+
prod_server_line = conf.readlines.select { |l| l.start_with? 'api_server_name' }.first
|
156
|
+
return true unless prod_server_line
|
157
|
+
|
158
|
+
prod_server = prod_server_line.chomp.split(': ').last
|
159
|
+
return true unless prod_server == @api_server
|
160
|
+
|
161
|
+
print "Really run the tests on the production server '#{prod_server}'? (y/n): "
|
162
|
+
doit = gets.chomp
|
163
|
+
doit == 'y'
|
164
|
+
end
|
165
|
+
|
166
|
+
def connect_to_servers
|
167
|
+
jss_keychain_creds = JSSTestHelper::Auth.rw_credentials_from_keychain(:jss)
|
168
|
+
if jss_keychain_creds
|
169
|
+
@api_server ||= jss_keychain_creds[:server]
|
170
|
+
@api_port ||= jss_keychain_creds[:port]
|
171
|
+
@api_user ||= jss_keychain_creds[:user]
|
172
|
+
pw = jss_keychain_creds[:pw]
|
173
|
+
else
|
174
|
+
apply_defaults
|
175
|
+
raise 'Please specify a server with --server' unless @api_server
|
176
|
+
raise 'Please specify a user with --user' unless @api_user
|
177
|
+
pw = 'nopw'
|
178
|
+
end
|
179
|
+
|
180
|
+
JSSTestHelper::Auth.connect_to_api(server: @api_server, port: @api_port, user: @api_user, pw: pw )
|
181
|
+
end
|
182
|
+
|
183
|
+
def run_tests
|
184
|
+
JSSTestHelper.say "Starting tests of ruby-jss v #{JSS::VERSION}"
|
185
|
+
JSSTestHelper.say "API Connection: #{@api_user}@#{@api_server}:#{@api_port} running Jamf Pro #{JSS.api.server.version}"
|
186
|
+
|
187
|
+
base_runnables = MiniTest::Runnable.runnables.dup
|
188
|
+
|
189
|
+
@tests_to_run.each do |t|
|
190
|
+
t += SPEC_SUFFIX unless t.end_with? SPEC_SUFFIX
|
191
|
+
specfile = @specdir + t
|
192
|
+
|
193
|
+
puts
|
194
|
+
|
195
|
+
if specfile.file?
|
196
|
+
JSSTestHelper.say "Running test #{specfile.basename}: "
|
197
|
+
load specfile.to_s
|
198
|
+
|
199
|
+
MiniTest.run @minitest_opts.dup
|
200
|
+
|
201
|
+
# clear this files specs from the run list..
|
202
|
+
MiniTest::Runnable.runnables.select! { |r| base_runnables.include? r }
|
203
|
+
puts
|
204
|
+
else
|
205
|
+
JSSTestHelper.say "Skipping unknown test #{specfile.basename}"
|
206
|
+
end # if
|
207
|
+
|
208
|
+
end # each
|
209
|
+
end # run tests
|
210
|
+
|
211
|
+
# display saved keychain data if asked
|
212
|
+
def show_saved_data
|
213
|
+
return false unless @show_saved_data
|
214
|
+
jss_keychain_creds = JSSTestHelper::Auth.rw_credentials_from_keychain(:jss)
|
215
|
+
msg =
|
216
|
+
if jss_keychain_creds
|
217
|
+
"JSS API Tests will run as user '#{jss_keychain_creds[:user]}' on server '#{jss_keychain_creds[:server]}', port #{jss_keychain_creds[:port]}"
|
218
|
+
else
|
219
|
+
'No JSS API credentials saved, please use --server, --user and --port (if needed)'
|
220
|
+
end
|
221
|
+
puts msg
|
222
|
+
true
|
223
|
+
end
|
224
|
+
|
225
|
+
# display help if asked
|
226
|
+
def show_help
|
227
|
+
return false unless @show_help
|
228
|
+
puts <<-USAGEBLURB
|
229
|
+
Usage: #{File.basename __FILE__} [options] [spec [spec ...]]
|
230
|
+
|
231
|
+
Runs one or more specification tests of ruby-jss.
|
232
|
+
|
233
|
+
The specifications are files in the directory:
|
234
|
+
#{@specdir}
|
235
|
+
|
236
|
+
The files must have a _spec.rb suffix, however you need not use the suffix when
|
237
|
+
listing tests to run on the command line, e.g. 'patch_source' will run
|
238
|
+
'patch_source_spec.rb'
|
239
|
+
|
240
|
+
If no specs files are listed on the command line, all will be run, in
|
241
|
+
alphabetical order.
|
242
|
+
|
243
|
+
By default, JSS connection settings are used from your /etc/ruby-jss.conf file
|
244
|
+
and/or ~/.ruby-jss.conf. Connection settings from the command line will be used
|
245
|
+
if provided.
|
246
|
+
|
247
|
+
WARNING: These tests create, modify, and delete objects in the JSS.
|
248
|
+
While no existing objects should be changed, * Be Careful * running them on
|
249
|
+
a production server.
|
250
|
+
If the server you're connecting to matches one defined in /etc/ruby-jss.conf
|
251
|
+
you will be asked for confirmation before proceding.
|
252
|
+
|
253
|
+
The first time you connect from this machine to a given server, you must provide
|
254
|
+
a username for the connection with --user, and will be prompted for the password.
|
255
|
+
Once authenticated, credentials for the server are saved in your keychain, and
|
256
|
+
future connections to that server will read the user & password from there.
|
257
|
+
If a different user is later specified for that server, you'll be prompted again
|
258
|
+
for a password, and the keychain will be updated.
|
259
|
+
|
260
|
+
Options
|
261
|
+
--server, -s <host> the hostname for the JSS API connection
|
262
|
+
--port, -p <port> the port for the API connection
|
263
|
+
--user, -u <user> the API username for the connection
|
264
|
+
NOTE: must have permissions to perform the tests!
|
265
|
+
--db-server, -S <host> the hostname for the JSS API connection
|
266
|
+
--db-port, -P <port> the port for the API connectino
|
267
|
+
--db-user, -U <user> the API username for the connection
|
268
|
+
--gem-dir, -g, -i <path> the path from which to require ruby-jss
|
269
|
+
(sets GEM_HOME to this path before requiring)
|
270
|
+
--saved-data, -d show the connection data saved in the keychain,
|
271
|
+
if any. (no tests run, password not shown)
|
272
|
+
--help, -h, -H show this help
|
273
|
+
USAGEBLURB
|
274
|
+
true
|
275
|
+
end # show_help
|
276
|
+
|
277
|
+
end # class app
|
278
|
+
|
279
|
+
################# The main block ########################
|
280
|
+
if $PROGRAM_NAME == __FILE__
|
281
|
+
begin
|
282
|
+
app = App.new
|
283
|
+
app.run
|
284
|
+
exit 0
|
285
|
+
rescue => the_exception
|
286
|
+
warn "An error occurred: #{the_exception.message}"
|
287
|
+
warn the_exception.backtrace
|
288
|
+
exit 1
|
289
|
+
end # begin
|
290
|
+
end # if $0 == __FILE__
|