taft 0.1.0 → 0.2.4

Sign up to get free protection for your applications and to get access to all the features.
Files changed (29) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +9 -3
  3. data/examples/ruby/rs/framework/red_sky.rb +11 -0
  4. data/examples/ruby/rs/framework/red_sky/api_helpers/general.rb +140 -0
  5. data/examples/ruby/rs/framework/red_sky/api_helpers/rest.rb +249 -0
  6. data/examples/ruby/rs/framework/red_sky/ui_helpers/ui_general.rb +36 -0
  7. data/examples/ruby/rs/framework/red_sky/watir/custom/all.rb +4 -0
  8. data/examples/ruby/rs/framework/red_sky/watir/custom/rs_custom.rb +32 -0
  9. data/examples/ruby/rs/framework/red_sky/watir/pages/page_objects.rb +166 -0
  10. data/examples/ruby/rs/framework/red_sky/watir/pages/rs_pages.rb +68 -0
  11. data/examples/ruby/rs/lib/config/red_sky_config.rb +27 -0
  12. data/examples/ruby/rs/lib/config/runtime_constants.rb +20 -0
  13. data/examples/ruby/rs/lib/red_sky_test_case.rb +218 -0
  14. data/examples/ruby/rs/tests/v1/tc_r001_01_an_example_test.rb +112 -0
  15. data/examples/ruby/rs/tests/v1/tc_r001_01_google_search.rb +64 -0
  16. data/lib/taft.rb +2 -0
  17. data/lib/taft_files/framework/zznamezz.rb +3 -0
  18. data/lib/taft_files/framework/zznamezz/api_helpers/general.rb +13 -13
  19. data/lib/taft_files/framework/zznamezz/ui_helpers/ui_general.rb +26 -0
  20. data/lib/taft_files/framework/zznamezz/watir/custom/all.rb +4 -0
  21. data/lib/taft_files/framework/zznamezz/watir/custom/xxabbrevxx_custom.rb +32 -0
  22. data/lib/taft_files/framework/zznamezz/watir/pages/page_objects.rb +166 -0
  23. data/lib/taft_files/framework/zznamezz/watir/pages/xxabbrevxx_pages.rb +101 -0
  24. data/lib/taft_files/lib/config/runtime_constants.rb +5 -1
  25. data/lib/taft_files/lib/config/zznamezz_config.rb +7 -2
  26. data/lib/taft_files/lib/zznamezz_test_case.rb +43 -42
  27. data/lib/taft_files/tests/v1/tc_r001_01_an_example_test.rb +1 -1
  28. data/taft.gemspec +5 -5
  29. metadata +23 -6
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: bd9ae23e1324c24c5a99e25a21858ea93ade0f8f1993379501fdfaf76c67ea19
4
- data.tar.gz: 5efce5a842f8a21f3b9c75a3a8edce0211aab23ac006f683fb7a562f1193ab31
3
+ metadata.gz: '0796c9a982c5849970634d3ce2e2838a76816694f12f26089089a7ca4a23098c'
4
+ data.tar.gz: 86e5aa8c9eec54af5025edd76c95e2fd1374fdb8839e7ab437842e8d6c48a0d1
5
5
  SHA512:
6
- metadata.gz: b4cc3d8926584f3b14c60f99475c85c5ecdb9265a1d2258c4b9e827037b8bdb25f640ab944fd309bfbb7c40f84da3c4a9237424ce8e390f540b324b18f07c37b
7
- data.tar.gz: cf13e673c7f5d6abb4594e42ab55006a3adad34492b3b7bae2f9e9e1bae6f1be702c97e446e6f47820de837fcfa803bff83cf4c4c974b245f8e72879bdeac6b1
6
+ metadata.gz: 7ebec6f4f7bf92bf2da2454a88c9d9c38eed7495e960618a0087f3cace1fd9a1941610620e2b0b249aa75614d5a5adbb8f3569bd8e93c468f5b9bfb5154dd3a1
7
+ data.tar.gz: 4d20ab7b94790bcffc53ea9065a00c856d4e313ab410dbd4d184d5ce27c64fdecbd45a14c44eb3a6d42db802450af913bb1b66dc43ab487570c018473037504d
data/README.md CHANGED
@@ -1,4 +1,4 @@
1
- ### Test Automation Framework Template
1
+ # Test Automation Framework Template (TAFT)
2
2
 
3
3
  This gem will deploy/install a skeleton code framework for the automated testing of applications with APIs and/or web-UIs.
4
4
 
@@ -7,11 +7,17 @@ Languages : Ruby
7
7
  ## How to use
8
8
 
9
9
  Command line : `ruby -e "require 'taft'; Taft.install"`
10
+ This will prompt you for all pertinent parameters.
10
11
 
12
+ ## Post-deployment
11
13
 
14
+ TAFT deploys a skeleton code framework that attempts to cover several common test areas. These often include the use of additional libraries. To reduce deployment bloat, TAFT will **not** attempt to install those additional libraries. You must install them yourself (using your preferred lib-manager), or deactivate the skeleton code that calls these libraries.
12
15
 
13
16
 
17
+ ## Example code
18
+
19
+ `examples/[language]` contains an example codebase generated from TAFT.
20
+
14
21
  ## TODO
15
22
 
16
- * More languages : Java
17
- * Ruby installation will also install some gems (bundled within TAFT)
23
+ * More languages : Java, Python, Golang
@@ -0,0 +1,11 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+
3
+ # Add a require line for every file within framework/red_sky
4
+
5
+ require "red_sky/api_helpers/general"
6
+ require "red_sky/api_helpers/rest"
7
+
8
+ require "red_sky/ui_helpers/ui_general"
9
+
10
+ require "red_sky/watir/pages/rs_pages"
11
+ require "red_sky/watir/custom/all"
@@ -0,0 +1,140 @@
1
+ require "test/unit/assertions" # required for the assert_ methods
2
+
3
+ require "json-schema"
4
+ require "avro"
5
+ require "csv"
6
+ require "net/ssh"
7
+ require "net/sftp"
8
+ require "more_ruby"
9
+
10
+
11
+ class RSHelper
12
+ include Test::Unit::Assertions
13
+
14
+ # E.g. calling homepage.displayed? from a test script :
15
+ # Test cannot see homepage so its call is routed through method_missing
16
+ # If method_missing returns an instance of the class, .displayed? can be called on it (seamlessly)
17
+ # At present this will happen for every call to a page from a test script
18
+ def method_missing(name, *args, &block)
19
+ #puts "RSHelper method_missing called; name = #{name.inspect}; #{name.class}"
20
+
21
+ case name.to_s
22
+ when /^rs/i, /^google/
23
+ RSPages.find(name.to_s) # return the page so that the helper-method can use it
24
+ else
25
+ super
26
+ end
27
+ end
28
+
29
+ # Reads in a file of CSV test data, e.g for use in data-driven tests
30
+ def read_csv_test_data(filename)
31
+ path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../../tests/data", filename)
32
+ read_csv_data_from_file(path)
33
+ end
34
+
35
+ # Reads in a CSV
36
+ def read_csv_data_from_file(full_file_path)
37
+ data = []
38
+ CSV.open(full_file_path, "r") do |csv|
39
+ data = csv.readlines
40
+ end
41
+ data
42
+ end
43
+
44
+ # Reads in a JSON schema
45
+ def read_json_schema(schema_filename)
46
+ path = File.join(File.dirname(File.expand_path(__FILE__)) + "/../../../../tests/data", schema_filename)
47
+ data = []
48
+ File.open(path, "r") do |f|
49
+ data = f.readlines
50
+ end
51
+ schema = JSON.parse(data.chomp) # there may be trailing whitespace
52
+ schema
53
+ end
54
+
55
+ # Reads in a serialised AVRO file
56
+ # Returns an array of the deserialised data rows
57
+ def read_avro_file(filename)
58
+ lines = []
59
+ File.open(path, "rb") do |f|
60
+ reader = Avro::IO::DatumReader.new
61
+ dr = Avro::DataFile::Reader.new(f, reader)
62
+ dr.each do |record|
63
+ lines << record
64
+ end
65
+ end
66
+ lines
67
+ end
68
+
69
+ # Validates the supplied hash against the JSON schema
70
+ def validate_hash_against_json_schema(hash, schema_filename)
71
+ raise "Must supply a hash to #{__method__}" unless hash.class == Hash
72
+
73
+ schema = read_json_schema(schema_filename)
74
+ errors = JSON::Validator.fully_validate(schema, hash)
75
+ errors
76
+ end
77
+
78
+ # Calls the build_number REST method
79
+ # This is an example of how to use get_rest_client
80
+ def get_version_number_from_api(cert_symbol = :regular)
81
+ client = get_rest_client(:build_number, cert_symbol)
82
+ json = client.get # {"message":"1.8.0"}
83
+ parsed = JSON.parse(json)
84
+ parsed["message"]
85
+ end
86
+
87
+ # Forms a .tar.gz archive from the specified source file
88
+ # Creates the file in the working directory
89
+ # Creates the .tar.gz via a call to system
90
+ def create_tar_gz_file(gz_base_file_name, source_file)
91
+ gz_name = "#{gz_base_file_name}.tar.gz"
92
+ cmd = "tar -czf #{gz_name} #{source_file}"
93
+ system(cmd)
94
+ gz_name
95
+ end
96
+
97
+ # Renames the specified file on the Linux server
98
+ # Needs the full path
99
+ def rename_linux_file(old_file, new_file, cert_symbol = :regular)
100
+ # Derive the FTP host & path from the URL in config
101
+ host = RedSkyConfig::SERVER[:red_sky_url].split("//")[1].split(":")[0]
102
+ host_short_form = host.split(".")[0]
103
+ user = get_user_id(cert_symbol)
104
+ pass = get_user_cert_pw(cert_symbol)
105
+
106
+ Net::SFTP.start(host, user, :password => pass) do |sftp|
107
+ puts "Renaming file : #{old_file} -> #{new_file}"
108
+ sftp.rename(old_file, new_file)
109
+ end
110
+ end
111
+
112
+ # Sets 777 permissions to the Linux server file
113
+ # Need the file name & dir
114
+ def chmod_linux_file(host, user, pass, path, file_name)
115
+ Net::SSH.start(host, user, :password => pass) do |ssh|
116
+ ssh.exec!("cd #{path}; chmod 777 #{file_name}")
117
+ end
118
+ end
119
+
120
+ # Executes the supplied curl command on the server
121
+ def submit_curl_command(cmd, cert_symbol = :regular)
122
+ # Derive the FTP host & path from the URL in config
123
+ host = RedSkyConfig::SERVER[:red_sky_url].split("//")[1].split(":")[0]
124
+ host_short_form = host.split(".")[0]
125
+ user = get_user_id(cert_symbol)
126
+ pass = get_user_cert_pw(cert_symbol)
127
+
128
+ output = ""
129
+ Net::SSH.start(host, user, :password => pass) do |ssh|
130
+ output = ssh.exec!(cmd)
131
+ end
132
+
133
+ # We expect a JSON response from the server
134
+ # The recorded output will contain this inside curl's own SDTOUT, so we need to extract the JSON
135
+ output = output[output.index("{") .. output.index("}")]
136
+ JSON.parse(output)
137
+ end
138
+
139
+
140
+ end
@@ -0,0 +1,249 @@
1
+ require "rest_client"
2
+ require "uri"
3
+ require "openssl"
4
+ require "json"
5
+
6
+ # File contains methods conductive to the execution of tests and scripts that call REST interfaces
7
+
8
+
9
+ class RSHelper
10
+
11
+ # Returns a RestClient::Resource object pointing to the URL of the requested service
12
+ def get_rest_client(service, cert_symbol = :regular, parameter_array_or_hash = [], base_url = RedSkyConfig::SERVER[:red_sky_url], version = nil, timeout = 150)
13
+
14
+ separator = "/"
15
+ api_version_string = separator + RedSkyConfig::API_VERSION.to_s # as the version parameter can be entirely absent, let's build the separator into the term
16
+ api_version_string = "" if RedSkyConfig::API_VERSION == :none # special case
17
+
18
+ api_version_string = separator + version if version # override always wins
19
+
20
+ parameter_array_or_hash = [parameter_array_or_hash] if parameter_array_or_hash.class != Array && parameter_array_or_hash.class != Hash # convert to array if a non-array/hash was supplied
21
+
22
+ # If common headers are needed
23
+ # headers = {"foo" => bar}
24
+
25
+ # Build up the path-string, then append it to the base URL
26
+ s = "" # initialise before manipulating it
27
+
28
+ if service.class == String
29
+ s = service
30
+ else
31
+ case service
32
+ when :options
33
+ s = "options#{api_version_string}"
34
+ s += "/#{parameter_array_or_hash[0]}"
35
+ when :build_number
36
+ s = "query/info#{api_version_string}/buildnumber"
37
+ else
38
+ raise "Unknown service #{service} supplied to #{__method__}"
39
+ end
40
+ end
41
+
42
+ encoded = encode_uri(s).to_s # Generates a URI::Generic object; we want a string
43
+ url = base_url + encoded
44
+
45
+ puts url
46
+
47
+ #######################################################
48
+ # Get certificate and other parameters needed for valid credentials
49
+ #######################################################
50
+
51
+ OpenSSL::SSL::SSLContext::DEFAULT_PARAMS[:ssl_version] = "SSLv3" # this may or may not be needed
52
+
53
+ cert_path = File.expand_path(RedSkyConfig::CERTIFICATE_DIR) # this must be an absolute filepath
54
+ cert_extension = get_user_cert_ext(cert_symbol).to_s
55
+
56
+ cert_name = get_user_p12_cert_name(cert_symbol)
57
+ cert_pw = get_user_cert_pw(cert_symbol)
58
+
59
+ # ca_file = RedSkyConfig::CA_CERTIFICATE_FILE # needed for VERIFY_PEER mode # VERIFY_PEER mode currently disabled
60
+
61
+ if cert_extension.to_sym == :pem
62
+ # If PEM, the credentials are in two parts - the certs.pem file and the key.pem file
63
+ # Need to read in the two separate files & construct OpenSSL::X509::Certificate & OpenSSL::PKey::RSA objects
64
+ cert_key_name = get_user_pem_cert_key_name(cert_symbol)
65
+ cert_key_pw = get_user_cert_key_pw(cert_symbol)
66
+ pem = File.read(File.join(cert_path, cert_name))
67
+ key_pem = File.read(File.join(cert_path, cert_key_name))
68
+
69
+ cert = OpenSSL::X509::Certificate.new(pem)
70
+
71
+ begin
72
+ key = OpenSSL::PKey::RSA.new(key_pem, cert_key_pw)
73
+ rescue
74
+ raise "Could not form OpenSSL::PKey::RSA object for the corresponding key.pem file. Does it have the right password?"
75
+ end
76
+ return RestClient::Resource.new(url, {:ssl_client_cert => cert, :ssl_client_key => key, :verify_ssl => OpenSSL::SSL::VERIFY_NONE, :timeout => timeout})
77
+ else
78
+ # If P12 or PFX, only need to construct the one object - the certificate and key are both stored within it
79
+ begin
80
+ p12 = OpenSSL::PKCS12.new(File.read(File.join(cert_path, cert_name), :binmode => true), cert_pw)
81
+ rescue OpenSSL::PKCS12::PKCS12Error => e
82
+ if e.to_s.include?("mac verify failure")
83
+ raise "Could not create PKCS12 object from certificate #{cert_name}; please specify a password for the certificate"
84
+ else
85
+ raise e
86
+ end
87
+ end
88
+
89
+ # Use if performing SSL Peer verification - needs a ca certificate
90
+ return RestClient::Resource.new(url, {:ssl_client_cert => p12.certificate, :ssl_client_key => p12.key, :ssl_ca_file => ca_file, :verify_ssl => OpenSSL::SSL::VERIFY_PEER, :headers => headers, :timeout => timeout})
91
+
92
+ # Use if not performing SSL Peer verification - does not need a ca certificate
93
+ return RestClient::Resource.new(url, {:ssl_client_cert => p12.certificate, :ssl_client_key => p12.key, :verify_ssl => OpenSSL::SSL::VERIFY_NONE, :timeout => timeout})
94
+ end
95
+
96
+ end
97
+
98
+ # Method to encode the URI
99
+ # Takes a string or an array of path fragments. If an array, the contents will be joined using / characters
100
+ def encode_uri(uri)
101
+ uri = uri.join("/") if uri.class == Array
102
+ additional_encoding(URI.parse(URI.encode(uri)).to_s)
103
+ end
104
+
105
+
106
+ # Method to perform additional encoding
107
+ # URI.encode does not convert the following chars: : +
108
+ def additional_encoding(s)
109
+ encoding_hash = {":" => "%3A", "+" => "%2B"}
110
+ encoding_hash.each_pair do |k, v|
111
+ s.gsub!(k, v)
112
+ end
113
+ s
114
+ end
115
+
116
+ # Converts a string or int representing the number of microseconds since the Time epoch (1970/01/01) into a DateTime object
117
+ def read_epoch_time(microseconds_since_epoch)
118
+ Time.at(microseconds_since_epoch.to_i/1000)
119
+ end
120
+
121
+ # Converts the body of the response object from JSON to Ruby, and sets the defaults for the main hash and all sub-hashes
122
+ def get_response_body(response)
123
+ raise "REST response was nil" if response == nil
124
+ raise "REST response had no attached body" if response.body == nil
125
+ begin
126
+ body = JSON.parse(response.body, {:max_nesting => 100})
127
+ set_all_defaults(body)
128
+ rescue JSON::ParserError => e
129
+ puts "rescued : ParserError"
130
+ puts e
131
+ body = response.body
132
+ end
133
+ body
134
+ end
135
+
136
+
137
+ # Converts the header of the response object from JSON to Ruby, and sets the defaults for the main hash and all sub-hashes
138
+ def get_response_header(response)
139
+ raise "REST response was nil" if response == nil
140
+ raise "REST response had no attached header" if response.headers == nil
141
+ begin
142
+ header = response.headers # already in Ruby Hash format
143
+ set_all_defaults(body)
144
+ rescue JSON::ParserError => e
145
+ puts "rescued : ParserError"
146
+ puts e
147
+ header = response.headers
148
+ end
149
+ header
150
+ end
151
+
152
+ # Takes a hash a recursively sets the default of the hash and all sub-hashes
153
+ def set_all_defaults(hash, default = nil)
154
+ return unless hash.class == Hash
155
+ hash.default = default
156
+ hash.each_pair do |k, v|
157
+ set_all_defaults(v) if v.class == Hash
158
+ if v.class == Array
159
+ v.each {|z| set_all_defaults(z) if z.class == Hash}
160
+ end
161
+ end
162
+ end
163
+
164
+ # Method to perform a POST request. Requires the RESTClient Resource client and a hash of the information to be sent in the POST body. This hash is converted to JSON for the POST.
165
+ # Optionally also takes an additional hash which contains desired headers for the POST request.
166
+ # Returns a RESTClient::Response object
167
+ def post_request(client, post_information_hash, additional_hash = nil)
168
+ new_hash = {:content_type => "application/json"}
169
+ additional_hash ||= {}
170
+ new_hash.merge!(additional_hash)
171
+
172
+ begin
173
+ client.post(JSON.generate(post_information_hash, {:max_nesting => 100}), new_hash)
174
+ rescue OpenSSL::SSL::SSLError => e
175
+ raise "SSLError occurred when calling REST service; #{e}"
176
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
177
+ puts "RestClient::Exception hit when calling REST service"
178
+ puts e
179
+ puts e.response
180
+ return e.response
181
+ rescue => e
182
+ raise "Unexpected error occurred when calling REST service; #{e}"
183
+ end
184
+ end
185
+
186
+ # Method to perform a POST request that sends a file. Requires the RESTClient Resource client and a hash of the information to be sent in the POST body.
187
+ # Assumes that all file information (including the File object itself) is included in the supplied hash
188
+ # Optionally also takes an additional hash which contains desired headers for the POST request.
189
+ # Returns a RESTClient::Response object
190
+ def post_file_request(client, post_information_hash, additional_hash = nil)
191
+ new_hash = {}
192
+ additional_hash ||= {}
193
+ new_hash.merge!(additional_hash)
194
+
195
+ begin
196
+ client.post(post_information_hash, new_hash)
197
+ rescue OpenSSL::SSL::SSLError => e
198
+ raise "SSLError occurred when calling REST service; #{e}"
199
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
200
+ puts "RestClient::Exception hit when calling REST service"
201
+ puts e
202
+ puts e.response
203
+ return e.response
204
+ rescue => e
205
+ raise "Unexpected error occurred when calling REST service; #{e}"
206
+ end
207
+ end
208
+
209
+
210
+ # Method to perform a PUT request. Requires the RESTClient Resource client and a hash of the information to be sent in the PUT body. This hash is converted to JSON for the PUT.
211
+ # Optionally also takes an additional hash which contains desired headers for the PUT request, e.g. {:content_type => "application/json"}
212
+ # Returns a RESTClient::Response object
213
+ def put_request(client, put_information_hash, additional_hash = nil)
214
+ new_hash = {:content_type => "application/json"}
215
+ additional_hash ||= {}
216
+ new_hash.merge!(additional_hash)
217
+
218
+ begin
219
+ client.put(JSON.generate(put_information_hash, {:max_nesting => 100}), new_hash)
220
+ rescue OpenSSL::SSL::SSLError => e
221
+ raise "SSLError occurred when calling REST service; #{e}"
222
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
223
+ puts "RestClient::Exception hit when calling REST service"
224
+ puts e
225
+ puts e.response
226
+ return e.response
227
+ rescue => e
228
+ raise "Unexpected error occurred when calling REST service; #{e}"
229
+ end
230
+ end
231
+
232
+
233
+ # Method to perform a DELETE request. Requires the RESTClient Resource client.
234
+ # Returns a RESTClient::Response object
235
+ def delete_request(client)
236
+ begin
237
+ client.delete
238
+ rescue OpenSSL::SSL::SSLError => e
239
+ raise "SSLError occurred when calling REST service; #{e}"
240
+ rescue RestClient::Exception => e # if the request failed, RestClient will throw an error. We want to retrieve that error and the response within
241
+ puts "RestClient::Exception hit when calling REST service"
242
+ puts e
243
+ puts e.response
244
+ return e.response
245
+ rescue => e
246
+ raise "Unexpected error occurred when calling REST service; #{e}"
247
+ end
248
+ end
249
+ end
@@ -0,0 +1,36 @@
1
+
2
+ class RSHelper
3
+
4
+ def new_browser_at_url(url)
5
+ puts "New browser at #{url}"
6
+ case RedSkyConfig::BROWSER
7
+ when :chrome
8
+ # Set detach to true so the browser remains open once the test finishes
9
+ options = Selenium::WebDriver::Chrome::Options.new
10
+ options.add_option(:detach, true)
11
+ b = Watir::Browser.new :chrome, :options => options
12
+
13
+ when :firefox
14
+ b = Watir::Browser.new :firefox
15
+
16
+ end
17
+
18
+ b.goto url
19
+
20
+ # Store the new browser in the global list
21
+ $browsers << b
22
+
23
+ b # return the browser
24
+ end
25
+
26
+ def ui_helper_test
27
+ puts "in #{__method__}"
28
+ end
29
+
30
+ # Simple method to show that @help can access the browser
31
+ def enter_google_term(term)
32
+ googleSearch.search_term = term
33
+ puts "@help set term"
34
+ end
35
+
36
+ end