Skip to content

Commit 38dc6c6

Browse files
authored
test: add tests for lp_load command (#403)
This also adds a utility to create in-memory zip files from a directory tree, to aid in future import testing.
1 parent 312d024 commit 38dc6c6

File tree

23 files changed

+456
-1
lines changed

23 files changed

+456
-1
lines changed

openedx_learning/apps/authoring/backup_restore/management/commands/lp_load.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ def handle(self, *args, **options):
2929
message = f'{file_name} loaded successfully'
3030
self.stdout.write(self.style.SUCCESS(message))
3131
except FileNotFoundError as exc:
32-
message = f"Learning package file {file_name} not found"
32+
message = f"Learning package file {file_name} not found: {exc}"
3333
raise CommandError(message) from exc
3434
except Exception as e:
3535
message = f"Failed to load '{file_name}': {e}"

test_utils/zip_file_utils.py

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
"""Utility functions for working with in-memory zip files from folders."""
2+
3+
import io
4+
import zipfile
5+
from pathlib import Path
6+
7+
8+
def folder_to_inmemory_zip(folder_path: str) -> zipfile.ZipFile:
9+
"""
10+
Reads the contents of a folder and returns an in-memory ZipFile object.
11+
12+
Args:
13+
folder_path (str): Path to the folder to zip.
14+
15+
Returns:
16+
zipfile.ZipFile: An in-memory ZipFile containing the folder's contents.
17+
"""
18+
buffer = io.BytesIO()
19+
folder = Path(folder_path)
20+
with zipfile.ZipFile(buffer, "w", compression=zipfile.ZIP_DEFLATED) as zipf:
21+
for file_path in folder.rglob("*"):
22+
if file_path.is_file():
23+
arcname = file_path.relative_to(folder)
24+
zipf.write(file_path, arcname=str(arcname))
25+
buffer.seek(0)
26+
return zipfile.ZipFile(buffer, "r")
Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
[collection]
2+
title = "Collection test1"
3+
key = "collection-test"
4+
description = ""
5+
created = 2025-08-19T04:25:27.754968Z
6+
entities = [
7+
"xblock.v1:html:e32d5479-9492-41f6-9222-550a7346bc37",
8+
"xblock.v1:problem:256739e8-c2df-4ced-bd10-8156f6cfa90b",
9+
]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[entity]
2+
uuid = "0df28dac-aa13-473c-8c41-2f27e10362da"
3+
can_stand_alone = true
4+
key = "section1-8ca126"
5+
created = 2025-09-04T22:51:40.919872Z
6+
7+
[entity.draft]
8+
version_num = 2
9+
10+
[entity.published]
11+
# unpublished: no published_version_num
12+
13+
[entity.container.section]
14+
15+
# ### Versions
16+
17+
[[version]]
18+
title = "Section1"
19+
uuid = "60756ba1-231a-4014-9602-1fba48678674"
20+
version_num = 2
21+
22+
[version.container]
23+
children = ["subsection1-48afa3"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[entity]
2+
uuid = "0b52444b-0604-4510-be71-960251e7343d"
3+
can_stand_alone = true
4+
key = "subsection1-48afa3"
5+
created = 2025-09-04T22:51:52.824941Z
6+
7+
[entity.draft]
8+
version_num = 2
9+
10+
[entity.published]
11+
# unpublished: no published_version_num
12+
13+
[entity.container.subsection]
14+
15+
# ### Versions
16+
17+
[[version]]
18+
title = "Subsection1"
19+
uuid = "46642bce-0861-4e22-8b37-3cd897c99239"
20+
version_num = 2
21+
22+
[version.container]
23+
children = ["unit1-b7eafb"]
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[entity]
2+
uuid = "c1a69936-ac68-4e1d-843a-0708fa7c755b"
3+
can_stand_alone = true
4+
key = "unit1-b7eafb"
5+
created = 2025-09-04T22:51:59.271334Z
6+
7+
[entity.draft]
8+
version_num = 2
9+
10+
[entity.published]
11+
# unpublished: no published_version_num
12+
13+
[entity.container.unit]
14+
15+
# ### Versions
16+
17+
[[version]]
18+
title = "Unit1"
19+
uuid = "f8aa4b20-8271-4838-bbe6-e0164d616c13"
20+
version_num = 2
21+
22+
[version.container]
23+
children = ["xblock.v1:video:22601ebd-9da8-430b-9778-cfe059a98568"]
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
[entity]
2+
uuid = "a919094d-1fd0-40bb-9fe2-66284a80effb"
3+
can_stand_alone = true
4+
key = "xblock.v1:drag-and-drop-v2:4d1b2fac-8b30-42fb-872d-6b10ab580b27"
5+
created = 2025-09-04T22:39:37.001432Z
6+
7+
[entity.draft]
8+
version_num = 2
9+
10+
[entity.published]
11+
# unpublished: no published_version_num
12+
13+
# ### Versions
14+
15+
[[version]]
16+
title = "Drag and Drop"
17+
uuid = "136f72d0-a793-4993-b0b1-8515e0c21e64"
18+
version_num = 2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<drag-and-drop-v2 xblock-family="xblock.v1" data="{&#10; &quot;explanation&quot;: &quot;&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;finish&quot;: &quot;Good work! You have completed this drag and drop problem.&quot;,&#10; &quot;start&quot;: &quot;Drag the items onto the image above.&quot;&#10; },&#10; &quot;items&quot;: [&#10; {&#10; &quot;displayName&quot;: &quot;Goes to the top&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;correct&quot;: &quot;Correct! This one belongs to The Top Zone.&quot;,&#10; &quot;incorrect&quot;: &quot;No, this item does not belong here. Try again.&quot;&#10; },&#10; &quot;id&quot;: 0,&#10; &quot;imageDescription&quot;: &quot;&quot;,&#10; &quot;imageURL&quot;: &quot;&quot;,&#10; &quot;noPadding&quot;: false,&#10; &quot;zones&quot;: [&#10; &quot;top&quot;&#10; ]&#10; },&#10; {&#10; &quot;displayName&quot;: &quot;Goes to the middle&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;correct&quot;: &quot;Correct! This one belongs to The Middle Zone.&quot;,&#10; &quot;incorrect&quot;: &quot;No, this item does not belong here. Try again.&quot;&#10; },&#10; &quot;id&quot;: 1,&#10; &quot;imageDescription&quot;: &quot;&quot;,&#10; &quot;imageURL&quot;: &quot;&quot;,&#10; &quot;noPadding&quot;: false,&#10; &quot;zones&quot;: [&#10; &quot;middle&quot;&#10; ]&#10; },&#10; {&#10; &quot;displayName&quot;: &quot;Goes to the bottom&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;correct&quot;: &quot;Correct! This one belongs to The Bottom Zone.&quot;,&#10; &quot;incorrect&quot;: &quot;No, this item does not belong here. Try again.&quot;&#10; },&#10; &quot;id&quot;: 2,&#10; &quot;imageDescription&quot;: &quot;&quot;,&#10; &quot;imageURL&quot;: &quot;&quot;,&#10; &quot;noPadding&quot;: false,&#10; &quot;zones&quot;: [&#10; &quot;bottom&quot;&#10; ]&#10; },&#10; {&#10; &quot;displayName&quot;: &quot;Goes anywhere&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;correct&quot;: &quot;Of course it goes here! It goes anywhere!&quot;,&#10; &quot;incorrect&quot;: &quot;&quot;&#10; },&#10; &quot;id&quot;: 3,&#10; &quot;imageDescription&quot;: &quot;&quot;,&#10; &quot;imageURL&quot;: &quot;&quot;,&#10; &quot;noPadding&quot;: false,&#10; &quot;zones&quot;: [&#10; &quot;top&quot;,&#10; &quot;middle&quot;,&#10; &quot;bottom&quot;&#10; ]&#10; },&#10; {&#10; &quot;displayName&quot;: &quot;I don't belong anywhere&quot;,&#10; &quot;feedback&quot;: {&#10; &quot;correct&quot;: &quot;&quot;,&#10; &quot;incorrect&quot;: &quot;You silly, there are no zones for this one.&quot;&#10; },&#10; &quot;id&quot;: 4,&#10; &quot;imageDescription&quot;: &quot;&quot;,&#10; &quot;imageURL&quot;: &quot;&quot;,&#10; &quot;noPadding&quot;: false,&#10; &quot;zones&quot;: []&#10; }&#10; ],&#10; &quot;targetImgDescription&quot;: &quot;An isosceles triangle with three layers of similar height. It is shown upright, so the widest layer is located at the bottom, and the narrowest layer is located at the top.&quot;,&#10; &quot;zones&quot;: [&#10; {&#10; &quot;align&quot;: &quot;center&quot;,&#10; &quot;description&quot;: &quot;Use this zone to associate an item with the top layer of the triangle.&quot;,&#10; &quot;height&quot;: 178,&#10; &quot;title&quot;: &quot;The Top Zone&quot;,&#10; &quot;uid&quot;: &quot;top&quot;,&#10; &quot;width&quot;: 196,&#10; &quot;x&quot;: 160,&#10; &quot;y&quot;: 30&#10; },&#10; {&#10; &quot;align&quot;: &quot;center&quot;,&#10; &quot;description&quot;: &quot;Use this zone to associate an item with the middle layer of the triangle.&quot;,&#10; &quot;height&quot;: 138,&#10; &quot;title&quot;: &quot;The Middle Zone&quot;,&#10; &quot;uid&quot;: &quot;middle&quot;,&#10; &quot;width&quot;: 340,&#10; &quot;x&quot;: 86,&#10; &quot;y&quot;: 210&#10; },&#10; {&#10; &quot;align&quot;: &quot;center&quot;,&#10; &quot;description&quot;: &quot;Use this zone to associate an item with the bottom layer of the triangle.&quot;,&#10; &quot;height&quot;: 135,&#10; &quot;title&quot;: &quot;The Bottom Zone&quot;,&#10; &quot;uid&quot;: &quot;bottom&quot;,&#10; &quot;width&quot;: 485,&#10; &quot;x&quot;: 15,&#10; &quot;y&quot;: 350&#10; }&#10; ]&#10;}" display_name="Drag and Drop" item_background_color="" item_text_color="" max_attempts="null" max_items_per_zone="null" mode="standard" question_text="test example" show_question_header="true" show_title="true" weight="1.0"/>
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
[entity]
2+
uuid = "1e5e93ef-c34b-4061-aae2-fbca91db6bcc"
3+
can_stand_alone = true
4+
key = "xblock.v1:html:e32d5479-9492-41f6-9222-550a7346bc37"
5+
created = 2025-08-19T04:25:43.685529Z
6+
7+
[entity.draft]
8+
version_num = 5
9+
10+
[entity.published]
11+
version_num = 4
12+
13+
# ### Versions
14+
15+
[[version]]
16+
title = "Text"
17+
uuid = "23dec9b0-0b2c-4706-9288-6ef4f3c888ea"
18+
version_num = 5
19+
20+
[[version]]
21+
title = "Text"
22+
uuid = "f6ccd316-d603-45ef-ab96-86cf9d3645ae"
23+
version_num = 4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
<html display_name="Text"><![CDATA[<p>Test<img src="/static/me.png" alt="Me" width="500" height="579" /></p>]]></html>

0 commit comments

Comments
 (0)