roku_builder 4.27.2 → 4.29.1
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.
- checksums.yaml +4 -4
- data/lib/roku_builder/config.rb +2 -2
- data/lib/roku_builder/config_parser.rb +5 -0
- data/lib/roku_builder/config_validator.rb +9 -2
- data/lib/roku_builder/plugins/loader.rb +1 -1
- data/lib/roku_builder/plugins/monitor.rb +1 -1
- data/lib/roku_builder/plugins/packager.rb +1 -1
- data/lib/roku_builder/plugins/rokuapi.rb +184 -0
- data/lib/roku_builder/version.rb +1 -1
- data/lib/roku_builder.rb +3 -0
- data/roku_builder.gemspec +1 -0
- data/test/roku_builder/plugins/test_analyzer.rb +1 -2
- data/test/roku_builder/plugins/test_core.rb +0 -2
- data/test/roku_builder/plugins/test_loader.rb +1 -1
- data/test/roku_builder/plugins/test_rokuapi.rb +557 -0
- data/test/roku_builder/test_config_parser.rb +16 -0
- data/test/roku_builder/test_config_validator.rb +14 -0
- data/test/roku_builder/test_device_manager.rb +4 -4
- data/test/roku_builder/test_files/roku_api_test/test.pkg +0 -0
- data/test/roku_builder/test_files/roku_api_test/test_key.json +13 -0
- data/test/roku_builder/test_helper.rb +66 -43
- data/test/roku_builder/test_ruby_git.rb +6 -6
- metadata +23 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: a74435c26dad5e136130516be10f397638bb374f4f105a8ca25c438193b39151
|
4
|
+
data.tar.gz: 1fa12ee0b271ae1506b5d3ffe028da016fbafa208eee996b6f9fbedd5dbb3a0e
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: a7a74b63df763ff355473e8f1d5e90c80ea0805c8539edf43d189199876ebf7fd801322e45020ae9192c888c53e9de39f2e23d2ebe95ce581a4e0016fb2db493
|
7
|
+
data.tar.gz: 202e8b749f4b0aa46d6a0ebd18aabae4a3c486214d5945b823e1cc897b0a36a1ed3d351c07f0e49bf89e612df92bed68d860d3b1797ff89a92af63a9c3bd8313
|
data/lib/roku_builder/config.rb
CHANGED
@@ -23,7 +23,8 @@ module RokuBuilder
|
|
23
23
|
load_config
|
24
24
|
end
|
25
25
|
|
26
|
-
def parse(stage: nil)
|
26
|
+
def parse(stage: nil, options: nil)
|
27
|
+
@options = options if options
|
27
28
|
@options[:stage] = stage if stage
|
28
29
|
@parsed = ConfigParser.parse(options: @options, config: @config)
|
29
30
|
end
|
@@ -126,7 +127,6 @@ module RokuBuilder
|
|
126
127
|
if File.exist?(local_config_path) and !@loaded_configs.include?(File.expand_path(local_config_path))
|
127
128
|
local_config_hash = read_config(File.open(local_config_path))
|
128
129
|
add_missing_directories(local_config_hash)
|
129
|
-
local_sub_configs = "./.roku_config/*.json"
|
130
130
|
@config = @config.deep_merge(local_config_hash)
|
131
131
|
Dir.glob("./.roku_config/*.json").each do |sub_config_path|
|
132
132
|
sub_config_hash = read_config(File.open(sub_config_path))
|
@@ -22,6 +22,7 @@ module RokuBuilder
|
|
22
22
|
def parse_config
|
23
23
|
process_in_argument
|
24
24
|
setup_devices
|
25
|
+
setup_api_keys
|
25
26
|
setup_project
|
26
27
|
setup_in_out_file
|
27
28
|
setup_project_config
|
@@ -41,6 +42,10 @@ module RokuBuilder
|
|
41
42
|
@parsed[:devices] = @config[:devices].select{|key, value| :default != key}
|
42
43
|
end
|
43
44
|
|
45
|
+
def setup_api_keys
|
46
|
+
@parsed[:api_keys] = @config[:api_keys]
|
47
|
+
end
|
48
|
+
|
44
49
|
def setup_project
|
45
50
|
if project_required and not @options[:project]
|
46
51
|
project = current_project
|
@@ -26,7 +26,7 @@ module RokuBuilder
|
|
26
26
|
KEY_MISSING_PATH = 19
|
27
27
|
KEY_MISSING_PASSWORD = 20
|
28
28
|
INVALID_MAPPING_INFO = 21
|
29
|
-
|
29
|
+
INVALID_API_KEY = 22
|
30
30
|
MISSING_STAGE_METHOD = 23
|
31
31
|
|
32
32
|
def initialize(config:)
|
@@ -63,7 +63,7 @@ module RokuBuilder
|
|
63
63
|
def validate_config
|
64
64
|
@codes = []
|
65
65
|
validate_structure
|
66
|
-
[:projects, :devices, :keys, :input_mappings].each do |section|
|
66
|
+
[:projects, :devices, :keys, :input_mappings, :api_keys].each do |section|
|
67
67
|
validate_section(section: section) if @config[section]
|
68
68
|
end
|
69
69
|
@codes.uniq!
|
@@ -174,6 +174,13 @@ module RokuBuilder
|
|
174
174
|
process_errors(errors: errors)
|
175
175
|
end
|
176
176
|
|
177
|
+
def validate_api_key(api_key:)
|
178
|
+
errors = [
|
179
|
+
[INVALID_API_KEY, (api_key.class != String)]
|
180
|
+
]
|
181
|
+
process_errors(errors: errors)
|
182
|
+
end
|
183
|
+
|
177
184
|
def process_errors(errors:)
|
178
185
|
errors.each do |error|
|
179
186
|
@codes.push(error[0]) if error[1]
|
@@ -115,7 +115,7 @@ module RokuBuilder
|
|
115
115
|
multipart_connection(device: device) do |conn|
|
116
116
|
response = conn.post "/plugin_install", payload
|
117
117
|
end
|
118
|
-
unless response.status == 200 and response.body =~ /
|
118
|
+
unless response.status == 200 and response.body =~ /Conversion succeeded/ or ignoreFailure
|
119
119
|
raise ExecutionError, "Failed Converting to Squashfs"
|
120
120
|
end
|
121
121
|
end
|
@@ -135,7 +135,7 @@ module RokuBuilder
|
|
135
135
|
# @param txt [String] current string from telnet
|
136
136
|
# @param regexp [Regexp] regular expression to filter text on
|
137
137
|
# @return [String] remaining partial line text
|
138
|
-
def manage_text(all_text:, txt:, regexp: nil, logging: false, logfile:)
|
138
|
+
def manage_text(all_text:, txt:, regexp: nil, logging: false, logfile: nil)
|
139
139
|
raise ExecutionError, "Connection Closed" unless txt
|
140
140
|
if /connection is already in use/ =~ txt
|
141
141
|
raise ExecutionError, "Connection is in use"
|
@@ -82,7 +82,7 @@ module RokuBuilder
|
|
82
82
|
get_device(device: device) do |device|
|
83
83
|
oldId = dev_id(device: device)
|
84
84
|
|
85
|
-
raise ExecutionError, "
|
85
|
+
raise ExecutionError, "No Key Found For Stage #{options[:stage]}" unless @config.key
|
86
86
|
|
87
87
|
# upload new key with password
|
88
88
|
payload = {
|
@@ -0,0 +1,184 @@
|
|
1
|
+
# ********** Copyright Viacom, Inc. Apache 2.0 **********
|
2
|
+
|
3
|
+
module RokuBuilder
|
4
|
+
|
5
|
+
# Load/Unload/Build roku applications
|
6
|
+
class RokuAPI < Util
|
7
|
+
extend Plugin
|
8
|
+
|
9
|
+
HOST = "https://apipub.roku.com"
|
10
|
+
|
11
|
+
def init
|
12
|
+
end
|
13
|
+
|
14
|
+
def self.commands
|
15
|
+
{
|
16
|
+
submit: {source: false},
|
17
|
+
publish: {}
|
18
|
+
}
|
19
|
+
end
|
20
|
+
|
21
|
+
def self.parse_options(parser:, options:)
|
22
|
+
parser.separator "Commands:"
|
23
|
+
parser.on("--submit", 'Submit a package to the Roku Portal') do
|
24
|
+
options[:submit] = true
|
25
|
+
end
|
26
|
+
parser.on("--publish", 'Publish an app on the Roku Portal') do
|
27
|
+
options[:publish] = true
|
28
|
+
end
|
29
|
+
parser.separator "Options:"
|
30
|
+
parser.on("--channel-id ID", 'ID of the channel to submit to/publish') do |id|
|
31
|
+
options[:channel_id] = id
|
32
|
+
end
|
33
|
+
parser.on("--api-key KEY", 'The API key to use to submit/publish') do |key|
|
34
|
+
options[:api_key] = key
|
35
|
+
end
|
36
|
+
parser.on("--no-publish", 'Prevent the channel from being automatically published when submitted') do
|
37
|
+
options[:no_publish] = true
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def self.dependencies
|
42
|
+
[]
|
43
|
+
end
|
44
|
+
|
45
|
+
def submit(options:)
|
46
|
+
raise RokuBuilder::InvalidOptions, "Missing channel id" unless options[:channel_id]
|
47
|
+
@logger.info "Submit to channel #{options[:channel_id]}"
|
48
|
+
@api_key = options[:api_key]
|
49
|
+
@no_publish = !!options[:no_publish]
|
50
|
+
response = get_channel_versions(options[:channel_id])
|
51
|
+
if response.first["channelState"] == "Unpublished"
|
52
|
+
response = update_channel_version(options[:channel_id], get_package(options), response.last["id"])
|
53
|
+
else
|
54
|
+
response = create_channel_version(options[:channel_id], get_package(options))
|
55
|
+
end
|
56
|
+
raise RokuBuilder::ExecutionError, "Request failed: #{response.reason_phrase}" unless response.success?
|
57
|
+
JSON.parse(response.body)
|
58
|
+
end
|
59
|
+
|
60
|
+
def publish(options:)
|
61
|
+
raise RokuBuilder::InvalidOptions, "Missing channel id" unless options[:channel_id]
|
62
|
+
@logger.info "Publish to channel #{options[:channel_id]}"
|
63
|
+
@api_key = options[:api_key]
|
64
|
+
response = get_channel_versions(options[:channel_id])
|
65
|
+
raise RokuBuilder::ExecutionError unless response.first["channelState"] == "Unpublished"
|
66
|
+
response = publish_channel_version(options[:channel_id], response.first["id"])
|
67
|
+
raise RokuBuilder::ExecutionError, "Request failed: #{response.reason_phrase}" unless response.success?
|
68
|
+
JSON.parse(response.body)
|
69
|
+
end
|
70
|
+
|
71
|
+
private
|
72
|
+
|
73
|
+
def get_package(options)
|
74
|
+
File.open(options[:in])
|
75
|
+
end
|
76
|
+
|
77
|
+
def api_path
|
78
|
+
"/developer/v1"
|
79
|
+
end
|
80
|
+
|
81
|
+
def get_channel_versions(channel)
|
82
|
+
path = "/external/channels/#{channel}/versions"
|
83
|
+
response = api_get(path)
|
84
|
+
sorted_versions(JSON.parse(response.body))
|
85
|
+
end
|
86
|
+
|
87
|
+
def sorted_versions(versions)
|
88
|
+
sorted = versions.sort do |a, b|
|
89
|
+
aa, ab = a["version"].split(".").map{|i| i.to_i}
|
90
|
+
ba, bb = b["version"].split(".").map{|i| i.to_i}
|
91
|
+
value = (aa == ba ? bb <=> ab : ba <=> aa)
|
92
|
+
value
|
93
|
+
end
|
94
|
+
sorted
|
95
|
+
end
|
96
|
+
|
97
|
+
def create_channel_version(channel, package)
|
98
|
+
path = "/external/channels/#{channel}/versions"
|
99
|
+
params = nil
|
100
|
+
unless @no_publish
|
101
|
+
params = {"channelState" => "Published"}
|
102
|
+
end
|
103
|
+
api_post(path, path, package, params)
|
104
|
+
end
|
105
|
+
|
106
|
+
def update_channel_version(channel, package, version)
|
107
|
+
path = "/external/channel/#{channel}/#{version}"
|
108
|
+
token_path = "/external/channels/#{channel}/#{version}"
|
109
|
+
api_patch(path, token_path, package)
|
110
|
+
end
|
111
|
+
|
112
|
+
def publish_channel_version(channel, version)
|
113
|
+
path = "/external/channels/#{channel}/versions/#{version}"
|
114
|
+
token_path = "/external/channels/#{channel}/versions/#{version}/state"
|
115
|
+
api_post(path, token_path)
|
116
|
+
end
|
117
|
+
|
118
|
+
def api_get(path)
|
119
|
+
service_urn = "urn:roku:cloud-services:chanprovsvc"
|
120
|
+
connection('GET', path, nil).get(api_path+path)
|
121
|
+
end
|
122
|
+
|
123
|
+
def api_post(path, token_path, package=nil, params = nil)
|
124
|
+
body = {}.to_json
|
125
|
+
if package
|
126
|
+
body = {
|
127
|
+
"appFileBase64Encoded" => Base64.encode64(package.read)
|
128
|
+
}.to_json
|
129
|
+
end
|
130
|
+
connection('POST', token_path, body).post(api_path+path) do |request|
|
131
|
+
if params
|
132
|
+
request.params = params
|
133
|
+
end if
|
134
|
+
request.body = body
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
def api_patch(path, token_path, package)
|
139
|
+
body = {
|
140
|
+
"path" => "/appFileBase64Encoded",
|
141
|
+
"value" => Base64.encode64(package.read),
|
142
|
+
"op" => "replace"
|
143
|
+
}.to_json
|
144
|
+
response = connection('PATCH', token_path, body).patch(api_path+path) do |request|
|
145
|
+
request.body = body
|
146
|
+
end
|
147
|
+
end
|
148
|
+
|
149
|
+
def connection(method, path, body)
|
150
|
+
service_urn = "urn:roku:cloud-services:chanprovsvc"
|
151
|
+
connection = Faraday.new(url: HOST, headers: {
|
152
|
+
'Authorization' => "Bearer "+get_jwt_token(@api_key, service_urn, method, path, body),
|
153
|
+
'Content-Type' => 'application/json',
|
154
|
+
'Accept' => 'application/json',
|
155
|
+
}) do |f|
|
156
|
+
f.adapter Faraday.default_adapter
|
157
|
+
end
|
158
|
+
end
|
159
|
+
|
160
|
+
def get_jwt_token(api_key, service_urn, method, path, body = nil)
|
161
|
+
key_file = File.expand_path(@config.api_keys[api_key.to_sym])
|
162
|
+
raise InvalidOptions "Missing api key" unless key_file
|
163
|
+
jwk = JWT::JWK.new(JSON.parse(File.read(key_file)))
|
164
|
+
header = {
|
165
|
+
"typ" => "JWT",
|
166
|
+
"kid" => jwk.export[:kid]
|
167
|
+
}
|
168
|
+
payload = {
|
169
|
+
"exp" => (Time.now + (12*60*60)).to_i,
|
170
|
+
"x-roku-request-key" => SecureRandom.uuid,
|
171
|
+
"x-roku-request-spec" => {
|
172
|
+
"serviceUrn" => service_urn,
|
173
|
+
"httpMethod" => method,
|
174
|
+
"path" => path,
|
175
|
+
}
|
176
|
+
}
|
177
|
+
if body
|
178
|
+
payload["x-roku-request-spec"]["bodySha256Base64"] = Digest::SHA256.base64digest(body)
|
179
|
+
end
|
180
|
+
JWT.encode(payload, jwk.signing_key, 'RS256', header)
|
181
|
+
end
|
182
|
+
end
|
183
|
+
RokuBuilder.register_plugin(RokuAPI)
|
184
|
+
end
|
data/lib/roku_builder/version.rb
CHANGED
data/lib/roku_builder.rb
CHANGED
data/roku_builder.gemspec
CHANGED
@@ -30,6 +30,7 @@ Gem::Specification.new do |spec|
|
|
30
30
|
spec.add_dependency "nokogiri", "~> 1.12"
|
31
31
|
spec.add_dependency "win32-security", "~> 0.5" # For windows compatibility
|
32
32
|
spec.add_dependency "image_size", "~> 2.0"
|
33
|
+
spec.add_dependency "jwt", "~> 2.7"
|
33
34
|
|
34
35
|
spec.add_development_dependency "bundler", "~> 2.0"
|
35
36
|
spec.add_development_dependency "rake", "~> 12.0"
|
@@ -153,11 +153,10 @@ module RokuBuilder
|
|
153
153
|
logger.expect(severity, nil, [String])
|
154
154
|
|
155
155
|
::Logger.stub :new, logger do
|
156
|
-
|
156
|
+
test_file(text: text, quiet: false)
|
157
157
|
end
|
158
158
|
|
159
159
|
logger.verify
|
160
|
-
warnings
|
161
160
|
end
|
162
161
|
|
163
162
|
def test(quiet=true)
|
@@ -120,8 +120,6 @@ module RokuBuilder
|
|
120
120
|
assert help_text
|
121
121
|
end
|
122
122
|
def test_core_get_plugin_by_name
|
123
|
-
parser = OptionParser.new
|
124
|
-
options = {}
|
125
123
|
plugin_name = Core.get_plugin_by_name("core")
|
126
124
|
refute_nil plugin_name
|
127
125
|
assert_match "RokuBuilder::Core", plugin_name.to_s
|
@@ -136,7 +136,7 @@ module RokuBuilder
|
|
136
136
|
end
|
137
137
|
def test_loader_squash
|
138
138
|
@request_stubs.push(stub_request(:post, "http://#{@device_config[:ip]}/plugin_install").
|
139
|
-
to_return(status: 200, body: "
|
139
|
+
to_return(status: 200, body: "Conversion succeeded", headers: {}))
|
140
140
|
@device_manager.expect(:reserve_device, @device, no_lock: false)
|
141
141
|
@device_manager.expect(:release_device, nil, [@device])
|
142
142
|
|
@@ -0,0 +1,557 @@
|
|
1
|
+
# ********** Copyright Viacom, Inc. Apache 2.0 **********
|
2
|
+
|
3
|
+
require_relative "../test_helper.rb"
|
4
|
+
|
5
|
+
module RokuBuilder
|
6
|
+
class RokuAPITest < Minitest::Test
|
7
|
+
def setup
|
8
|
+
Logger.set_testing
|
9
|
+
RokuBuilder.class_variable_set(:@@dev, false)
|
10
|
+
RokuBuilder.setup_plugins
|
11
|
+
register_plugins(RokuAPI)
|
12
|
+
@config, @options = build_config_options_objects(RokuAPITest, {submit: true, channel_id: "1234", api_key: "key1"}, false)
|
13
|
+
@requests = []
|
14
|
+
end
|
15
|
+
|
16
|
+
def teardown
|
17
|
+
@requests.each {|req| remove_request_stub(req)}
|
18
|
+
WebMock.reset!
|
19
|
+
end
|
20
|
+
|
21
|
+
def test_commands
|
22
|
+
commands = RokuAPI.commands
|
23
|
+
refute_nil commands[:submit]
|
24
|
+
refute_nil commands[:publish]
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_parse_options
|
28
|
+
parser = OptionParser.new
|
29
|
+
options = {}
|
30
|
+
RokuAPI.parse_options(parser: parser, options: options)
|
31
|
+
argv = ["roku", "--submit", "--publish", "--channel-id", "1234", "--api-key", "key1", "--no-publish"]
|
32
|
+
parser.parse! argv
|
33
|
+
assert options[:submit]
|
34
|
+
assert options[:publish]
|
35
|
+
assert_equal options[:channel_id], "1234"
|
36
|
+
assert_equal options[:api_key], "key1"
|
37
|
+
assert options[:no_publish]
|
38
|
+
end
|
39
|
+
|
40
|
+
def test_dependencies
|
41
|
+
assert_kind_of Array, RokuAPI.dependencies
|
42
|
+
assert_equal RokuAPI.dependencies.count, 0
|
43
|
+
end
|
44
|
+
|
45
|
+
def test_get_package
|
46
|
+
api = RokuAPI.new(config: @config)
|
47
|
+
options = {in: "in/path"}
|
48
|
+
called = false
|
49
|
+
open_proc = proc do |path|
|
50
|
+
called = true
|
51
|
+
assert_equal options[:in], path
|
52
|
+
end
|
53
|
+
File.stub(:open, open_proc) do
|
54
|
+
api.send(:get_package, options)
|
55
|
+
end
|
56
|
+
assert called
|
57
|
+
end
|
58
|
+
|
59
|
+
def test_api_path
|
60
|
+
api = RokuAPI.new(config: @config)
|
61
|
+
assert_equal "/developer/v1", api.send(:api_path)
|
62
|
+
end
|
63
|
+
|
64
|
+
def test_sorted_versions
|
65
|
+
api = RokuAPI.new(config: @config)
|
66
|
+
versions = [{"version" => "1.9"}, {"version" => "1.11"}, {"version" => "2.3"}, {"version" => "2.4"}]
|
67
|
+
sorted = api.send(:sorted_versions, versions)
|
68
|
+
assert_equal "2.4", sorted[0]["version"]
|
69
|
+
assert_equal "2.3", sorted[1]["version"]
|
70
|
+
assert_equal "1.11", sorted[2]["version"]
|
71
|
+
assert_equal "1.9", sorted[3]["version"]
|
72
|
+
versions = [{"version" => "1.4"}, {"version" => "1.3"}]
|
73
|
+
sorted = api.send(:sorted_versions, versions)
|
74
|
+
assert_equal "1.4", sorted[0]["version"]
|
75
|
+
assert_equal "1.3", sorted[1]["version"]
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_get_jwt_token
|
79
|
+
api = RokuAPI.new(config: @config)
|
80
|
+
urn = "test:urn"
|
81
|
+
method = "GET"
|
82
|
+
path = "/test/path"
|
83
|
+
token = api.send(:get_jwt_token, @options[:api_key], urn, method, path)
|
84
|
+
jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
|
85
|
+
decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
|
86
|
+
assert_equal decoded[1]["typ"], "JWT"
|
87
|
+
assert_equal decoded[1]["alg"], "RS256"
|
88
|
+
assert_equal decoded[1]["kid"], jwk.export[:kid]
|
89
|
+
|
90
|
+
assert is_uuid?(decoded[0]["x-roku-request-key"])
|
91
|
+
spec = decoded[0]["x-roku-request-spec"]
|
92
|
+
refute_nil spec
|
93
|
+
assert_equal spec["serviceUrn"], urn
|
94
|
+
assert_equal spec["httpMethod"], method
|
95
|
+
assert_equal spec["path"], path
|
96
|
+
end
|
97
|
+
|
98
|
+
def test_get_jwt_token_with_body
|
99
|
+
api = RokuAPI.new(config: @config)
|
100
|
+
urn = "test:urn"
|
101
|
+
method = "GET"
|
102
|
+
path = "/test/path"
|
103
|
+
body = {
|
104
|
+
"appFileBase64Encoded" => Base64.encode64(File.open(File.join(test_files_path(RokuAPITest), "test.pkg")).read)
|
105
|
+
}
|
106
|
+
sha256 = Digest::SHA256.base64digest(body.to_json)
|
107
|
+
token = api.send(:get_jwt_token, @options[:api_key], urn, method, path, body.to_json)
|
108
|
+
jwk = JWT::JWK.new(JSON.parse(File.read(@config.api_keys[:key1])))
|
109
|
+
decoded = JWT.decode(token, jwk.public_key, true, {algorithm: 'RS256'})
|
110
|
+
assert_equal decoded[1]["typ"], "JWT"
|
111
|
+
assert_equal decoded[1]["alg"], "RS256"
|
112
|
+
assert_equal decoded[1]["kid"], jwk.export[:kid]
|
113
|
+
|
114
|
+
assert is_uuid?(decoded[0]["x-roku-request-key"])
|
115
|
+
spec = decoded[0]["x-roku-request-spec"]
|
116
|
+
refute_nil spec
|
117
|
+
assert_equal spec["serviceUrn"], urn
|
118
|
+
assert_equal spec["httpMethod"], method
|
119
|
+
assert_equal spec["path"], path
|
120
|
+
assert_equal spec["bodySha256Base64"], sha256
|
121
|
+
end
|
122
|
+
|
123
|
+
def test_api_get
|
124
|
+
api = RokuAPI.new(config: @config)
|
125
|
+
path = "/test/path"
|
126
|
+
api.instance_variable_set(:@api_key, "key1")
|
127
|
+
@requests.push(stub_request(:any, /apipub.roku.com.*/))
|
128
|
+
response = api.send(:api_get, path)
|
129
|
+
assert_requested(:get, "https://apipub.roku.com/developer/v1/test/path", headers: {
|
130
|
+
"Accept" => "application/json",
|
131
|
+
"Content-Type" => "application/json",
|
132
|
+
"Authorization" => /Bearer .*/
|
133
|
+
})
|
134
|
+
end
|
135
|
+
|
136
|
+
def test_api_post
|
137
|
+
api = RokuAPI.new(config: @config)
|
138
|
+
path = "/test/path"
|
139
|
+
token_path = "/other/path"
|
140
|
+
api.instance_variable_set(:@api_key, "key1")
|
141
|
+
package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
|
142
|
+
encoded = Base64.encode64(package.read)
|
143
|
+
@requests.push(stub_request(:any, /apipub.roku.com.*/))
|
144
|
+
called = false
|
145
|
+
jwt_proc = proc do |api_key, service_urn, method, path, body|
|
146
|
+
called = true
|
147
|
+
assert_equal path, token_path
|
148
|
+
"token"
|
149
|
+
end
|
150
|
+
params = {"status" => "Published"}
|
151
|
+
api.stub(:get_jwt_token, jwt_proc) do
|
152
|
+
response = api.send(:api_post, path, token_path, package, params)
|
153
|
+
end
|
154
|
+
assert called
|
155
|
+
assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
|
156
|
+
body: {"appFileBase64Encoded" => encoded}.to_json,
|
157
|
+
headers: {
|
158
|
+
"Accept" => "application/json",
|
159
|
+
"Content-Type" => "application/json",
|
160
|
+
"Authorization" => /Bearer token/
|
161
|
+
},
|
162
|
+
query: {"status" => "Published"}
|
163
|
+
)
|
164
|
+
end
|
165
|
+
|
166
|
+
def test_api_post_no_package
|
167
|
+
api = RokuAPI.new(config: @config)
|
168
|
+
path = "/test/path"
|
169
|
+
token_path = "/other/path"
|
170
|
+
api.instance_variable_set(:@api_key, "key1")
|
171
|
+
@requests.push(stub_request(:any, /apipub.roku.com.*/))
|
172
|
+
called = false
|
173
|
+
jwt_proc = proc do |api_key, service_urn, method, path, body|
|
174
|
+
called = true
|
175
|
+
assert_equal path, token_path
|
176
|
+
"token"
|
177
|
+
end
|
178
|
+
api.stub(:get_jwt_token, jwt_proc) do
|
179
|
+
response = api.send(:api_post, path, token_path)
|
180
|
+
end
|
181
|
+
assert called
|
182
|
+
assert_requested(:post, "https://apipub.roku.com/developer/v1/test/path",
|
183
|
+
headers: {
|
184
|
+
"Accept" => "application/json",
|
185
|
+
"Content-Type" => "application/json",
|
186
|
+
"Authorization" => /Bearer .*/
|
187
|
+
}
|
188
|
+
)
|
189
|
+
end
|
190
|
+
|
191
|
+
def test_api_patch
|
192
|
+
api = RokuAPI.new(config: @config)
|
193
|
+
path = "/test/path"
|
194
|
+
token_path = "/other/path"
|
195
|
+
api.instance_variable_set(:@api_key, "key1")
|
196
|
+
package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
|
197
|
+
encoded = Base64.encode64(package.read)
|
198
|
+
@requests.push(stub_request(:any, /apipub.roku.com.*/))
|
199
|
+
called = false
|
200
|
+
jwt_proc = proc do |api_key, service_urn, method, path, body|
|
201
|
+
called = true
|
202
|
+
assert_equal path, token_path
|
203
|
+
"token"
|
204
|
+
end
|
205
|
+
api.stub(:get_jwt_token, jwt_proc) do
|
206
|
+
response = api.send(:api_patch, path, token_path, package)
|
207
|
+
end
|
208
|
+
assert called
|
209
|
+
assert_requested(:patch, "https://apipub.roku.com/developer/v1/test/path",
|
210
|
+
body: {"path" => "/appFileBase64Encoded", "value" => encoded, "op" => "replace"}.to_json,
|
211
|
+
headers: {
|
212
|
+
"Accept" => "application/json",
|
213
|
+
"Content-Type" => "application/json",
|
214
|
+
"Authorization" => /Bearer token/
|
215
|
+
}
|
216
|
+
)
|
217
|
+
end
|
218
|
+
|
219
|
+
def test_get_channel_versions
|
220
|
+
api = RokuAPI.new(config: @config)
|
221
|
+
channel = "1234"
|
222
|
+
api.instance_variable_set(:@api_key, "key1")
|
223
|
+
response = Minitest::Mock.new
|
224
|
+
body = { "id" => "1234", "version" => "1.1"}
|
225
|
+
response.expect(:body, body.to_json)
|
226
|
+
called = 0
|
227
|
+
get_proc = proc do |path|
|
228
|
+
called +=1
|
229
|
+
assert_equal path, "/external/channels/#{channel}/versions"
|
230
|
+
response
|
231
|
+
end
|
232
|
+
sort_proc = proc do |versions|
|
233
|
+
called += 1
|
234
|
+
versions
|
235
|
+
end
|
236
|
+
api.stub(:api_get, get_proc) do
|
237
|
+
api.stub(:sorted_versions, sort_proc) do
|
238
|
+
result = api.send(:get_channel_versions, channel)
|
239
|
+
assert_equal result, body
|
240
|
+
end
|
241
|
+
end
|
242
|
+
assert_equal 2, called
|
243
|
+
end
|
244
|
+
|
245
|
+
def test_submit_no_channel_id
|
246
|
+
api = RokuAPI.new(config: @config)
|
247
|
+
assert_raises RokuBuilder::InvalidOptions do
|
248
|
+
api.submit(options: {})
|
249
|
+
end
|
250
|
+
end
|
251
|
+
|
252
|
+
def test_submit_without_unpublished
|
253
|
+
api = RokuAPI.new(config: @config)
|
254
|
+
called = {}
|
255
|
+
@options[:no_publish] = true
|
256
|
+
response = Minitest::Mock.new
|
257
|
+
response.expect(:success?, true)
|
258
|
+
response.expect(:body, api_versions[0].to_json)
|
259
|
+
updated = proc {called[:updated] = true; response}
|
260
|
+
created = proc {called[:created] = true; response}
|
261
|
+
@requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
|
262
|
+
body: api_versions.to_json
|
263
|
+
))
|
264
|
+
api.stub(:create_channel_version, created) do
|
265
|
+
api.stub(:update_channel_version, updated) do
|
266
|
+
api.stub(:get_package, "") do
|
267
|
+
api.submit(options: @options)
|
268
|
+
end
|
269
|
+
end
|
270
|
+
end
|
271
|
+
assert called[:created]
|
272
|
+
assert_nil called[:updated]
|
273
|
+
assert api.instance_variable_get(:@no_publish)
|
274
|
+
|
275
|
+
end
|
276
|
+
def test_submit_without_latest_unpublished
|
277
|
+
api = RokuAPI.new(config: @config)
|
278
|
+
called = {}
|
279
|
+
body = api_versions
|
280
|
+
body.push(api_versions.first)
|
281
|
+
body[1]["version"] = "1.3"
|
282
|
+
body[1]["channelState"] = "Unpublished"
|
283
|
+
response = Minitest::Mock.new
|
284
|
+
response.expect(:success?, true)
|
285
|
+
response.expect(:body, body[0].to_json)
|
286
|
+
updated = proc {called[:updated] = true; response}
|
287
|
+
created = proc {called[:created] = true; response}
|
288
|
+
@requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
|
289
|
+
body: body.to_json
|
290
|
+
))
|
291
|
+
api.stub(:create_channel_version, created) do
|
292
|
+
api.stub(:update_channel_version, updated) do
|
293
|
+
api.stub(:get_package, "") do
|
294
|
+
api.submit(options: @options)
|
295
|
+
end
|
296
|
+
end
|
297
|
+
end
|
298
|
+
assert called[:created]
|
299
|
+
assert_nil called[:updated]
|
300
|
+
end
|
301
|
+
|
302
|
+
def test_submit_with_unpublished
|
303
|
+
api = RokuAPI.new(config: @config)
|
304
|
+
body = api_versions
|
305
|
+
body[0]["channelState"] = "Unpublished"
|
306
|
+
called = {}
|
307
|
+
response = Minitest::Mock.new
|
308
|
+
response.expect(:success?, true)
|
309
|
+
response.expect(:body, body[0].to_json)
|
310
|
+
updated = proc do |channel, package, version|
|
311
|
+
called[:updated] = true
|
312
|
+
assert_equal body[0]["id"], version
|
313
|
+
response
|
314
|
+
end
|
315
|
+
created = proc {called[:created] = true; response}
|
316
|
+
@requests.push(stub_request(:any, "https://apipub.roku.com/developer/v1/external/channels/1234/versions").to_return(
|
317
|
+
body: body.to_json
|
318
|
+
))
|
319
|
+
api.stub(:create_channel_version, created) do
|
320
|
+
api.stub(:update_channel_version, updated) do
|
321
|
+
api.stub(:get_package, "") do
|
322
|
+
api.submit(options: @options)
|
323
|
+
end
|
324
|
+
end
|
325
|
+
end
|
326
|
+
assert called[:updated]
|
327
|
+
assert_nil called[:created]
|
328
|
+
end
|
329
|
+
|
330
|
+
def test_create_channel_version
|
331
|
+
api = RokuAPI.new(config: @config)
|
332
|
+
channel = "1234"
|
333
|
+
api.instance_variable_set(:@api_key, "key1")
|
334
|
+
package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
|
335
|
+
called = false
|
336
|
+
post_proc = proc do |path, token_path, package, params|
|
337
|
+
called = true
|
338
|
+
assert_equal path, "/external/channels/#{channel}/versions"
|
339
|
+
assert_equal token_path, "/external/channels/#{channel}/versions"
|
340
|
+
assert_equal "Published", params["channelState"]
|
341
|
+
assert_kind_of File, package
|
342
|
+
end
|
343
|
+
api.stub(:api_post, post_proc) do
|
344
|
+
api.send(:create_channel_version, channel, package)
|
345
|
+
end
|
346
|
+
assert called
|
347
|
+
end
|
348
|
+
|
349
|
+
def test_create_channel_version_no_publish
|
350
|
+
api = RokuAPI.new(config: @config)
|
351
|
+
channel = "1234"
|
352
|
+
api.instance_variable_set(:@api_key, "key1")
|
353
|
+
api.instance_variable_set(:@no_publish, true)
|
354
|
+
package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
|
355
|
+
called = false
|
356
|
+
post_proc = proc do |path, token_path, package, params|
|
357
|
+
called = true
|
358
|
+
assert_equal path, "/external/channels/#{channel}/versions"
|
359
|
+
assert_equal token_path, "/external/channels/#{channel}/versions"
|
360
|
+
assert_nil params
|
361
|
+
assert_kind_of File, package
|
362
|
+
end
|
363
|
+
api.stub(:api_post, post_proc) do
|
364
|
+
api.send(:create_channel_version, channel, package)
|
365
|
+
end
|
366
|
+
assert called
|
367
|
+
end
|
368
|
+
|
369
|
+
def test_update_channel_version
|
370
|
+
api = RokuAPI.new(config: @config)
|
371
|
+
channel = "1234"
|
372
|
+
version = "1234"
|
373
|
+
api.instance_variable_set(:@api_key, "key1")
|
374
|
+
package = File.open(File.join(test_files_path(RokuAPITest), "test.pkg"))
|
375
|
+
called = false
|
376
|
+
patch_proc = proc do |path, token_path, package|
|
377
|
+
called = true
|
378
|
+
assert_equal path, "/external/channel/#{channel}/#{version}"
|
379
|
+
assert_equal token_path, "/external/channels/#{channel}/#{version}"
|
380
|
+
assert_kind_of File, package
|
381
|
+
end
|
382
|
+
api.stub(:api_patch, patch_proc) do
|
383
|
+
api.send(:update_channel_version, channel, package, version)
|
384
|
+
end
|
385
|
+
assert called
|
386
|
+
end
|
387
|
+
|
388
|
+
def test_publish_no_channel_id
|
389
|
+
api = RokuAPI.new(config: @config)
|
390
|
+
assert_raises RokuBuilder::InvalidOptions do
|
391
|
+
params = {options: {}}
|
392
|
+
api.send(:publish, **params)
|
393
|
+
end
|
394
|
+
end
|
395
|
+
|
396
|
+
def test_publish_without_unpublished
|
397
|
+
api = RokuAPI.new(config: @config)
|
398
|
+
expected_channel = "1234"
|
399
|
+
api.instance_variable_set(:@api_key, "key1")
|
400
|
+
body = api_versions
|
401
|
+
called = false
|
402
|
+
get_proc = proc do |channel|
|
403
|
+
called = true
|
404
|
+
assert_equal expected_channel, channel
|
405
|
+
body
|
406
|
+
end
|
407
|
+
api.stub(:get_channel_versions, get_proc) do
|
408
|
+
assert_raises RokuBuilder::ExecutionError do
|
409
|
+
params = {options: {channel_id: expected_channel}}
|
410
|
+
api.send(:publish, **params)
|
411
|
+
end
|
412
|
+
end
|
413
|
+
assert called
|
414
|
+
end
|
415
|
+
|
416
|
+
def test_publish_without_latest_unpublished
|
417
|
+
api = RokuAPI.new(config: @config)
|
418
|
+
expected_channel = "1234"
|
419
|
+
api.instance_variable_set(:@api_key, "key1")
|
420
|
+
body = api_versions
|
421
|
+
body.push(api_versions.first)
|
422
|
+
body[1]["version"] = "1.3"
|
423
|
+
body[1]["channelState"] = "Unpublished"
|
424
|
+
called = false
|
425
|
+
get_proc = proc do |channel|
|
426
|
+
called = true
|
427
|
+
assert_equal expected_channel, channel
|
428
|
+
body
|
429
|
+
end
|
430
|
+
api.stub(:get_channel_versions, get_proc) do
|
431
|
+
assert_raises RokuBuilder::ExecutionError do
|
432
|
+
params = {options: {channel_id: expected_channel}}
|
433
|
+
api.send(:publish, **params)
|
434
|
+
end
|
435
|
+
end
|
436
|
+
assert called
|
437
|
+
end
|
438
|
+
|
439
|
+
def test_publish_with_unpublished
|
440
|
+
api = RokuAPI.new(config: @config)
|
441
|
+
expected_channel = "1234"
|
442
|
+
api.instance_variable_set(:@api_key, "key1")
|
443
|
+
body = [{ "id" => "1234", "version" => "1.1", "channelState" => "Unpublished"}]
|
444
|
+
called = 0
|
445
|
+
get_proc = proc do |channel|
|
446
|
+
called += 1
|
447
|
+
assert_equal expected_channel, channel
|
448
|
+
body
|
449
|
+
end
|
450
|
+
response = Minitest::Mock.new
|
451
|
+
response.expect(:success?, true)
|
452
|
+
response.expect(:body, body[0].to_json)
|
453
|
+
post_proc = proc do |channel, version|
|
454
|
+
called += 1
|
455
|
+
assert_equal expected_channel, channel
|
456
|
+
assert_equal body.first["id"], version
|
457
|
+
response
|
458
|
+
end
|
459
|
+
api.stub(:get_channel_versions, get_proc) do
|
460
|
+
api.stub(:publish_channel_version, post_proc) do
|
461
|
+
params = {options: {channel_id: expected_channel}}
|
462
|
+
api.send(:publish, **params)
|
463
|
+
end
|
464
|
+
end
|
465
|
+
assert_equal called, 2
|
466
|
+
end
|
467
|
+
|
468
|
+
def test_publish_channel_version
|
469
|
+
api = RokuAPI.new(config: @config)
|
470
|
+
channel = "1234"
|
471
|
+
api.instance_variable_set(:@api_key, "key1")
|
472
|
+
response = Minitest::Mock.new
|
473
|
+
body = { "id" => "1234", "version" => "1.1"}
|
474
|
+
response.expect(:body, body.to_json)
|
475
|
+
called = false
|
476
|
+
post_proc = proc do |path, token_path|
|
477
|
+
called = true
|
478
|
+
assert_equal path, "/external/channels/#{channel}/versions/#{body["id"]}"
|
479
|
+
assert_equal token_path, "/external/channels/#{channel}/versions/#{body["id"]}/state"
|
480
|
+
end
|
481
|
+
api.stub(:api_post, post_proc) do
|
482
|
+
api.send(:publish_channel_version, channel, body["id"])
|
483
|
+
end
|
484
|
+
assert called
|
485
|
+
end
|
486
|
+
|
487
|
+
def test_submit_failure_create
|
488
|
+
api = RokuAPI.new(config: @config)
|
489
|
+
response = Minitest::Mock.new
|
490
|
+
response.expect(:success?, false)
|
491
|
+
response.expect(:reason_phrase, "reason")
|
492
|
+
api.stub(:get_channel_versions, api_versions) do
|
493
|
+
api.stub(:create_channel_version, response) do
|
494
|
+
api.stub(:get_package, "") do
|
495
|
+
assert_raises RokuBuilder::ExecutionError do
|
496
|
+
api.submit(options: @options)
|
497
|
+
end
|
498
|
+
end
|
499
|
+
end
|
500
|
+
end
|
501
|
+
assert_mock response
|
502
|
+
end
|
503
|
+
|
504
|
+
def test_submit_response_created
|
505
|
+
api = RokuAPI.new(config: @config)
|
506
|
+
body = { "id" => "1234", "version" => "1.1"}
|
507
|
+
response = Minitest::Mock.new
|
508
|
+
response.expect(:success?, true)
|
509
|
+
response.expect(:body, body.to_json)
|
510
|
+
api.stub(:get_channel_versions, api_versions) do
|
511
|
+
api.stub(:create_channel_version, response) do
|
512
|
+
api.stub(:get_package, "") do
|
513
|
+
response_json = api.submit(options: @options)
|
514
|
+
assert_equal body, response_json
|
515
|
+
end
|
516
|
+
end
|
517
|
+
end
|
518
|
+
assert_mock response
|
519
|
+
end
|
520
|
+
|
521
|
+
def test_submit_response_updated
|
522
|
+
api = RokuAPI.new(config: @config)
|
523
|
+
body = { "id" => "1234", "version" => "1.1"}
|
524
|
+
response = Minitest::Mock.new
|
525
|
+
response.expect(:success?, true)
|
526
|
+
response.expect(:body, body.to_json)
|
527
|
+
versions = api_versions
|
528
|
+
versions[0]["channelState"] = "Unpublished"
|
529
|
+
api.stub(:get_channel_versions, versions) do
|
530
|
+
api.stub(:update_channel_version, response) do
|
531
|
+
api.stub(:get_package, "") do
|
532
|
+
response_json = api.submit(options: @options)
|
533
|
+
assert_equal body, response_json
|
534
|
+
end
|
535
|
+
end
|
536
|
+
end
|
537
|
+
assert_mock response
|
538
|
+
end
|
539
|
+
|
540
|
+
def test_publish_response
|
541
|
+
api = RokuAPI.new(config: @config)
|
542
|
+
body = { "id" => "1234", "version" => "1.1"}
|
543
|
+
response = Minitest::Mock.new
|
544
|
+
response.expect(:success?, true)
|
545
|
+
response.expect(:body, body.to_json)
|
546
|
+
versions = api_versions
|
547
|
+
versions[0]["channelState"] = "Unpublished"
|
548
|
+
api.stub(:get_channel_versions, versions) do
|
549
|
+
api.stub(:publish_channel_version, response) do
|
550
|
+
response_json = api.publish(options: @options)
|
551
|
+
assert_equal body, response_json
|
552
|
+
end
|
553
|
+
end
|
554
|
+
assert_mock response
|
555
|
+
end
|
556
|
+
end
|
557
|
+
end
|
@@ -44,6 +44,22 @@ module RokuBuilder
|
|
44
44
|
assert_equal File.join(Dir.pwd, "infile"), configs[:root_dir]
|
45
45
|
end
|
46
46
|
|
47
|
+
def test_api_keys
|
48
|
+
options = build_options({
|
49
|
+
current: true,
|
50
|
+
validate: true
|
51
|
+
})
|
52
|
+
config = good_config(ConfigParserTest)
|
53
|
+
configs = nil
|
54
|
+
File.stub(:exist?, true) do
|
55
|
+
configs = ConfigParser.parse(options: options, config: config)
|
56
|
+
end
|
57
|
+
|
58
|
+
assert_kind_of Hash, configs
|
59
|
+
assert_kind_of Hash, configs[:api_keys]
|
60
|
+
assert_equal configs[:api_keys][:key1], File.join(test_files_path(ConfigParserTest), "test_key.json")
|
61
|
+
end
|
62
|
+
|
47
63
|
def test_manifest_config_current
|
48
64
|
options = build_options({
|
49
65
|
current: true,
|
@@ -216,5 +216,19 @@ module RokuBuilder
|
|
216
216
|
validator = ConfigValidator.new(config: config)
|
217
217
|
assert_equal [12], validator.instance_variable_get(:@codes)
|
218
218
|
end
|
219
|
+
|
220
|
+
def test_config_validate_invalid_api_key
|
221
|
+
config = good_config
|
222
|
+
config[:api_keys][:key1] = nil
|
223
|
+
validator = ConfigValidator.new(config: config)
|
224
|
+
assert_equal [22], validator.instance_variable_get(:@codes)
|
225
|
+
end
|
226
|
+
|
227
|
+
def test_confif_validate_no_api_keys
|
228
|
+
config = good_config
|
229
|
+
config[:api_keys] = nil
|
230
|
+
validator = ConfigValidator.new(config: config)
|
231
|
+
assert_equal [0], validator.instance_variable_get(:@codes)
|
232
|
+
end
|
219
233
|
end
|
220
234
|
end
|
@@ -39,7 +39,7 @@ module RokuBuilder
|
|
39
39
|
@ping.expect(:ping?, false, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
|
40
40
|
manager = DeviceManager.new(config: config, options: options)
|
41
41
|
assert_raises(DeviceError) do
|
42
|
-
|
42
|
+
manager.reserve_device
|
43
43
|
end
|
44
44
|
end
|
45
45
|
end
|
@@ -50,9 +50,9 @@ module RokuBuilder
|
|
50
50
|
@ping.expect(:ping?, true, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
|
51
51
|
@ping.expect(:ping?, true, [config.raw[:devices][:roku][:ip], 1, 0.2, 1])
|
52
52
|
manager = DeviceManager.new(config: config, options: options)
|
53
|
-
|
53
|
+
manager.reserve_device
|
54
54
|
assert_raises(DeviceError) do
|
55
|
-
|
55
|
+
manager.reserve_device
|
56
56
|
end
|
57
57
|
end
|
58
58
|
end
|
@@ -121,7 +121,7 @@ module RokuBuilder
|
|
121
121
|
manager = DeviceManager.new(config: config, options: options)
|
122
122
|
device1 = manager.reserve_device
|
123
123
|
assert_raises(DeviceError) do
|
124
|
-
|
124
|
+
manager.reserve_device
|
125
125
|
end
|
126
126
|
assert_equal "test2", device1.name
|
127
127
|
end
|
File without changes
|
@@ -0,0 +1,13 @@
|
|
1
|
+
{
|
2
|
+
"kty": "RSA",
|
3
|
+
"kid": "hbdk0JpkFRc39Dx7WXxKkntR0UeCp-J7PiWWkwGOaHk",
|
4
|
+
"alg": "RS256",
|
5
|
+
"e": "AQAB",
|
6
|
+
"n": "xRFv0nywIFBexub60g-bi4ZwEOj_E-bA_bqO99w6kbAMu_XqAvYaIu2StZK1SedrK-kKcOCXFfEbCGlM0CZnrIXU5usRERvS1dDUZz3KyJ9DPi4VMUgTTONM6m_NrfgOa8-V71LcNXcnQ2ZhWTvffcvgZ7Btz0yMbuwhIKlJNEs9MtrZDV_yWpbns-kQDH1A3PS22ZNGej7ifJJuIX1KitDLvkjrYR8MaCf-PUJewU-7ugpvO1pNi6ChYcTY09YuScPYiZg5i9yClve0lwScw2DBIBMfxyAG626YZtUkv6ffKQuceak-w0vx7gYLOJv_aCyKNcxrmFmMYwDIbXDaHQ",
|
7
|
+
"d": "G0wdBzUKWI-JcVfRaoOK8jq_DziXDLSsCvlqkF7LJh8SxH592ccpO6lY5xnZTtFlgQGY1qXlh76MFhAv-a04MyeepBXvmUUXYVK5-UsP6dZVxCkx-k-XjND3eIngHbb8mGZ6yFnb8vP8VlO6LFgkzxIMlZBUxaA-26aNuC5622lKUoQQiD3eVxu93hIOAjn08dMn4yl8D4MbD8kfkWeQIXM0VI25YjKlt2mJSajyMxxMFTIrevoGo72tEgjpER--EDXMBuq0KsPSU7ZHfLhs6Dk2bcG79JAZ4WG17gkoO1atjta_kPXik4MQEeQYFgT3kaLSsSvhv3ipp28nOwFugQ",
|
8
|
+
"p": "7OeIV6zOUlyWcNvX4uwRy_qKo-JAltmSqIiTQmry9l2HDFEV3hnPnV5uyYU6uIo-OWMTWxWR_41Wl45Na15DYhcY8ttudAseiPHPqczhbm5jCzYSt6vY4prKDMXP3rXbRb9wGPm22BqU-ERxQz_vwMhXxDhLaHjOZ3ihjcFI440",
|
9
|
+
"q": "1PPkKEGmegHkH7YPXoZyz90qk2FRBBY76ulU-ThXaaMDiS0vDJqcwrvpk9UDT3hdnZhh0zLhlS1C9ypvnQDqTA7p8h_my0VL9bXVcEgUzzkgQ_Vjyq9-6Lb2y9HGqXUoycLS4xss5qXZOM26oFGkeRgfGXZo2Ndlb-zGQN88ZNE",
|
10
|
+
"dp": "2Q1FGPclzcYwu9RglvMtVxMEpSRtgwhy22DOcwLj-h801W8RNv20_3z-yjn71Aos-o0wtbosmtRXKuJhQmcKG7wHyrKLH1z0rAnI9szVGkWfDy2KtqeHPg8N4ef3DRjXfq7oOKnKAXNRW6nxj-jrdFjaONhPFrfgfGLEuckGTB0",
|
11
|
+
"dq": "HWWZrnD5oUgXjMUeNAdNXCKE2RmLDIxhMxmI0GqVrpCBUXN6VjwVvdAg-3ZhYZwVGEdL4dLZTzWTU_l4tOzGaz93ziPXQWJMjRvP3hMlREH3kUoTv4wgcdGoGhTYXtY8jjWl1RIQTbrBVNUZmT4L_Wd2C5bL_Hsnlp7R82ydsrE",
|
12
|
+
"qi": "cnrYQq21HMSlYj3Ga_F8Su1H_9cKjZPJoeRcGagkBQpIx2zGxhheTEXZV7X9RFNyLev6zBXxue6PEhjAEEDqlNKNFXSmlLSkbDkKCMb1yeALTPSqrNFvq8DdH0cxMDTPI0U5K2JCwuAoAyXzWxENEiRlq4oizdzZBvilM7TF4fM"
|
13
|
+
}
|
@@ -71,56 +71,79 @@ def tmp_folder()
|
|
71
71
|
Dir.tmpdir()
|
72
72
|
end
|
73
73
|
|
74
|
+
def is_uuid?(uuid)
|
75
|
+
uuid_regex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/
|
76
|
+
return true if uuid_regex.match?(uuid.to_s.downcase)
|
77
|
+
false
|
78
|
+
end
|
79
|
+
|
74
80
|
def good_config(klass=nil)
|
75
81
|
root_dir = "/tmp"
|
76
82
|
root_dir = test_files_path(klass) if klass
|
77
83
|
{
|
78
84
|
devices: {
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
85
|
+
default: :roku,
|
86
|
+
roku: {
|
87
|
+
ip: "192.168.0.100",
|
88
|
+
user: "user",
|
89
|
+
password: "password"
|
90
|
+
}
|
91
|
+
},
|
86
92
|
projects: {
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
93
|
+
default: :project1,
|
94
|
+
project1: {
|
95
|
+
directory: root_dir,
|
96
|
+
source_files: ["manifest", "images", "source"],
|
97
|
+
app_name: "<app name>",
|
98
|
+
stage_method: :git,
|
99
|
+
stages:{
|
100
|
+
production: {
|
101
|
+
branch: "production",
|
102
|
+
key: {
|
103
|
+
keyed_pkg: File.join(root_dir, "test.pkg"),
|
104
|
+
password: "password"
|
105
|
+
}
|
106
|
+
}
|
107
|
+
}
|
108
|
+
},
|
109
|
+
project2: {
|
110
|
+
directory: root_dir,
|
111
|
+
source_files: ["images","source","manifest"],
|
112
|
+
app_name: "<app name>",
|
113
|
+
stage_method: :script,
|
114
|
+
stages:{
|
115
|
+
production: {
|
116
|
+
script: {stage: "stage_script", unstage: "unstage_script"},
|
117
|
+
key: "a"
|
118
|
+
}
|
119
|
+
}
|
120
|
+
}
|
121
|
+
},
|
116
122
|
keys: {
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
123
|
+
a: {
|
124
|
+
keyed_pkg: File.join(root_dir, "test.pkg"),
|
125
|
+
password: "password"
|
126
|
+
}
|
127
|
+
},
|
122
128
|
input_mappings: {
|
123
|
-
|
124
|
-
|
129
|
+
"a": ["home", "Home"]
|
130
|
+
},
|
131
|
+
api_keys: {
|
132
|
+
key1: File.join(root_dir, "test_key.json")
|
133
|
+
}
|
125
134
|
}
|
126
135
|
end
|
136
|
+
|
137
|
+
def api_versions
|
138
|
+
[
|
139
|
+
{
|
140
|
+
"id" => "5735B375-2607-435F-97AE-66954DC2A91F",
|
141
|
+
"channelState" => "Published",
|
142
|
+
"appSize" => 1226192,
|
143
|
+
"channelId" => 722085,
|
144
|
+
"version" => "1.4",
|
145
|
+
"minFirmwareVersion" => 0,
|
146
|
+
"minimumFirmwareVersionTextShort" => "v2.5 b388"
|
147
|
+
}
|
148
|
+
]
|
149
|
+
end
|
@@ -10,12 +10,12 @@ class GitTest < Minitest::Test
|
|
10
10
|
|
11
11
|
index = 1
|
12
12
|
base.expect(:lib, lib)
|
13
|
+
base.expect(:lib, lib)
|
14
|
+
lib.expect(:stashes_all, [])
|
13
15
|
lib.expect(:stash_pop, nil, [index])
|
14
16
|
|
15
17
|
Dir.mktmpdir do |dir|
|
16
|
-
|
17
|
-
stashes = git.branch.stashes
|
18
|
-
stashes.instance_variable_set(:@base, base)
|
18
|
+
stashes = Git::Stashes.new(base)
|
19
19
|
stashes.pop(index)
|
20
20
|
end
|
21
21
|
|
@@ -29,12 +29,12 @@ class GitTest < Minitest::Test
|
|
29
29
|
|
30
30
|
index = 1
|
31
31
|
base.expect(:lib, lib)
|
32
|
+
base.expect(:lib, lib)
|
33
|
+
lib.expect(:stashes_all, [])
|
32
34
|
lib.expect(:stash_drop, nil, [index])
|
33
35
|
|
34
36
|
Dir.mktmpdir do |dir|
|
35
|
-
|
36
|
-
stashes = git.branch.stashes
|
37
|
-
stashes.instance_variable_set(:@base, base)
|
37
|
+
stashes = Git::Stashes.new(base)
|
38
38
|
stashes.drop(index)
|
39
39
|
end
|
40
40
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: roku_builder
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 4.
|
4
|
+
version: 4.29.1
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- greeneca
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2024-01-25 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rubyzip
|
@@ -150,6 +150,20 @@ dependencies:
|
|
150
150
|
- - "~>"
|
151
151
|
- !ruby/object:Gem::Version
|
152
152
|
version: '2.0'
|
153
|
+
- !ruby/object:Gem::Dependency
|
154
|
+
name: jwt
|
155
|
+
requirement: !ruby/object:Gem::Requirement
|
156
|
+
requirements:
|
157
|
+
- - "~>"
|
158
|
+
- !ruby/object:Gem::Version
|
159
|
+
version: '2.7'
|
160
|
+
type: :runtime
|
161
|
+
prerelease: false
|
162
|
+
version_requirements: !ruby/object:Gem::Requirement
|
163
|
+
requirements:
|
164
|
+
- - "~>"
|
165
|
+
- !ruby/object:Gem::Version
|
166
|
+
version: '2.7'
|
153
167
|
- !ruby/object:Gem::Dependency
|
154
168
|
name: bundler
|
155
169
|
requirement: !ruby/object:Gem::Requirement
|
@@ -514,6 +528,7 @@ files:
|
|
514
528
|
- lib/roku_builder/plugins/packager.rb
|
515
529
|
- lib/roku_builder/plugins/performance_config.json
|
516
530
|
- lib/roku_builder/plugins/profiler.rb
|
531
|
+
- lib/roku_builder/plugins/rokuapi.rb
|
517
532
|
- lib/roku_builder/plugins/sca-cmd/LICENSE
|
518
533
|
- lib/roku_builder/plugins/sca-cmd/README.md
|
519
534
|
- lib/roku_builder/plugins/sca-cmd/bin/sca-cmd
|
@@ -536,6 +551,7 @@ files:
|
|
536
551
|
- test/roku_builder/plugins/test_navigator.rb
|
537
552
|
- test/roku_builder/plugins/test_packager.rb
|
538
553
|
- test/roku_builder/plugins/test_profiler.rb
|
554
|
+
- test/roku_builder/plugins/test_rokuapi.rb
|
539
555
|
- test/roku_builder/plugins/test_scripter.rb
|
540
556
|
- test/roku_builder/plugins/test_tester.rb
|
541
557
|
- test/roku_builder/test_config.rb
|
@@ -614,6 +630,8 @@ files:
|
|
614
630
|
- test/roku_builder/test_files/packager_test/manifest
|
615
631
|
- test/roku_builder/test_files/packager_test/scripter_test/manifest
|
616
632
|
- test/roku_builder/test_files/packager_test/test.pkg
|
633
|
+
- test/roku_builder/test_files/roku_api_test/test.pkg
|
634
|
+
- test/roku_builder/test_files/roku_api_test/test_key.json
|
617
635
|
- test/roku_builder/test_files/roku_builder_test/config.json
|
618
636
|
- test/roku_builder/test_files/scripter_test/manifest
|
619
637
|
- test/roku_builder/test_files/scripter_test/test.pkg
|
@@ -667,6 +685,7 @@ test_files:
|
|
667
685
|
- test/roku_builder/plugins/test_navigator.rb
|
668
686
|
- test/roku_builder/plugins/test_packager.rb
|
669
687
|
- test/roku_builder/plugins/test_profiler.rb
|
688
|
+
- test/roku_builder/plugins/test_rokuapi.rb
|
670
689
|
- test/roku_builder/plugins/test_scripter.rb
|
671
690
|
- test/roku_builder/plugins/test_tester.rb
|
672
691
|
- test/roku_builder/test_config.rb
|
@@ -745,6 +764,8 @@ test_files:
|
|
745
764
|
- test/roku_builder/test_files/packager_test/manifest
|
746
765
|
- test/roku_builder/test_files/packager_test/scripter_test/manifest
|
747
766
|
- test/roku_builder/test_files/packager_test/test.pkg
|
767
|
+
- test/roku_builder/test_files/roku_api_test/test.pkg
|
768
|
+
- test/roku_builder/test_files/roku_api_test/test_key.json
|
748
769
|
- test/roku_builder/test_files/roku_builder_test/config.json
|
749
770
|
- test/roku_builder/test_files/scripter_test/manifest
|
750
771
|
- test/roku_builder/test_files/scripter_test/test.pkg
|