Skip to content

Conversation

@ttqureshi
Copy link
Member

@ttqureshi ttqureshi commented Dec 12, 2024

Test the LTI XBlock in both built-in and extracted modes to keep them in sync.

Related to: #36281

@ttqureshi ttqureshi marked this pull request as draft December 12, 2024 08:31
@ttqureshi ttqureshi marked this pull request as ready for review December 12, 2024 08:37
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from ba481cd to 8343717 Compare December 12, 2024 08:40
@ttqureshi ttqureshi marked this pull request as draft December 12, 2024 09:21
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 4 times, most recently from d132ef3 to eaf2743 Compare February 17, 2025 10:19
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 4 times, most recently from 8a886fd to 48be2e4 Compare February 21, 2025 05:57
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from cf6d9cc to 995261a Compare March 17, 2025 09:35
@ttqureshi
Copy link
Member Author

ttqureshi commented Apr 3, 2025

@kdmccormick
test_number_mongo_calls this test case is failing with the test params expecting 37 mongo calls as in 2nd, 3rd and 4th test case parameters.

With the flag (USE_EXTRACTED_LTI_BLOCK) set to True, 36 calls are made and thus assertion fails. I have tried to figure out the reason but couldn't get any clue.

I'm sharing the output diff here. Please take a look, and guide me what could be the possible way-outs.

cc: @feanil @farhan

@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from f5560d2 to efc6cb7 Compare April 4, 2025 13:25
@farhan
Copy link
Contributor

farhan commented Apr 5, 2025

@ttqureshi

test_number_mongo_calls this test case is failing with the test params expecting 37 mongo calls as in 2nd, 3rd and 4th test case parameters.

  1. We are not adding the EmptyDataRawMixin in the extracted XBlock.
  2. EmptyDataRawMixin has data String field which is missing in the extracted XBlock
  3. This 1 less field is causing 1 less mongo DB call. So either
    a. add this data field for initial extraction to make exact code
    b. or decrease 1 count in test case

Note: I don't have technical depth of the mongo calls working, it needs to be explored

@ttqureshi
Copy link
Member Author

ttqureshi commented Apr 7, 2025

@farhan
Thanks for giving the pointers.

  1. We are not adding the EmptyDataRawMixin in the extracted XBlock.
  2. EmptyDataRawMixin has data String field which is missing in the extracted XBlock
  3. This 1 less field is causing 1 less mongo DB call. So either
    a. add this data field for initial extraction to make exact code
    b. or decrease 1 count in test case

Seems like this is causing the issue. Let me try things around first, and IMO decreasing the count by 1 in the test case (inside if condition) sounds more reasonable than adding extra data field that is not required anywhere in the extracted LTIBlock.

@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 3 times, most recently from 373aa3e to 58f8e54 Compare April 10, 2025 13:38
@kdmccormick kdmccormick self-requested a review April 10, 2025 17:14
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 2 times, most recently from 324c681 to 9c4c049 Compare April 15, 2025 09:46
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from 9c4c049 to b5f2551 Compare April 16, 2025 13:44
@kdmccormick kdmccormick self-assigned this Aug 1, 2025
@kdmccormick kdmccormick removed their request for review August 14, 2025 17:03
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from 4164531 to b2ffa96 Compare September 16, 2025 08:36
@ttqureshi
Copy link
Member Author

@mphilbrick211
YES, it's a WIP. It is currently blocked on this. This is the new story for the #XBlock/823.

@mphilbrick211 mphilbrick211 added blocked by other work PR cannot be finished until other work is complete and removed inactive PR author has been unresponsive for several months labels Dec 12, 2025
@mphilbrick211 mphilbrick211 moved this from Waiting on Author to Blocked in Contributions Dec 12, 2025
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 3 times, most recently from c6d0b64 to 80773ab Compare January 1, 2026 13:47
@ttqureshi ttqureshi marked this pull request as ready for review January 2, 2026 08:37
@ttqureshi ttqureshi requested a review from salman2013 January 2, 2026 09:46
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from ae9edf1 to faf53a8 Compare January 2, 2026 10:24

@ddt.data(*PER_COURSE_ANONYMIZED_XBLOCKS)
def test_per_course_anonymized_id(self, xblock_class):
if settings.USE_EXTRACTED_LTI_BLOCK and not hasattr(xblock_class, 'bind_for_student'):
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why we only need it in case of Extracted LTI block.
As per discussion we need to explore bind_for_student.
Perhaps if its necessary for the block we should do it in the extracted block rather than only do it in the test case.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No, we don't need to add bind_for_student method as it's not specific to LTIBlock. This method is called while loading the preview (cms/djangoapps/contentstore/views/preview.py) by the runtime. So there's no need to add it in the LTIBlock class.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As per discussion further testing is required in case of Extracted LTI block, how the block behaves on following code.

    _prepare_runtime_for_preview(request, block)

    block.bind_for_student(
        request.user.id,
        [wrapper]
    )
    return block

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I've tested this by putting a debugger, in both cases (built-in and extracted), bind_for_student method is being called form XModuleMixin.

@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch 4 times, most recently from 4268a6b to 3004f24 Compare January 5, 2026 13:25
@farhan
Copy link
Contributor

farhan commented Jan 5, 2026

We per discussion this XBlock needs to be properly tested on the Content Library - V2 like we have tested the other XBlocks.

Here is some crash logs while testing on content-library:

Traceback (most recent call last):
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/pyenv/versions/3.11.8/lib/python3.11/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/generic/base.py", line 105, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 512, in dispatch
    response = handler(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/decorators.py", line 50, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/clickjacking.py", line 86, in _view_wrapper
    response = view_func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/rest_api/views.py", line 118, in embed_block_view
    fragment = _render_block_view(block, view_name, request.user)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/api.py", line 261, in render_block_view
    fragment = block.render(view_name)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/core.py", line 818, in render
    return self.runtime.render(self, view, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py", line 415, in render
    fragment = super().render(block, view_name, context)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/shims.py", line 41, in render
    return super().render(block, view_name, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/runtime.py", line 823, in render
    frag = view_fn(context)
           ^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 536, in student_view
    "templates/lti.html", self.get_context(),
                          ^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 508, in get_context
    'input_fields': self.get_input_fields(),
                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 438, in get_input_fields
    client_key, client_secret = self.get_client_key_secret()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 994, in get_client_key_secret
    course = self.get_course()
             ^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 767, in get_course
    return self.runtime.modulestore.get_course(self.location.course_key)
           ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'LearningCoreXBlockRuntime' object has no attribute 'modulestore'
Internal Server Error: /xblocks/v2/lb:axim:lib1:lti:28d163a1-8bdb-4ce4-919d-7dcff9bb739c/embed/student_view/
Traceback (most recent call last):
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/pyenv/versions/3.11.8/lib/python3.11/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/generic/base.py", line 105, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 512, in dispatch
    response = handler(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/decorators.py", line 50, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/clickjacking.py", line 86, in _view_wrapper
    response = view_func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/rest_api/views.py", line 118, in embed_block_view
    fragment = _render_block_view(block, view_name, request.user)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/api.py", line 261, in render_block_view
    fragment = block.render(view_name)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/core.py", line 818, in render
    return self.runtime.render(self, view, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py", line 415, in render
    fragment = super().render(block, view_name, context)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/shims.py", line 41, in render
    return super().render(block, view_name, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/runtime.py", line 823, in render
    frag = view_fn(context)
           ^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 536, in student_view
    "templates/lti.html", self.get_context(),
                          ^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 508, in get_context
    'input_fields': self.get_input_fields(),
                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 438, in get_input_fields
    client_key, client_secret = self.get_client_key_secret()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 994, in get_client_key_secret
    course = self.get_course()
             ^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 767, in get_course
    return self.runtime.modulestore.get_course(self.location.course_key)
           ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'LearningCoreXBlockRuntime' object has no attribute 'modulestore'
2026-01-05 14:13:39,088 ERROR 25 [django.request] [user None] [ip None] log.py:253 - Internal Server Error: /xblocks/v2/lb:axim:lib1:lti:28d163a1-8bdb-4ce4-919d-7dcff9bb739c/embed/student_view/
Traceback (most recent call last):
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/exception.py", line 55, in inner
    response = get_response(request)
               ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/core/handlers/base.py", line 197, in _get_response
    response = wrapped_callback(request, *callback_args, **callback_kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/opt/pyenv/versions/3.11.8/lib/python3.11/contextlib.py", line 81, in inner
    return func(*args, **kwds)
           ^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/csrf.py", line 65, in _view_wrapper
    return view_func(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/generic/base.py", line 105, in view
    return self.dispatch(request, *args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 515, in dispatch
    response = self.handle_exception(exc)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 475, in handle_exception
    self.raise_uncaught_exception(exc)
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 486, in raise_uncaught_exception
    raise exc
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/views.py", line 512, in dispatch
    response = handler(request, *args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/rest_framework/decorators.py", line 50, in handler
    return func(*args, **kwargs)
           ^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/venv/lib/python3.11/site-packages/django/views/decorators/clickjacking.py", line 86, in _view_wrapper
    response = view_func(*args, **kwargs)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/rest_api/views.py", line 118, in embed_block_view
    fragment = _render_block_view(block, view_name, request.user)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/api.py", line 261, in render_block_view
    fragment = block.render(view_name)
               ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/core.py", line 818, in render
    return self.runtime.render(self, view, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/runtime.py", line 415, in render
    fragment = super().render(block, view_name, context)
               ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/openedx/edx-platform/openedx/core/djangoapps/xblock/runtime/shims.py", line 41, in render
    return super().render(block, view_name, context)
           ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblock/xblock/runtime.py", line 823, in render
    frag = view_fn(context)
           ^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 536, in student_view
    "templates/lti.html", self.get_context(),
                          ^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 508, in get_context
    'input_fields': self.get_input_fields(),
                    ^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 438, in get_input_fields
    client_key, client_secret = self.get_client_key_secret()
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 994, in get_client_key_secret
    course = self.get_course()
             ^^^^^^^^^^^^^^^^^
  File "/mnt/xblocks-contrib/xblocks_contrib/lti/lti.py", line 767, in get_course
    return self.runtime.modulestore.get_course(self.location.course_key)
           ^^^^^^^^^^^^^^^^^^^^^^^^
AttributeError: 'LearningCoreXBlockRuntime' object has no attribute 'modulestore'

@ttqureshi ttqureshi added the create-sandbox open-craft-grove should create a sandbox environment from this PR label Jan 5, 2026
@open-craft-grove
Copy link

Sandbox deployment failed 💥
Please check the settings and requirements.
Retry deployment by pushing a new commit or updating the requirements/settings in the pull request's description.
📜 Failure Logs
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from 3004f24 to f9e7c57 Compare January 6, 2026 07:21
@ttqureshi ttqureshi force-pushed the ttqureshi/test-lti-block branch from f9e7c57 to f6edf0b Compare January 6, 2026 07:21
@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@open-craft-grove
Copy link

Sandbox deployment successful 🚀
🎓 LMS
📝 Studio
ℹ️ Grove Config, Tutor Config, Tutor Requirements

@ttqureshi
Copy link
Member Author

@farhan

We per discussion this XBlock needs to be properly tested on the Content Library - V2 like we have tested the other XBlocks.

Here is some crash logs while testing on content-library:

I've opened an issue to fix this: openedx/xblocks-contrib#132

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

blocked by other work PR cannot be finished until other work is complete create-sandbox open-craft-grove should create a sandbox environment from this PR open-source-contribution PR author is not from Axim or 2U

Projects

Status: Blocked

Development

Successfully merging this pull request may close these issues.

Allow tests for Extracted & BuiltIn LTI XBlock

7 participants