lti2 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,230 @@
1
+ require "test/unit"
2
+ require "rubygems"
3
+ require 'json'
4
+ require 'jsonpath'
5
+
6
+ require File.expand_path('../../lib/lti2_commons/json_wrapper', __FILE__)
7
+ require File.expand_path('../../lib/lti2_commons/utils', __FILE__)
8
+
9
+ include Lti2Commons
10
+ include Utils
11
+
12
+ class TestJsonWrapper < Test::Unit::TestCase
13
+ def setup
14
+ @json_str =
15
+ <<PROXY
16
+ {
17
+ "@context" : [
18
+ "http://www.imsglobal.org/imspurl/lti/v2/ctx/ToolProxy",
19
+ "http://purl.org/blackboard/ctx/v1/iconStyle"
20
+ ],
21
+ "@type" : "ToolProxy",
22
+ "@id" : "http://fabericious..com/ToolProxy/869e5ce5-214c-4e85-86c6-b99e8458a592",
23
+ "lti_version" : "LTI-2p0",
24
+ "tool_proxy_guid" : "869e5ce5-214c-4e85-86c6-b99e8458a592",
25
+ "tool_consumer_profile" : "http://lms.example.com/profile/b6ffa601-ce1d-4549-9ccf-145670a964d4",
26
+ "tool_profile" : {
27
+ "lti_version" : "LTI-2p0",
28
+ "product_instance" : {
29
+ "guid" : "fd75124a-140e-470f-944c-114d2d92bb40",
30
+ "product_info" : {
31
+ "product_name" : {
32
+ "default_value" : "Acme Assessments",
33
+ "key" : "tool.name"
34
+ },
35
+ "description" : {
36
+ "default_value" : "Acme Assessments provide an interactive test format.",
37
+ "key" : "tool.description"
38
+ },
39
+ "product_version" : "10.3",
40
+ "technical_description" : {
41
+ "default_value" : "Support provided for all LTI 1 extensions as well as LTI 2",
42
+ "key" : "tool.technical"
43
+ },
44
+ "product_family" : {
45
+ "code" : "assessment-tool",
46
+ "vendor" : {
47
+ "code" : "acme.com",
48
+ "name" : {
49
+ "default_value" : "Acme",
50
+ "key" : "tool.vendor.name"
51
+ },
52
+ "description" : {
53
+ "default_value" : "Acme is a leading provider of interactive tools for education",
54
+ "key" : "tool.vendor.description"
55
+ },
56
+ "website" : "http://acme.example.com",
57
+ "timestamp" : "2012-04-05T09:08:16-04:00",
58
+ "contact" : {
59
+ "email" : "info@example.com"
60
+ }
61
+ }
62
+ }
63
+ },
64
+ "support" : {
65
+ "email" : "helpdesk@example.com"
66
+ },
67
+ "service_provider" : {
68
+ "guid" : "18e7ea50-3d6d-4f6b-aff2-ed3ab577716c",
69
+ "provider_name" : {
70
+ "default_value" : "Acme Hosting",
71
+ "key" : "service_provider.name"
72
+ },
73
+ "description" : {
74
+ "default_value" : "Provider of high performance managed hosting environments",
75
+ "key" : "service_provider.description"
76
+ },
77
+ "support" : {
78
+ "email" : "support@acme-hosting.example.com"
79
+ },
80
+ "timestamp" : "2012-04-05T09:08:16-04:00"
81
+ }
82
+ },
83
+ "base_url_choice" : [
84
+ { "default_base_url" : "http://acme.example.com",
85
+ "secure_base_url" : "https://acme.example.com",
86
+ "selector" : {
87
+ "applies_to" : [
88
+ "IconEndpoint",
89
+ "MessageHandler"
90
+ ]
91
+ }
92
+ }
93
+ ],
94
+ "resource_handler" : [
95
+ {
96
+ "resource_type": "urn:lti:ResourceType:{fabericious.lti.org}/handler/launchRequest",
97
+ "name" : {
98
+ "default_value" : "Acme Assessment",
99
+ "key" : "assessment.resource.name"
100
+ },
101
+ "description" : {
102
+ "default_value" : "An interactive assessment using the Acme scale.",
103
+ "key" : "assessment.resource.description"
104
+ },
105
+ "message" : [{
106
+ "message_type" : "basic-lti-launch-request",
107
+ "path" : "/handler/launchRequest",
108
+ "capability" : [
109
+ "Result.autocreate",
110
+ "Result.sourcedGUID"
111
+ ],
112
+ "parameter" : [
113
+ { "name" : "result_id",
114
+ "variable" : "$Result.sourcedGUID"
115
+ },
116
+ { "name" : "discipline",
117
+ "fixed" : "chemistry"
118
+ }
119
+ ]
120
+ }],
121
+ "icon_info" : [
122
+ {
123
+ "default_location" : {
124
+ "path" : "/images/bb/en/icon.png"
125
+ },
126
+ "key" : "iconStyle.default.path"
127
+ },
128
+ { "icon_style" : "BbListElementIcon",
129
+ "default_location" : {
130
+ "path" : "/images/bb/en/listElement.png"
131
+ },
132
+ "key" : "iconStyle.bb.listElement.path"
133
+ },
134
+ { "icon_style" : "BbPushButtonIcon",
135
+ "default_location" : {
136
+ "path" : "images/bb/en/pushButton.png"
137
+ },
138
+ "key" : "iconStyle.bb.pushButton.path"
139
+ }
140
+ ]
141
+ }
142
+ ]
143
+ },
144
+ "security_contract" : {
145
+ "shared_secret" : "ThisIsASecret!",
146
+ "tool_service" : [
147
+ { "@type" : "RestServiceProfile",
148
+ "service" : "http://lms.example.com/profile/b6ffa601-ce1d-4549-9ccf-145670a964d4#ToolProxy.collection",
149
+ "action" : "POST"
150
+ },
151
+ { "@type" : "RestServiceProfile",
152
+ "service" : "http://lms.example.com/profile/b6ffa601-ce1d-4549-9ccf-145670a964d4#ToolProxy.item",
153
+ "action" : [
154
+ "GET",
155
+ "PUT"
156
+ ]
157
+ },
158
+ { "@type" : "RestService",
159
+ "service" : "http://lms.example.com/profile/b6ffa601-ce1d-4549-9ccf-145670a964d4#Result.item",
160
+ "action" : [
161
+ "GET",
162
+ "PUT"
163
+ ]
164
+ }
165
+ ]
166
+ }
167
+ }
168
+ PROXY
169
+
170
+ @json_wrapper = JsonWrapper.new @json_str
171
+ end
172
+
173
+ def test_constuctor
174
+ assert_not_nil @json_wrapper.root
175
+ end
176
+
177
+ def test_at
178
+ assert_equal ["869e5ce5-214c-4e85-86c6-b99e8458a592"], @json_wrapper.at('tool_proxy_guid')
179
+ end
180
+
181
+ def test_first_at
182
+ assert_equal "869e5ce5-214c-4e85-86c6-b99e8458a592", @json_wrapper.first_at('tool_proxy_guid')
183
+ assert_nil @json_wrapper.first_at('asdf')
184
+ end
185
+
186
+ def test_each_leaf
187
+ counter = 0
188
+ @json_wrapper.each_leaf { |node| counter += 1 }
189
+ assert_equal 70, counter
190
+ end
191
+
192
+ def test_deep_copy
193
+ new_json_wrapper = @json_wrapper.deep_copy
194
+ assert_not_equal new_json_wrapper.object_id, @json_wrapper.object_id
195
+ assert_equal "869e5ce5-214c-4e85-86c6-b99e8458a592", new_json_wrapper.first_at('tool_proxy_guid')
196
+ end
197
+
198
+ def test_search
199
+ assert_equal "/handler/launchRequest",
200
+ ( @json_wrapper.search 'tool_profile.resource_handler..message',
201
+ { 'message_type' => "basic-lti-launch-request" },
202
+ "path")
203
+ assert_nil @json_wrapper.search 'tool_profile.resource_handler..message',
204
+ { 'message_type' => "basic-lti-launch-request" },
205
+ "xxxx"
206
+ assert_nil @json_wrapper.search 'tool_profile.resource_handler..message',
207
+ { 'message_type' => "xxx" },
208
+ "path"
209
+ end
210
+
211
+ def test_select
212
+ assert_equal "http://acme.example.com",
213
+ @json_wrapper.select('tool_profile.base_url_choice',
214
+ "selector.applies_to", "MessageHandler", 'default_base_url')
215
+ assert_equal nil, @json_wrapper.select('tool_profile.xxxxx',
216
+ "selector.applies_to", "MessageHandler", 'default_base_url')
217
+ end
218
+
219
+ def test_each_deep_with_substitution
220
+ hash = {"root" => {"child1" => "{value}1", "child2" => {"grandchild1" => "{grand}{value}1"}, "child3" => "{value}3"}}
221
+ json_hash = JsonWrapper.new hash
222
+ subst_hash = {'value' => 'VLU', 'great' => 'GRT', 'grand' => 'GRND'}
223
+ json_hash.substitute_text_in_all_nodes '{', '}', subst_hash
224
+ assert_equal "VLU1", json_hash.first_at('$..child1')
225
+ assert_equal "GRNDVLU1", json_hash.first_at('$..grandchild1')
226
+ end
227
+
228
+ ARGV = ['', "--name", "test_select"]
229
+ # Test::Unit::AutoRunner.run(false, nil, ARGV)
230
+ end
@@ -0,0 +1,143 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/lti2_commons/message_support', __FILE__)
3
+ require File.expand_path('../../lib/lti2_commons/cache', __FILE__)
4
+ require File.expand_path('../../lib/lti2_commons/utils', __FILE__)
5
+ require File.expand_path('../../lib/lti2_commons/signer', __FILE__)
6
+ require File.expand_path('../../lib/lti2_commons/oauth_request', __FILE__)
7
+
8
+ require 'rack'
9
+ require 'oauth'
10
+
11
+ include Lti2Commons
12
+ include Signer
13
+ include Utils
14
+ include MessageSupport
15
+ include OAuth::RequestProxy
16
+
17
+ class TestOAuthRequest < Test::Unit::TestCase
18
+ def setup
19
+ @launch_url = 'http://localhost:3000/tenants/3'
20
+ # @launch_url = 'http://vst-bc.com/tenants/3/books'
21
+ @http_method = 'post'
22
+ @consumer_key = '12345'
23
+ @consumer_secret = 'secret'
24
+ @params = {'oauth_consumer_key'=>'12345', 'oauth_signature_method'=> "HMAC-SHA1", 'user_id'=>'jt'}
25
+ @oauth_request = OAuth::OAuthProxy::OAuthRequest.new \
26
+ "method" => @http_method,
27
+ "uri" => @launch_url,
28
+ "parameters" => @params
29
+ @nonce_cache = Lti2Commons::Cache.new :ttl => 300
30
+ end
31
+
32
+ def create_stale_request(minutes_stale)
33
+ now = Time::now
34
+ stale_time = now + (minutes_stale*60.0)
35
+ # puts "Now: #{now} Stale_time: #{stale_time}]"
36
+ params = @params.dup
37
+ params['oauth_timestamp'] = stale_time.to_i
38
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, params
39
+ # dump_oauth_parameters request, "stale create"
40
+ request
41
+ end
42
+
43
+ def dump_oauth_parameters(request, label=nil)
44
+ puts ">>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>"
45
+ if label
46
+ puts "*** #{label}"
47
+ end
48
+ puts "non_oauth_parameters: #{request.non_oauth_parameters.inspect}"
49
+ puts "oauth_header: #{request.oauth_header}"
50
+ puts "oauth_parameters: #{request.oauth_parameters.inspect}"
51
+ puts "signature_base_string: #{request.signature_base_string}"
52
+ puts "signed? #{request.signed?}"
53
+ puts "signed_uri: #{request.signed_uri}"
54
+ puts "<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<"
55
+ end
56
+
57
+ def test_oauth_request
58
+ request = Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, @params
59
+ dump_oauth_parameters(request, 'postsigning')
60
+ end
61
+
62
+ def test_valid_request
63
+ request = Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, @params
64
+ assert_not_nil request
65
+ assert_equal true, request.verify_signature?(@consumer_secret, @nonce_cache)
66
+ end
67
+
68
+ def test_create_signed_request_simple_post
69
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, @params
70
+ assert_not_nil request
71
+ signature_base_string = request.signature_base_string
72
+ assert_equal "POST&http%3A%2F%2Flocalhost%3A3000%2Ftenants%2F3&basiclti_submit%3DPress%2520t", signature_base_string[0..77]
73
+ end
74
+
75
+ def test_create_signed_request_get
76
+ request = Lti2Commons::Signer.create_signed_request @launch_url, 'get', @consumer_key, @consumer_secret, @params
77
+ assert_not_nil request
78
+ signature_base_string = request.signature_base_string
79
+ assert_equal "GET&http%3A%2F%2Flocalhost%3A3000%2Ftenants%2F3&basiclti_submit%3DPress%2520t", signature_base_string[0..76]
80
+ end
81
+
82
+ def test_create_signed_request_put
83
+ request = Lti2Commons::Signer.create_signed_request @launch_url, 'put', @consumer_key, @consumer_secret, @params
84
+ assert_not_nil request
85
+ signature_base_string = request.signature_base_string
86
+ assert_equal "PUT&http%3A%2F%2Flocalhost%3A3000%2Ftenants%2F3&basiclti_submit%3DPress%2520t", signature_base_string[0..76]
87
+ end
88
+
89
+ def test_lti_message_body_from_signed_request
90
+ request = Signer.create_signed_request @launch_url, 'put', @consumer_key, @consumer_secret, @params
91
+ assert_not_nil request
92
+ assert_not_nil MessageSupport.create_lti_message_body_from_signed_request request
93
+ puts MessageSupport.create_lti_message_body_from_signed_request request
94
+ end
95
+
96
+ def test_lti_message_body
97
+ assert_not_nil MessageSupport.create_lti_message_body @launch_url, @params
98
+ puts MessageSupport.create_lti_message_body @launch_url, @params
99
+ end
100
+
101
+ def test_break_signature
102
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, @params
103
+ request.parameters['oauth_signature'] = "asdf"
104
+ assert_equal false, (request.verify_signature? @consumer_secret, @nonce_cache)
105
+ end
106
+
107
+ def test_exception_on_signature_error
108
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, @params
109
+ request.parameters['oauth_signature'] = "asdf"
110
+ begin
111
+ request.verify_signature? @consumer_secret, @nonce_cache, false
112
+ fail "Exception expected here"
113
+ rescue
114
+ # expected
115
+ end
116
+ end
117
+
118
+ def test_timeout_within_margin
119
+ request = create_stale_request 2
120
+ assert_equal true, (request.verify_signature? @consumer_secret, @nonce_cache)
121
+ request = create_stale_request(-2)
122
+ assert_equal true, (request.verify_signature? @consumer_secret, @nonce_cache)
123
+ end
124
+
125
+ def test_timeout_error
126
+ request = create_stale_request 10
127
+ assert_equal false, (request.verify_signature? @consumer_secret, @nonce_cache)
128
+ request = create_stale_request(-10)
129
+ assert_equal false, (request.verify_signature? @consumer_secret, @nonce_cache)
130
+ end
131
+
132
+ def test_duplicate_nonce
133
+ params = @params.dup
134
+ params['oauth_nonce'] = "1234"
135
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, params
136
+ assert_equal true, (request.verify_signature? @consumer_secret, @nonce_cache)
137
+ request = Lti2Commons::Signer.create_signed_request @launch_url, @http_method, @consumer_key, @consumer_secret, params
138
+ assert_equal false, (request.verify_signature? @consumer_secret, @nonce_cache)
139
+ end
140
+
141
+ ARGV = ['', "--name", "test_duplicate_nonce"]
142
+ Test::Unit::AutoRunner.run(false, nil, ARGV)
143
+ end
@@ -0,0 +1,71 @@
1
+ require 'test/unit'
2
+ require File.expand_path('../../lib/lti2_commons/substitution_support', __FILE__)
3
+
4
+ include Lti2Commons
5
+ include SubstitutionSupport
6
+
7
+
8
+ class TestObject
9
+ attr_accessor :user_id, :name
10
+
11
+ def initialize
12
+ @user_id = 'jt'
13
+ @name = "john.thomas"
14
+ @code = @name.reverse
15
+ end
16
+
17
+ def to_s
18
+ @user_id
19
+ end
20
+ end
21
+
22
+ class TestSubstitutionSupport < Test::Unit::TestCase
23
+ def setup
24
+ @resolver = Resolver.new
25
+ @resolver.add_resolver "user", {'name' => "jt", 'id' => "1234"}
26
+ @resolver.add_resolver "user", {'name' => "jt", 'id' => "9876", 'sport' => 'judo'}
27
+ @resolver.add_resolver "course", lambda { |x| "COURSE-#{x}"}
28
+ @resolver.add_resolver "resource", self.method(:resource_transform_sample)
29
+ @resolver.add_resolver "testobject", TestObject.new
30
+ @resolver.add_resolver "testnest", {'nestlevel' => 'inner'}
31
+ @resolver.add_resolver "*", {'ip'=> '192.168.2.177'}
32
+ end
33
+
34
+ def resource_transform_sample(name)
35
+ name.reverse
36
+ end
37
+
38
+ def test_add_hash
39
+ assert_equal "jt", @resolver.resolve('user.name')
40
+ assert_equal "judo", @resolver.resolve('user.sport')
41
+ assert_equal "192.168.2.177", @resolver.resolve('user.ip')
42
+ assert_equal "192.168.2.177", @resolver.resolve('foo.ip')
43
+ assert_equal "user.notfound", @resolver.resolve('user.notfound')
44
+ end
45
+
46
+ def test_add_block
47
+ assert_equal "COURSE-anything", @resolver.resolve('course.anything')
48
+ end
49
+
50
+ def test_internal_method
51
+ assert_equal "fdsa", @resolver.resolve('resource.asdf')
52
+ end
53
+
54
+ def test_testobject
55
+ assert_equal "john.thomas", @resolver.resolve('testobject.name')
56
+ end
57
+
58
+ def test_nested_resolver
59
+ outer_resolver = Resolver.new
60
+ outer_resolver.add_resolver "testnest", {'nestlevel' => 'outer'}
61
+ outer_resolver.add_resolver "inner", @resolver
62
+
63
+ assert_equal "inner", @resolver.resolve('testnest.nestlevel')
64
+ assert_equal "outer", outer_resolver.resolve('testnest.nestlevel')
65
+ assert_equal "jt", outer_resolver.resolve('user.name')
66
+ assert_equal "COURSE-anything", outer_resolver.resolve('course.anything')
67
+ end
68
+
69
+ ARGV = ['', "--name", "test_nested_resolver"]
70
+ # Test::Unit::AutoRunner.run(false, nil, ARGV)
71
+ end
@@ -0,0 +1,15 @@
1
+ require File.expand_path('../../lib/lti2_commons/wire_log', __FILE__)
2
+ require File.expand_path('../../lib/lti2_commons/mock_request', __FILE__)
3
+
4
+ wl = Lti2Commons::WireLogSupport::WireLog.new 'test', 'test.txt'
5
+
6
+ wl.clear_log
7
+ wl.log 'test'
8
+ wl.log 'tube'
9
+
10
+ wl.log <<aa
11
+ hello,
12
+ how are you?
13
+ aa
14
+
15
+ puts 'done'