嗨,我在app/controllers/lti_controller.rb
有一个控制器文件,我需要为POST #launch
端点添加测试,该端点在routes.rb
中定义为/lti/launch
,并按预期工作。
问题
我需要以x-www-form-urlencoded
的编码格式向/lti/launch
发送一些数据,并使用Net::HTTP从规范文件中完成此操作。但是由于Net::HTTP需要host
和port
来进行操作,我现在已经给出了localhost:3000
,它将用于development
环境。
提问
1.如何在Rspec 3.10中访问测试环境的主机和端口,以便我可以在spec文件中传递它们?
1.有没有办法使用post
'/lti/launch',req.body:x-www-form-urlencoded
的数据`?并获取测试环境的主机和端口?
我的Spec文件
spec/requests/lti_spec.rb
# frozen_string_literal: true
require "rails_helper"
require 'uri'
require 'net/http'
describe LtiController, type: :request do
before do
# shared keys for lms access
@oauth_consumer_key_fromlms = 'some_keys'
@oauth_shared_secret_fromlms = 'some_secrets'
end
describe "#launch" do
before do
# creation of assignment and required users
@mentor = FactoryBot.create(:user)
@group = FactoryBot.create(:group, mentor: @mentor)
@member = FactoryBot.create(:user)
FactoryBot.create(:group_member, user: @member, group: @group)
@assignment = FactoryBot.create(:assignment, group: @group, lti_consumer_key: @oauth_consumer_key_fromlms, lti_shared_secret: @oauth_shared_secret_fromlms, status: "open")
end
def launch_uri
launch_url = "http://0.0.0.0:3000/lti/launch"
URI(launch_url)
end
let(:parameters) {
{
'launch_url' => launch_uri().to_s,
'user_id' => @member.id,
'launch_presentation_return_url' => 'http://localhost:3000/tool_return',
'lti_version' => 'LTI-1p0',
'lti_message_type' => 'basic-lti-launch-request',
'resource_link_id' => '88391-e1919-bb3456',
'lis_person_contact_email_primary' => @member.email,
'tool_consumer_info_product_family_code' => 'moodle',
'context_title' => 'sample Course',
'lis_outcome_service_url' => 'http://localhost:3000/grade_passback',
'lis_result_sourcedid' => SecureRandom.hex(10)
}
}
def consumer_data(oauth_consumer_key_fromlms, oauth_shared_secret_fromlms, parameters)
consumer = IMS::LTI::ToolConsumer.new(oauth_consumer_key_fromlms, oauth_shared_secret_fromlms, parameters)
allow(consumer).to receive(:to_params).and_return(parameters)
consumer.generate_launch_data
end
context "lti parameters are valid" do
it "returns success if assignment key and secret are ok and group member is present" do
data = consumer_data(@oauth_consumer_key_fromlms, @oauth_shared_secret_fromlms, parameters)
response = Net::HTTP.post_form(launch_uri(), data)
expect(response.code).to eq("200")
end
end
end
end
我的Controller文件
app/controllers/lti_controller.rb
class LtiController < ApplicationController
skip_before_action :verify_authenticity_token, only: :launch # for lti integration
before_action :set_group_assignment, only: %i[launch]
before_action :set_lti_params, only: %i[launch]
after_action :allow_iframe_lti, only: %i[launch]
def launch
session[:is_lti]=true # the lti session starting
require 'oauth/request_proxy/action_controller_request'
if @assignment.blank?
# if no assignment is found
flash[:notice] = t("lti.launch.notice_no_assignment")
render :launch_error, status: 401
return
end
if @group.present? # if there is a valid group based for the lti_token_key
@provider = IMS::LTI::ToolProvider.new(
params[:oauth_consumer_key], # lms_oauth_consumer_key
@assignment.lti_shared_secret, # the group's lti_token
params
)
if [email protected]_request?(request) # checking the lti request from the lms end
render :launch_error, status: 401
return
end
lms_lti_host = URI.join @launch_url_from_lms, '/' # identifies the domain and saves in session
session[:lms_domain]=lms_lti_host
@user = User.find_by(email: @email_from_lms) # find user by matching email with circuitverse and lms
if @user.present? # user is present in cv
if @user.id == @group.mentor_id # user is teacher
sign_in(@user) # passwordless sign_in the user as the authenticity is verified via lms
lms_auth_success_notice = t("lti.launch.notice_lms_auth_success_teacher", email_from_lms: @email_from_lms, lms_type: @lms_type, course_title_from_lms: @course_title_from_lms)
redirect_to group_assignment_path(@group, @assignment), notice: lms_auth_success_notice # if auth_success send to group page
else
user_in_group = GroupMember.find_by(user_id:@user.id,group_id:@group.id) # check if the user belongs to the cv group
if user_in_group.present? # user is member of the group
# render the button
flash[:notice] = t("lti.launch.notice_students_open_in_cv")
create_project_if_student_present() # create project with lis_result_sourced_id for the student
render :open_incv, status: 200
else # user is not a member of the group
# send the user an email
flash[:notice] = t("lti.launch.notice_ask_teacher")
render :launch_error, status: 401
end
end
else # no such user in circuitverse,showing a notice to create an account in cv
flash[:notice] = t("lti.launch.notice_no_account_in_cv", email_from_lms: @email_from_lms )
render :launch_error, status: 400
end
else # there is no valid group present for the lti_consumer_key
flash[:notice] = t("lti.launch.notice_invalid_group")
render :launch_error, status: 400
end
end
def allow_iframe_lti
return unless session[:is_lti]
response.headers["X-FRAME-OPTIONS"] = "ALLOW-FROM #{session[:lms_domain]}"
end
def create_project_if_student_present
@user = User.find_by(email: @email_from_lms)
@project = Project.find_by(author_id: @user.id, assignment_id: @assignment.id) # find if the project is already present
if @project.blank? # if not then create one
@project = @user.projects.new
@project.name = "#{@user.name}/#{@assignment.name}"
@project.assignment_id = @assignment.id
@project.project_access_type = "Private"
@project.build_project_datum
@project.lis_result_sourced_id = params[:lis_result_sourcedid] # this param is required for grade submission
@project.save
end
end
private
def set_group_assignment # query db and check lms_oauth_consumer_key is equal to which assignment and find the group also
@assignment = Assignment.find_by(lti_consumer_key: params[:oauth_consumer_key])
if @assignment.present?
@group [email protected]
end
end
def set_lti_params # get some of the parameters from the lti request
@email_from_lms = params[:lis_person_contact_email_primary] # the email from the LMS
@lms_type = params[:tool_consumer_info_product_family_code] # type of lms like moodle/canvas
@course_title_from_lms = params[:context_title] # the course titile from lms
@launch_url_from_lms = params[:launch_presentation_return_url]
session[:lis_outcome_service_url] = params[:lis_outcome_service_url] # requires for grade submission
session[:oauth_consumer_key] = params[:oauth_consumer_key] # requires for grade submission
end
end
需要发送的样本数据
{"oauth_consumer_key"=>"some_keys", "oauth_signature_method"=>"HMAC-SHA1", "oauth_timestamp"=>"1627879512", "oauth_nonce"=>"Id3rLYZBqMvnRuSpisMEEgFkLFnkxZPS2oqoyBJZLM", "oauth_version"=>"1.0", "context_title"=>"sample Course", "launch_presentation_return_url"=>"http://localhost:3000/tool_return", "launch_url"=>"http://0.0.0.0:3000/lti/launch", "lis_outcome_service_url"=>"http://localhost:3000/grade_passback", "lis_person_contact_email_primary"=>"[email protected]", "lis_result_sourcedid"=>"3e87e3aa8f5056260a12", "lti_message_type"=>"basic-lti-launch-request", "lti_version"=>"LTI-1p0", "resource_link_id"=>"88391-e1919-bb3456", "tool_consumer_info_product_family_code"=>"moodle", "user_id"=>"461", "oauth_signature"=>"lgsHKJxHolBU1rTZ5M9zXg688hU="}
2条答案
按热度按时间yizd12fk1#
在Rspec中,您可以在发出请求之前设置主机。
如果你想为所有的spec设置主机,你可以创建一个如下配置:
要使用
x-www-form-urlencoded
发布,您可以尝试以下操作:4ngedf3f2#
你不需要知道主机和端口。并且您不应该直接手动使用
Net::HTTP
执行请求。get
/post
/.助手们处理这个。https://relishapp.com/rspec/rspec-rails/v/5-0/docs/request-specs/request-spec