#!/usr/bin/env python3 # Copyright © 2025 Collabora Ltd. # Authors: # Sergi Blanch Torne # # SPDX-License-Identifier: MIT from dataclasses import dataclass from datetime import timedelta from unittest import TestCase from typing import Iterable from marge_queue import MargeMergeRequest, MargeQueue, get_merge_queue DATA = { 37564: { # sample of a Merge Request rejected by marge and later reassigned to marge "updated_at": "2025-09-25T10:59:27.144Z", "title": "etnaviv: Fix util_blitter_save_so_targets(..) call", "notes": [ # Those notes must be listed in reverse order # because the list is requested sort="desc" { "body": "assigned to @marge-bot and unassigned @austriancoder", "created_at": "2025-09-25T11:44:01.672Z", }, { "body": "added 1 commit", "created_at": "2025-09-25T10:43:43.490Z", }, { "body": "This branch couldn't be merged:", "created_at": "2025-09-25T10:42:27.817Z", }, { "body": "assigned to @austriancoder and unassigned @marge-bot", "created_at": "2025-09-25T10:42:15.404Z", }, { "body": "added 3 commits", "created_at": "2025-09-25T10:38:57.332Z", }, { "body": "assigned to @marge-bot", "created_at": "2025-09-25T10:38:03.993Z", }, ], }, 37560: { # sample of a Merge Request assigned to marge between the two # assignments of the previous sample. This is meant to show that # this goes first in the queue, and it doesn't confuses the sequence. "updated_at": "2025-09-25T11:38:08.420Z", "title": "tu: limit query pool types logged into RMV", "notes": [ { "body": "assigned to @marge-bot", "created_at": "2025-09-25T10:47:40.040Z", }, { "body": "added 1 commit", "created_at": "2025-09-25T10:46:42.113Z", }, { "body": "mentioned in issue #13970", "created_at": "2025-09-25T10:45:35.566Z", }, { "body": "Rb", "created_at": "2025-09-25T08:25:51.527Z", }, ], }, } @dataclass class ProjectMergeRequestNote: body: str created_at: str @dataclass class ProjectMergeRequestNoteManager: """ Mock the gitlab.v4.objects.ProjectMergeRequestNoteManager """ iid: int def list(self, *args, **kwargs) -> Iterable: for note in DATA[self.iid]["notes"]: yield ProjectMergeRequestNote(**note) @dataclass class ProjectMergeRequest: """ Mock the gitlab.v4.objects.ProjectMergeRequest """ iid: int @property def updated_at(self) -> str: return DATA[self.iid]["updated_at"] @property def web_url(self) -> str: return f"https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/{self.iid}" @property def title(self) -> str: return DATA[self.iid]["title"] @property def notes(self) -> ProjectMergeRequestNoteManager: return ProjectMergeRequestNoteManager(self.iid) @dataclass class ProjectMergeRequestManager: """ Mock the gitlab.v4.objects.ProjectMergeRequestManager """ def list(self, *args, **kwargs) -> Iterable: for mr in DATA.keys(): yield ProjectMergeRequest(mr) @dataclass class Project: """ Mock the gitlab.v4.objects.Project """ @property def mergerequests(self) -> ProjectMergeRequestManager: return ProjectMergeRequestManager() class MargeMergeTestCase(TestCase): def test_queue(self) -> None: queue = MargeQueue() for mr_id in DATA.keys(): gl_mr_mock_obj = ProjectMergeRequest(mr_id) marge_mr = MargeMergeRequest(gl_mr_mock_obj) # for each element in the data sample, test the MargeMergeRequest construction self.assertEqual(marge_mr.title, gl_mr_mock_obj.title) self.assertEqual(marge_mr.web_url, gl_mr_mock_obj.web_url) self.assertIsInstance(marge_mr.time_enqueued, timedelta) queue.append(marge_mr) self.assertEqual(queue.n_merge_requests_enqueued, 2) def test_get_merge_queue(self) -> None: project = Project() queue = get_merge_queue(project) self.assertEqual(queue.n_merge_requests_enqueued, 2) self.assertEqual(len(queue.sorted_queue), 2) # They are in reverse order because of the reassignment to marge self.assertEqual(queue.sorted_queue[0].id, list(DATA.keys())[1]) self.assertEqual(queue.sorted_queue[1].id, list(DATA.keys())[0]) self.assertEqual(len(queue.undetermined), 0) for marge_mr in queue.sorted_queue: mr_id = marge_mr.id self.assertEqual(marge_mr.title, DATA[mr_id]["title"]) self.assertEqual( marge_mr.web_url, f"https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/{mr_id}" ) self.assertIsInstance(marge_mr.time_enqueued, timedelta)