Developer Tests Tickets - edmozley/freeitsm GitHub Wiki
Part of Developer Tests. Ticket numbering, saved views, and the task engine: priority, recurrence, the people on a task, and what goes into a calendar.
| Test | Needs |
|---|---|
ticket-numbering.php |
Database |
table-views.php |
Database |
team-counts-no-departments.php |
Database |
analyst-folders-by-company.php |
Database, two or more companies |
tasks-priority.php |
Nothing |
task-recurrence-dates.php |
Nothing |
task-recurrence-spawn.php |
Database |
task-collaborators/run.php |
Database |
calendar-sync-tasks.php |
Database |
test_email_thread.php |
The assertions that matter are not "it makes a number". They are:
- A number is never issued twice โ including one a renumbered ticket used to have, because a reply quoting it must not land on a stranger's ticket.
- An old number keeps resolving forever, because the emails quoting it live in customers' inboxes and nobody can recall them.
- The reference parser recognises any format, because an install can change its format and every number it ever issued has to go on working.
- The padding is a minimum, never a limit.
Creates only ZZNUM-prefixed rows and sweeps them before and after. It
exercises the renumber path deliberately, because that is where a number can be
freed and handed out again.
php tests/ticket-numbering.php
A reissued number is the serious one. It routes a customer's reply onto somebody else's ticket, which is a data leak dressed as a filing error. Treat any red here as blocking a release.
Saved table views โ specifically the visibility rules. There are three answers (mine, my team's, everyone's) and a fourth that must never happen: somebody else's private view.
Each is checked from the side that must be refused as well as the side that
must work, using a refuses() helper that asserts the call throws.
php tests/table-views.php
Creates ZZTV-named rows and removes them, including on failure.
A refuses() assertion going red means one analyst can load another's private
view โ including its filters, which can describe data they cannot otherwise see.
The ticket folder numbers for an analyst who is in a team. Someone in a team gets folders and counts for that team's departments, plus every ticket with no department. Until 3.7.0 a team linked to no department set every count to 0 instead โ the bug in A team with no departments showed 0 tickets.
- A team with no departments โ All Tickets equals the number of tickets with no department, the status folders are counted, there are no department folders, and the analyst's own folder is unchanged.
- A team with one department โ All Tickets is that department plus the no-department tickets, and the departments the team is deliberately not linked to stay out. This half guards the other direction: a fix for (1) that simply stopped filtering would pass (1) and fail here.
Two positive controls stop it passing vacuously: there must be tickets with no department, and tickets in a department the team is not linked to.
It drives the real endpoint, api/tickets/get_ticket_counts.php, in-process, as an active analyst who is in no team. The endpoint opens its own database connection, so a rolled-back transaction would be invisible to it โ instead the test writes one throwaway team (ZZ test team counts) and its links, deletes them by id in a finally, and then checks they are gone. It writes nothing else.
COUNTS_ENDPOINT=<path> points it at another copy of the endpoint. That is how the control was run: against the 3.6.1 code it fails exactly the two "no departments" counting checks and passes the rest.
php tests/team-counts-no-departments.php
A red "no departments" check means somebody has short-circuited an empty department list to 0 again โ look for the TRAP: line in get_ticket_counts.php. A red "one department" check is the more serious one: team members are seeing tickets in departments their team is not linked to.
Which analysts get a folder in the inbox's Analyst grouping on a multi-company install (#176). Until 3.7.0 it was every active analyst, so one client's analysts saw another client's by name. The rule now: an analyst gets a folder if they can access the company being viewed (with All companies, any company the viewer can access), or they are the viewer, or they hold tickets in scope.
- Viewing the company the analyst can access - they get a folder.
- Viewing a company they cannot access - no folder, while the viewer keeps their own.
- All companies - they get a folder, because they share a company with the viewer.
- Nobody who can access the company lost their folder - checked against every real analyst, so a fix that hid too much fails here.
Drives the real api/tickets/get_ticket_counts.php in-process. The analyst under test is a throwaway (zz-test-folders) who can access exactly one company, with an unusable password hash so nobody can sign in as it; it is deleted by id in a finally and checked gone. Skips on a single-company install, where the list is deliberately unchanged. Control: against the code before #176 it fails check 2 and passes the rest.
Not covered: the "holds tickets in scope" exception (it would mean assigning a real ticket to the throwaway analyst).
php tests/analyst-folders-by-company.php
Check 2 red means analysts' names are shown to other companies again. Check 4 red means analysts who should be there have vanished - usually a copy of the company-access rule that has drifted from getAccessibleTenantIds() (there is a TRAP: line about exactly that).
This is a scan, not a behaviour test, and deliberately so.
The bug it guards is not a wrong output โ it is a renderer deriving a colour from
a priority's display name. That produced class="priority-dot hoch" on a
German install, matched none of the four hardcoded English rules, and drew a
transparent circle: no error, no fallback, nothing on screen to suggest a
setting had not applied.
A behaviour test proves the renderer that exists today is right. It cannot stop the fifth renderer, written next year, from reaching for the name again because that is what its neighbours used to do. This is the same shape as the bug where every ticket intake path resolved its status by the word "Open", and the Watchtower counters before that. Three times, so the invariant gets a test rather than a comment:
- No stylesheet carries a per-priority-name rule.
- No renderer interpolates a priority into a class attribute.
- Every place that draws a priority goes through
TasksPriority. -
TasksPriorityvalidates the colour and escapes the name โ both are admin-editable free text, and the name is stored exactly as typed.
php tests/tasks-priority.php
48 assertions. No database, no network, writes nothing.
Someone has added a renderer that builds a class from a priority name, or a
stylesheet rule keyed to one. Route it through TasksPriority instead. The test
names the file.
The recurrence date engine. Pure date arithmetic, no database โ which is precisely why it is worth testing hard: every interesting bug in a recurrence feature is a calendar edge case, and none of them show up in a demo where everything falls on the 15th of a 31-day month.
The cases are the ones that break naive implementations:
- the 31st in a 30-day month, and in February
- "the last day of the month" across month lengths and a leap year
- "the 5th Tuesday" of a month that has only four
- "every 2 weeks on Mon and Thu" not collapsing into every week
- 29 February under a yearly rule
php tests/task-recurrence-dates.php
60 assertions, nothing required. Each line prints the date it produced, so a failure shows you the arithmetic rather than just a label.
The output gives got and wanted as real dates. Work out which rule the case
belongs to before changing anything โ these cases interact, and "fixing" the 31st
commonly breaks the last-day-of-month rule.
The other half of recurrence: that completing a task actually produces the next one, carries across what the rule says to carry and nothing it should not, and fires from both ways a task can be completed.
๐ That last one is the point. TasksService::moveTask โ dragging a card into
a closed column โ is documented "No workflow event" and dispatches nothing. A
hook placed only on saveTask would give you a task that repeats when you tick it
and silently does not when you drag it. Dragging is the commoner action.
php tests/task-recurrence-spawn.php
ZZREC-prefixed, cleaned up including on failure.
If only the drag path is red, the hook has been attached to one completion route again. Both routes must spawn.
The other people on a task โ the "Involved" list.
๐ด The first suite is the one that matters. A task you are on that fails to
appear in one list is indistinguishable, to the person looking, from your
never having been added to it โ and there are four separate places that can hide
it. A single assertion against api/tasks/list.php would pass while the REST API
still hid the task, so every surface is asserted separately.
php tests/task-collaborators/run.php
Writes one task and two throwaway analysts, all removed in the teardown.
The label names the surface. Fix it there, then ask whether the other three share a helper that should have been used.
Tasks in a calendar โ the decisions, not the network.
๐ Nothing here talks to Microsoft. What is worth testing is what the code decides: which of a task's two dates belongs in whose calendar, what an event looks like once built, and what happens at the edges. The provider is a network call and belongs behind a live run, not a unit test.
php tests/calendar-sync-tasks.php
ZZCAL-named rows, removed including on failure.
Read it as "we would now put the wrong thing in somebody's calendar". Since the network half is deliberately untested here, a green run does not mean sync works end to end โ that still needs a live run against a real account.
It also had no authentication check of any kind โ it called session_start()
and then printed that ticket's from_address and body_content to whoever asked.
Until tests/ was closed off it was fetchable over HTTP by anyone who knew the
path. See Test suite exposure.
It is recorded here so nobody goes looking for it, and so nobody mistakes its former existence for coverage of email threading. There is none โ email threading has no automated test.