A complete shot in the dark, but I would guess someone has created a new Profile in production called 'Read Only' that is being returned before the default system profile.
E.g. You can create a new Profile with the same name as the system 'Read Only' Profile.
To tell them apart you would need to use the Organization.CreatedDate to find the System created on. E.g.
Datetime orgCreatedDate = [Select id, CreatedDate from Organization limit 1].CreatedDate;
List<Profile> readOnlyProfiles = [select id, Name from Profile where Name = 'Read Only' and CreatedDate = :orgCreatedDate];
// Maybe to a sanity check here to make sure there was only one matching Profile.
From the log, it appears that this line in the test case is causing the failure.
System.Assert(ApexPages.hasMessages(ApexPages.Severity.ERROR) == true);
For this assertion to pass the code would need to call ApexPages.addMessages(ex)
(where ex is an exception).
I see the check against UserRecordAccess.HasEditAccess
for the Contact comes back as false. Same with the HasEditAccess values for all the Course__c records.
So it does seem really odd that you can then turn round and update those records from an apex update. Assuming you have with sharing
on, the next thing that comes to mind is the "Modify All Data" Administrative Permissions. However, I don't think you can change that on the built in Read Only role.
It doesn't appear to be the case, but it is worth confirming the the active user isn't the owner of the record you are updating.
"The record owner is automatically granted Full Access, allowing them to view, edit, transfer, share, and delete the record." Understanding Sharing
Best Answer
While Salesforce does run something called the hammer to ensure a release doesn't break functionalities, that doesn't guarantee that your test will never break in production. This feature doesn't actually care whether the test failed or not, just that if it passed it doesn't fail after the new release (since lots of customers have failing tests in their org).
There are tons of reasons a test can fail in production, you'll need to review the specific test failures to find the cause. That being said, common ones are the addition of a new validation rule that a test method isn't complying with, or a test that references data in the production org that has been modified or deleted.