diff --git a/uploader/testdata/uploader.go/case_basic/courses.json b/uploader/testdata/uploader.go/case_basic/courses.json new file mode 100644 index 0000000..720d623 --- /dev/null +++ b/uploader/testdata/uploader.go/case_basic/courses.json @@ -0,0 +1,25 @@ +[ + { + "_id": "67d07ee0c972c18731e23bee", + "subject_prefix": "BA", + "course_number": "1320", + "title": "Business in a Global World", + "description": "BA 1320 - Business in a Global World (3 semester credit hours) This course provides a primer on the impacts of globalization on business.", + "enrollment_reqs": "BA 1320 Repeat Restriction", + "school": "Naveen Jindal School of Management", + "credit_hours": "3", + "class_level": "Undergraduate", + "activity_type": "Lecture", + "grading": "Graded - Undergraduate", + "internal_course_number": "015444", + "prerequisites": null, + "corequisites": null, + "co_or_pre_requisites": null, + "sections": ["67d07ee0c972c18731e23bef"], + "lecture_contact_hours": "3", + "laboratory_contact_hours": "0", + "offering_frequency": "S", + "catalog_year": "24", + "attributes": null + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_basic/professors.json b/uploader/testdata/uploader.go/case_basic/professors.json new file mode 100644 index 0000000..79806d9 --- /dev/null +++ b/uploader/testdata/uploader.go/case_basic/professors.json @@ -0,0 +1,15 @@ +[ + { + "_id": "67d07ee0c972c18731e23bf0", + "first_name": "Peter", + "last_name": "Lewin", + "titles": ["Primary Instructor"], + "email": "plewin@utdallas.edu", + "phone_number": "", + "office": {"building": "", "room": "", "map_uri": ""}, + "profile_uri": "", + "image_uri": "", + "office_hours": null, + "sections": ["67d07ee0c972c18731e23bef"] + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_basic/sections.json b/uploader/testdata/uploader.go/case_basic/sections.json new file mode 100644 index 0000000..d1b9b43 --- /dev/null +++ b/uploader/testdata/uploader.go/case_basic/sections.json @@ -0,0 +1,32 @@ +[ + { + "_id": "67d07ee0c972c18731e23bef", + "section_number": "501", + "course_reference": "67d07ee0c972c18731e23bee", + "section_corequisites": null, + "academic_session": { + "name": "25S", + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-16T00:00:00-05:00" + }, + "professors": ["67d07ee0c972c18731e23bf0"], + "teaching_assistants": [], + "internal_class_number": "27195", + "instruction_mode": "Face-to-Face", + "meetings": [ + { + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-09T00:00:00-05:00", + "meeting_days": ["Tuesday", "Thursday"], + "start_time": "5:30pm", + "end_time": "6:45pm", + "modality": "", + "location": {"building": "JSOM", "room": "12.218", "map_uri": "https://locator.utdallas.edu/SOM_12.218"} + } + ], + "core_flags": ["080", "090"], + "syllabus_uri": "https://dox.utdallas.edu/syl153033", + "grade_distribution": [], + "attributes": null + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_edge/courses.json b/uploader/testdata/uploader.go/case_edge/courses.json new file mode 100644 index 0000000..17977d8 --- /dev/null +++ b/uploader/testdata/uploader.go/case_edge/courses.json @@ -0,0 +1,25 @@ +[ + { + "_id": "67d07ee0c972c18731e23bf4", + "subject_prefix": "AERO", + "course_number": "3320", + "title": "- Recitation", + "description": "- ()", + "enrollment_reqs": "", + "school": "Undergraduate Studies", + "credit_hours": "Non-Enroll", + "class_level": "Undergraduate", + "activity_type": "Laboratory - No Lab Fee", + "grading": "Graded - Undergraduate", + "internal_course_number": "000243", + "prerequisites": null, + "corequisites": null, + "co_or_pre_requisites": null, + "sections": ["67d07ee0c972c18731e23bf5"], + "lecture_contact_hours": "", + "laboratory_contact_hours": "", + "offering_frequency": "", + "catalog_year": "24", + "attributes": null + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_edge/professors.json b/uploader/testdata/uploader.go/case_edge/professors.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uploader/testdata/uploader.go/case_edge/professors.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_edge/sections.json b/uploader/testdata/uploader.go/case_edge/sections.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uploader/testdata/uploader.go/case_edge/sections.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_multiple/courses.json b/uploader/testdata/uploader.go/case_multiple/courses.json new file mode 100644 index 0000000..c91310d --- /dev/null +++ b/uploader/testdata/uploader.go/case_multiple/courses.json @@ -0,0 +1,25 @@ +[ + { + "_id": "67d07ee0c972c18731e23be9", + "subject_prefix": "ACCT", + "course_number": "2301", + "title": "Introductory Financial Accounting", + "description": "ACCT 2301 - Introductory Financial Accounting (3 semester credit hours) An introduction to financial reporting...", + "enrollment_reqs": "ACCT 2301 Repeat Restriction", + "school": "Naveen Jindal School of Management", + "credit_hours": "3", + "class_level": "Undergraduate", + "activity_type": "Lecture", + "grading": "Graded - Undergraduate", + "internal_course_number": "000061", + "prerequisites": null, + "corequisites": null, + "co_or_pre_requisites": null, + "sections": ["67d07ee0c972c18731e23bea", "67d07ee0c972c18731e23bed"], + "lecture_contact_hours": "3", + "laboratory_contact_hours": "0", + "offering_frequency": "S", + "catalog_year": "24", + "attributes": null + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_multiple/professors.json b/uploader/testdata/uploader.go/case_multiple/professors.json new file mode 100644 index 0000000..b6f627b --- /dev/null +++ b/uploader/testdata/uploader.go/case_multiple/professors.json @@ -0,0 +1,15 @@ +[ + { + "_id": "67d07ee0c972c18731e23beb", + "first_name": "Naim Bugra", + "last_name": "Ozel", + "titles": ["Primary Instructor (50%)"], + "email": "nbo150030@utdallas.edu", + "phone_number": "", + "office": {"building": "", "room": "", "map_uri": ""}, + "profile_uri": "", + "image_uri": "", + "office_hours": null, + "sections": ["67d07ee0c972c18731e23bea", "67d07ee0c972c18731e23bed"] + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_multiple/sections.json b/uploader/testdata/uploader.go/case_multiple/sections.json new file mode 100644 index 0000000..8bd812a --- /dev/null +++ b/uploader/testdata/uploader.go/case_multiple/sections.json @@ -0,0 +1,66 @@ +[ + { + "_id": "67d07ee0c972c18731e23bea", + "section_number": "003", + "course_reference": "67d07ee0c972c18731e23be9", + "section_corequisites": null, + "academic_session": { + "name": "25S", + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-16T00:00:00-05:00" + }, + "professors": ["67d07ee0c972c18731e23beb"], + "teaching_assistants": [ + {"first_name": "Galymzhan", "last_name": "Tazhibayev", "role": "Teaching Assistant", "email": "gxt230023@utdallas.edu"} + ], + "internal_class_number": "27706", + "instruction_mode": "Face-to-Face", + "meetings": [ + { + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-09T00:00:00-05:00", + "meeting_days": ["Tuesday", "Thursday"], + "start_time": "10:00am", + "end_time": "11:15am", + "modality": "", + "location": {"building": "JSOM", "room": "2.717", "map_uri": "https://locator.utdallas.edu/SOM_2.717"} + } + ], + "core_flags": [], + "syllabus_uri": "https://dox.utdallas.edu/syl152555", + "grade_distribution": [], + "attributes": null + }, + { + "_id": "67d07ee0c972c18731e23bed", + "section_number": "001", + "course_reference": "67d07ee0c972c18731e23be9", + "section_corequisites": null, + "academic_session": { + "name": "25S", + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-16T00:00:00-05:00" + }, + "professors": ["67d07ee0c972c18731e23beb"], + "teaching_assistants": [ + {"first_name": "Galymzhan", "last_name": "Tazhibayev", "role": "Teaching Assistant", "email": "gxt230023@utdallas.edu"} + ], + "internal_class_number": "26595", + "instruction_mode": "Face-to-Face", + "meetings": [ + { + "start_date": "2025-01-21T00:00:00-06:00", + "end_date": "2025-05-09T00:00:00-05:00", + "meeting_days": ["Tuesday", "Thursday"], + "start_time": "8:30am", + "end_time": "9:45am", + "modality": "", + "location": {"building": "JSOM", "room": "2.717", "map_uri": "https://locator.utdallas.edu/SOM_2.717"} + } + ], + "core_flags": [], + "syllabus_uri": "https://dox.utdallas.edu/syl152552", + "grade_distribution": [], + "attributes": null + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_relationship/courses.json b/uploader/testdata/uploader.go/case_relationship/courses.json new file mode 100644 index 0000000..5a3cf56 --- /dev/null +++ b/uploader/testdata/uploader.go/case_relationship/courses.json @@ -0,0 +1,13 @@ +[ + { + "_id": "67d07ee0c972c18731e23be9", + "subject_prefix": "ACCT", + "course_number": "2301", + "title": "Introductory Financial Accounting", + "school": "Naveen Jindal School of Management", + "credit_hours": "3", + "class_level": "Undergraduate", + "activity_type": "Lecture", + "sections": ["67d07ee0c972c18731e23bea", "67d07ee0c972c18731e23bed"] + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_relationship/professors.json b/uploader/testdata/uploader.go/case_relationship/professors.json new file mode 100644 index 0000000..896f8f4 --- /dev/null +++ b/uploader/testdata/uploader.go/case_relationship/professors.json @@ -0,0 +1,18 @@ +[ + { + "_id": "67d07ee0c972c18731e23beb", + "first_name": "Naim Bugra", + "last_name": "Ozel", + "titles": ["Primary Instructor (50%)"], + "email": "nbo150030@utdallas.edu", + "sections": ["67d07ee0c972c18731e23bea", "67d07ee0c972c18731e23bed"] + }, + { + "_id": "67d07ee0c972c18731e23bec", + "first_name": "Jieying", + "last_name": "Zhang", + "titles": ["Primary Instructor (50%)"], + "email": "jxz146230@utdallas.edu", + "sections": ["67d07ee0c972c18731e23bea", "67d07ee0c972c18731e23bed"] + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_relationship/sections.json b/uploader/testdata/uploader.go/case_relationship/sections.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uploader/testdata/uploader.go/case_relationship/sections.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_sorting/courses.json b/uploader/testdata/uploader.go/case_sorting/courses.json new file mode 100644 index 0000000..f36b1e0 --- /dev/null +++ b/uploader/testdata/uploader.go/case_sorting/courses.json @@ -0,0 +1,38 @@ +[ + { + "_id": "67d07ee0c972c18731e23be9", + "subject_prefix": "ACCT", + "course_number": "2301", + "title": "Introductory Financial Accounting", + "school": "Naveen Jindal School of Management", + "credit_hours": "3", + "class_level": "Undergraduate", + "activity_type": "Lecture", + "catalog_year": "24", + "sections": [] + }, + { + "_id": "67d07ee0c972c18731e23bee", + "subject_prefix": "BA", + "course_number": "1320", + "title": "Business in a Global World", + "school": "Naveen Jindal School of Management", + "credit_hours": "3", + "class_level": "Undergraduate", + "activity_type": "Lecture", + "catalog_year": "23", + "sections": [] + }, + { + "_id": "67d07ee0c972c18731e23bf1", + "subject_prefix": "BIOL", + "course_number": "6111", + "title": "Graduate Research Presentation", + "school": "School of Natural Sciences and Mathematics", + "credit_hours": "1", + "class_level": "Graduate", + "activity_type": "Lecture", + "catalog_year": "24", + "sections": [] + } +] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_sorting/professors.json b/uploader/testdata/uploader.go/case_sorting/professors.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uploader/testdata/uploader.go/case_sorting/professors.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uploader/testdata/uploader.go/case_sorting/sections.json b/uploader/testdata/uploader.go/case_sorting/sections.json new file mode 100644 index 0000000..0637a08 --- /dev/null +++ b/uploader/testdata/uploader.go/case_sorting/sections.json @@ -0,0 +1 @@ +[] \ No newline at end of file diff --git a/uploader/uploader.go b/uploader/uploader.go index 1bb4015..49f9f17 100644 --- a/uploader/uploader.go +++ b/uploader/uploader.go @@ -28,10 +28,15 @@ import ( var filesToUpload [3]string = [3]string{"courses.json", "professors.json", "sections.json"} +// Wrapped for testability - can be replaced with mock in unit tests +var connectDBFunc = func() *mongo.Client { + return connectDB() +} + // Upload sends parsed JSON files to MongoDB and refreshes static aggregations. func Upload(inDir string, replace bool, staticOnly bool) { //Connect to mongo - client := connectDB() + client := connectDBFunc() // Get 5 minute context ctx, cancel := context.WithTimeout(context.Background(), 5*time.Minute) diff --git a/uploader/uploader_test.go b/uploader/uploader_test.go new file mode 100644 index 0000000..c975f60 --- /dev/null +++ b/uploader/uploader_test.go @@ -0,0 +1,103 @@ +package uploader + +import ( + "path/filepath" + "testing" + + "go.mongodb.org/mongo-driver/mongo" +) + +func TestUpload(t *testing.T) { + // Save original function and restore after test + originalConnectDB := connectDBFunc + defer func() { connectDBFunc = originalConnectDB }() + + // Create a simple mock that returns nil (or a minimal mock client) + connectDBFunc = func() *mongo.Client { + return nil + } + + // Test cases + tests := []struct { + name string + inDir string + replace bool + staticOnly bool + }{ + { + name: "Case Basic: static only mode", + inDir: filepath.Join(".", "testdata", "case_basic"), + replace: false, + staticOnly: true, + }, + { + name: "Case Basic: full upload with replace", + inDir: filepath.Join(".", "testdata", "case_basic"), + replace: true, + staticOnly: false, + }, + { + name: "Case Edge: static only mode", + inDir: filepath.Join(".", "testdata", "case_edge"), + replace: false, + staticOnly: true, + }, + { + name: "Case Edge: full upload with replace", + inDir: filepath.Join(".", "testdata", "case_edge"), + replace: true, + staticOnly: false, + }, + { + name: "Case Multiple: static only mode", + inDir: filepath.Join(".", "testdata", "case_multiple"), + replace: false, + staticOnly: true, + }, + { + name: "Case Multiple: full upload with replace", + inDir: filepath.Join(".", "testdata", "case_multiple"), + replace: true, + staticOnly: false, + }, + { + name: "Case Relationship: static only mode", + inDir: filepath.Join(".", "testdata", "case_relationship"), + replace: false, + staticOnly: true, + }, + { + name: "Case Relationship: full upload with replace", + inDir: filepath.Join(".", "testdata", "case_relationship"), + replace: true, + staticOnly: false, + }, + { + name: "Case Sorting: static only mode", + inDir: filepath.Join(".", "testdata", "case_sorting"), + replace: false, + staticOnly: true, + }, + { + name: "Case Sorting: full upload with replace", + inDir: filepath.Join(".", "testdata", "case_sorting"), + replace: true, + staticOnly: false, + }, + } + + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + // This will panic when it tries to use the nil client, but that's fine for now + // The goal is to test that the function calls what it should call + + defer func() { + if r := recover(); r != nil { + t.Logf("Expected panic when database operations are attempted: %v", r) + } + }() + + Upload(tt.inDir, tt.replace, tt.staticOnly) + }) + } +}