this is driving me NUTS and any thoughts are MUCH appreciated after looking at this for far too long.

Use case: users in certain profiles need to be automatically added/removed from a particular CollaborationGroup. If they're moved INTO one of these profiles they need to be added, moved OUT need to be removed. I have on insert and on update triggers that run, pass unit tests, and give 100% code coverage in sandbox but fail/throw cc errors when trying to validate in production. Sandbox and production are fully synced.

Trigger:

trigger UserGroup on User (after insert, after update){

    if(Trigger.isAfter && Trigger.isInsert){
    //Stops these requirements from running in other unit tests since we have a lot of user/profile based customizations
        if(!Test.isRunningTest() || UserInfo.getFirstName() == 'ActiveUserTester'){
            ActiveUser.oninsert(Trigger.new);
        }
    }

    if(Trigger.isAfter && Trigger.isUpdate){
        if(!Test.isRunningTest() || UserInfo.getFirstName() == 'ActiveUserTester'){
            ActiveUser.onedit(Trigger.new, Trigger.oldMap);
        }
    }
}

ISSUE: In Production unit-tests the condition that ensures users are entered just seems to be skipping for no apparent reason.

Apex Class:

public static void oninsert(List<User> users){

    List<CollaborationGroupMember> newmembers = new List<CollaborationGroupMember>();
  //Calls the updated Profile list of appropriate profiles from UserHelper helper class
    List<Id> profiles = UserHelper.callprofiles();
    System.debug('oninsert profiles list contains ' + profiles.size() + ' valid profiles;');

    Id thegroup = [SELECT Id FROM CollaborationGroup WHERE Name LIKE '%Active Users%' AND IsBroadcast = TRUE LIMIT 1].Id;
    System.debug('GroupId is: ' + thegroup);

    //Any Active Users included in the correct Profiles receive membership
    for(User u : users){
      //The last part of this condition is just to stop our connector users from getting added
        if(u.IsActive && profiles.contains(u.ProfileId) && u.FirstName != 'Connector'){
            CollaborationGroupMember g = new CollaborationGroupMember();
            g.CollaborationGroupId=thegroup;
            g.CollaborationRole = 'Standard';
            g.MemberId=u.id;
            g.NotificationFrequency = 'N';
            newmembers.add(g);
            System.debug('+1 new Group member');
        }
        System.debug('IsActive = ' + u.IsActive + '; ProfileId = ' + u.ProfileId + '; u.FirstName = ' + u.FirstName);
    }

    System.debug(newmembers.size() + ' members for addition');
    if(newmembers.size()>0){
        System.debug('Inserting ' + newmembers.size() + ' new members into TalentForce Active Members Group');
        insert newmembers;
    }
}

The UserHelper class just returns a public List that only contains the correct profile Ids. I've verified via debugging that the profiles being returned are correct.

I'll give a condensed version of the @isTest class:

//Retrieve Ids from Profiles known to be on and not on the managed list
    Id valid = [SELECT Id FROM Profile WHERE Name='Developer' LIMIT 1].Id;
    Id invalid = [SELECT Id FROM Profile WHERE Name='Partner' LIMIT 1].Id;
    Id adminid = [SELECT Id FROM Profile WHERE Name = 'Admin (Global System Administrator)'].Id;

    CollaborationGroup newgroup = new CollaborationGroup(Name = 'Testing Active Users', IsBroadcast = TRUE, CollaborationType = 'Private', CanHaveGuests = FALSE, IsArchived = FALSE, IsAutoArchiveDisabled = TRUE);
    insert newgroup;

  //Create two users, one that should receive group membership and one that should not based on their Profiles
    List<User> users = new List<User>();

    User u1 = new User(ProfileId = valid,
        LastName = 'User',
        Email = 'testuser001@testing.com',
        isActive = TRUE,
        ...);
    users.add(u1);

    User u2 = new User(ProfileId = invalid,
        LastName = 'User',
        Email = 'testuser002@testing.com',
        isActive = TRUE,
        ...);
    users.add(u2);

    User adminuser = new User(ProfileId = adminid,
        FirstName = 'ActiveUserTester',
        LastName = 'TestUser',
        Email = 'admintestuser@testing.com',
        isActive = TRUE,
        ...);

    insert adminuser;

    test.startTest();

    System.runAs(adminuser){
        insert users;
    }

    test.stopTest();

    List<CollaborationGroupMember> groupcheck = new List<CollaborationGroupmember>([SELECT Id FROM CollaborationGroupMember WHERE MemberId IN :users]);

  //Only one user should have membership
    System.assertEquals(1, groupcheck.size(), 'Incorrect number of group memberships created');

The error occurs on the assertEquals, where it consistently returns 0 group members in production, but not in sandbox. Did a deep-dive through my debug logs and am posting the relevant portion here: it appears that the production system just SKIPS OVER the creation of CollaborationGroupMembers even for users that meet the criteria. WHAT AM I MISSING HERE?!?

17:40:29.132 (1600535096)|SYSTEM_METHOD_ENTRY|[14]|System.debug(ANY)
17:40:29.132 (1600538319)|USER_DEBUG|[14]|DEBUG|oninsert profiles list contains 9 valid profiles;
17:40:29.132 (1600543341)|SYSTEM_METHOD_EXIT|[14]|System.debug(ANY)
17:40:29.132 (1600546419)|STATEMENT_EXECUTE|[16]
17:40:29.132 (1600548867)|HEAP_ALLOCATE|[16]|Bytes:129
17:40:29.132 (1600567700)|HEAP_ALLOCATE|[16]|Bytes:4
17:40:29.132 (1600891174)|SOQL_EXECUTE_BEGIN|[16]|Aggregations:0|SELECT Id FROM CollaborationGroup WHERE (Name LIKE '%Acrtive Users%' AND IsBroadcast = TRUE) LIMIT 1
17:40:29.132 (1604743622)|SOQL_EXECUTE_END|[16]|Rows:1
17:40:29.132 (1604782530)|HEAP_ALLOCATE|[16]|Bytes:8
17:40:29.132 (1604797444)|HEAP_ALLOCATE|[16]|Bytes:29
17:40:29.132 (1604830795)|HEAP_ALLOCATE|[16]|Bytes:8
17:40:29.132 (1604842690)|HEAP_ALLOCATE|[16]|Bytes:44
17:40:29.132 (1604864271)|HEAP_ALLOCATE|[16]|Bytes:8
17:40:29.132 (1604877166)|STATEMENT_EXECUTE|[17]
17:40:29.132 (1604880225)|HEAP_ALLOCATE|[17]|Bytes:12
17:40:29.132 (1604905160)|SYSTEM_METHOD_ENTRY|[17]|String.valueOf(Object)
17:40:29.132 (1604912925)|HEAP_ALLOCATE|[17]|Bytes:18
17:40:29.132 (1604923286)|SYSTEM_METHOD_EXIT|[17]|String.valueOf(Object)
17:40:29.132 (1604931414)|HEAP_ALLOCATE|[17]|Bytes:30
17:40:29.132 (1604941000)|SYSTEM_METHOD_ENTRY|[17]|System.debug(ANY)
17:40:29.132 (1604947221)|USER_DEBUG|[17]|DEBUG|GroupId is: 0F9f4000000RiCcCAK
17:40:29.132 (1604954348)|SYSTEM_METHOD_EXIT|[17]|System.debug(ANY)
17:40:29.132 (1604966195)|SYSTEM_METHOD_ENTRY|[20]|List<User>.iterator()
17:40:29.132 (1604976365)|SYSTEM_METHOD_EXIT|[20]|List<User>.iterator()
17:40:29.132 (1604984140)|SYSTEM_METHOD_ENTRY [20]|system.ListIterator.hasNext()
17:40:29.132 (1604994063)|HEAP_ALLOCATE|[20]|Bytes:5
17:40:29.132 (1605000274)|SYSTEM_METHOD_EXIT|[20]|system.ListIterator.hasNext()
17:40:29.132 (1605015735)|STATEMENT_EXECUTE|[20]
17:40:29.132 (1605086374)|SYSTEM_METHOD_ENTRY|[21]|List<Id>.contains(Object)
17:40:29.132 (1605096861)|SYSTEM_METHOD_EXIT|[21]|List<Id>.contains(Object)
17:40:29.132 (1605102778)|STATEMENT_EXECUTE|[21]
17:40:29.132 (1605104475)|STATEMENT_EXECUTE|[30]
17:40:29.132 (1605107731)|HEAP_ALLOCATE|[30]|Bytes:11
17:40:29.132 (1605124517)|SYSTEM_METHOD_ENTRY|[30]|String.valueOf(Object)
17:40:29.132 (1605129806)|HEAP_ALLOCATE|[30]|Bytes:4
17:40:29.132 (1605138258)|SYSTEM_METHOD_EXIT|[30]|String.valueOf(Object)
17:40:29.132 (1605142589)|HEAP_ALLOCATE|[30]|Bytes:14
17:40:29.132 (1605153991)|SYSTEM_METHOD_ENTRY|[30]|String.valueOf(Object)
17:40:29.132 (1605158261)|HEAP_ALLOCATE|[30]|Bytes:18
17:40:29.132 (1605166486)|SYSTEM_METHOD_EXIT|[30]|String.valueOf(Object)
17:40:29.132 (1605171205)|HEAP_ALLOCATE|[30]|Bytes:16
17:40:29.132 (1605201409)|HEAP_ALLOCATE|[30]|Bytes:67
17:40:29.132 (1605210068)|SYSTEM_METHOD_ENTRY|[30]|System.debug(ANY)
17:40:29.132 (1605214654)|USER_DEBUG|[30]|DEBUG|IsActive = true; ProfileId = 00ef4000000hUcnAAE; u.FirstName = null
17:40:29.132 (1605220164)|SYSTEM_METHOD_EXIT|[30]|System.debug(ANY)
17:40:29.132 (1605226994)|SYSTEM_METHOD_ENTRY|[20]|system.ListIterator.hasNext()
17:40:29.132 (1605233201)|HEAP_ALLOCATE|[20]|Bytes:5
17:40:29.132 (1605238309)|SYSTEM_METHOD_EXIT|[20]|system.ListIterator.hasNext()
17:40:29.132 (1605247481)|STATEMENT_EXECUTE|[20]
17:40:29.132 (1605271846)|SYSTEM_METHOD_ENTRY|[21]|List<Id>.contains(Object)
17:40:29.132 (1605280187)|SYSTEM_METHOD_EXIT|[21]|List<Id>.contains(Object)
17:40:29.132 (1605284607)|STATEMENT_EXECUTE|[21]
17:40:29.132 (1605286539)|STATEMENT_EXECUTE|[30]
17:40:29.132 (1605297216)|SYSTEM_METHOD_ENTRY|[30]|String.valueOf(Object)
17:40:29.132 (1605301509)|HEAP_ALLOCATE|[30]|Bytes:4
17:40:29.132 (1605309246)|SYSTEM_METHOD_EXIT|[30]|String.valueOf(Object)
17:40:29.132 (1605319582)|SYSTEM_METHOD_ENTRY|[30]|String.valueOf(Object)
17:40:29.132 (1605323831)|HEAP_ALLOCATE|[30]|Bytes:18
17:40:29.132 (1605330916)|SYSTEM_METHOD_EXIT|[30]|String.valueOf(Object)
17:40:29.132 (1605346044)|HEAP_ALLOCATE|[30]|Bytes:67
17:40:29.132 (1605352953)|SYSTEM_METHOD_ENTRY|[30]|System.debug(ANY)
17:40:29.132 (1605357342)|USER_DEBUG|[30]|DEBUG|IsActive = true; ProfileId = 00ef4000000hUYgAAM; u.FirstName = null
17:40:29.132 (1605362101)|SYSTEM_METHOD_EXIT|[30]|System.debug(ANY)
17:40:29.132 (1605368053)|SYSTEM_METHOD_ENTRY|[20]|system.ListIterator.hasNext()
17:40:29.132 (1605373903)|HEAP_ALLOCATE|[20]|Bytes:5
17:40:29.132 (1605378770)|SYSTEM_METHOD_EXIT|[20]|system.ListIterator.hasNext()
17:40:29.132 (1605383633)|STATEMENT_EXECUTE|[33]
17:40:29.132 (1605391114)|SYSTEM_METHOD_ENTRY|[33]|List<CollaborationGroupMember>.size()
17:40:29.132 (1605396002)|SYSTEM_METHOD_EXIT|[33]|List<CollaborationGroupMember>.size()
17:40:29.132 (1605407383)|SYSTEM_METHOD_ENTRY|[33]|String.valueOf(Object)
17:40:29.132 (1605412634)|HEAP_ALLOCATE|[33]|Bytes:1
17:40:29.132 (1605420853)|SYSTEM_METHOD_EXIT|[33]|String.valueOf(Object)
17:40:29.132 (1605424755)|HEAP_ALLOCATE|[33]|Bytes:21
17:40:29.132 (1605430524)|HEAP_ALLOCATE|[33]|Bytes:22
17:40:29.132 (1605436677)|SYSTEM_METHOD_ENTRY|[33]|System.debug(ANY)
17:40:29.132 (1605440709)|USER_DEBUG|[33]|DEBUG|0 members for addition
17:40:29.132 (1605445625)|SYSTEM_METHOD_EXIT|[33]|System.debug(ANY)
17:40:29.132 (1605451021)|SYSTEM_METHOD_ENTRY|[34]|List<CollaborationGroupMember>.size()
17:40:29.132 (1605455536)|SYSTEM_METHOD_EXIT|[34]|List<CollaborationGroupMember>.size()
17:40:29.132 (1605460896)|STATEMENT_EXECUTE|[34]
17:40:29.132 (1605469336)|METHOD_EXIT|[10]|01pf400000GlaEu|ActiveUser.oninsert(List<User>)
17:40:29.132 (1605484274)|STATEMENT_EXECUTE|[14]
17:40:29.605 (1605492909)|CUMULATIVE_LIMIT_USAGE
17:40:29.605 (1605492909)|LIMIT_USAGE_FOR_NS|(default)|

Number of SOQL queries: 3 out of 100
Number of query rows: 3 out of 50000
Number of SOSL queries: 0 out of 20
Number of DML statements: 2 out of 150
Number of DML rows: 2 out of 10000
Maximum CPU time: 0 out of 10000
Maximum heap size: 0 out of 6000000
Number of callouts: 0 out of 100
Number of Email Invocations: 0 out of 10
Number of future calls: 0 out of 50
Number of queueable jobs added to the queue: 0 out of 50
Number of Mobile Apex push calls: 0 out of 10

17:40:29.605 (1605492909)|TESTING_LIMITS
17:40:29.605 (1605492909)|LIMIT_USAGE_FOR_NS|(default)|

Number of SOQL queries: 2 out of 100
Number of query rows: 33 out of 50000
Number of SOSL queries: 0 out of 20
Number of DML statements: 2 out of 150
Number of DML rows: 3 out of 10000
Maximum CPU time: 0 out of 10000
Maximum heap size: 0 out of 6000000
Number of callouts: 0 out of 100
Number of Email Invocations: 0 out of 10
Number of future calls: 0 out of 50
Number of queueable jobs added to the queue: 0 out of 50
Number of Mobile Apex push calls: 0 out of 10

17:40:29.605 (1605492909)|CUMULATIVE_LIMIT_USAGE_END

17:40:29.132 (1606295685)|CODE_UNIT_FINISHED|UserGroup on User trigger event AfterInsert|__sfdc_trigger/UserGroup
17:40:29.132 (1606963869)|DML_END|[70]
17:40:29.132 (1607004211)|HEAP_ALLOCATE|[EXTERNAL]|Bytes:12
17:40:29.132 (1627257774)|STATEMENT_EXECUTE|[73]
17:40:29.132 (1627286595)|METHOD_ENTRY|[73]||System.Test.stopTest()
17:40:29.132 (1628093454)|METHOD_EXIT|[73]||System.Test.stopTest()
17:40:29.132 (1628105520)|STATEMENT_EXECUTE|[75]
17:40:29.132 (1628123541)|HEAP_ALLOCATE|[75]|Bytes:4
17:40:29.132 (1628143711)|SYSTEM_CONSTRUCTOR_ENTRY|[75]|<init>()
17:40:29.132 (1628167347)|SYSTEM_CONSTRUCTOR_EXIT|[75]|<init>()
17:40:29.132 (1628177322)|HEAP_ALLOCATE|[75]|Bytes:66
17:40:29.132 (1628191687)|HEAP_ALLOCATE|[75]|Bytes:4
17:40:29.132 (1628201138)|HEAP_ALLOCATE|[75]|Bytes:7
17:40:29.132 (1628467118)|SOQL_EXECUTE_BEGIN|[75]|Aggregations:0|SELECT Id FROM CollaborationGroupMember WHERE MemberId IN :tmpVar1
17:40:29.132 (1631834909)|SOQL_EXECUTE_END|[75]|Rows:0
17:40:29.132 (1631859081)|HEAP_ALLOCATE|[75]|Bytes:4
17:40:29.132 (1631873632)|HEAP_ALLOCATE|[75]|Bytes:0
17:40:29.132 (1631901705)|HEAP_ALLOCATE|[75]|Bytes:4
17:40:29.132 (1631944926)|SYSTEM_METHOD_ENTRY|[75]|List<CollaborationGroupMember>.addAll(Object)
17:40:29.132 (1631958598)|HEAP_ALLOCATE|[75]|Bytes:0
17:40:29.132 (1631973551)|SYSTEM_METHOD_EXIT|[75]|List<CollaborationGroupMember>.addAll(Object)
17:40:29.132 (1631982271)|STATEMENT_EXECUTE|[78]
17:40:29.132 (1631991206)|SYSTEM_METHOD_ENTRY|[78]|List<CollaborationGroupMember>.size()
17:40:29.132 (1632014557)|SYSTEM_METHOD_EXIT|[78]|List<CollaborationGroupMember>.size()
17:40:29.132 (1632025830)|HEAP_ALLOCATE|[78]|Bytes:45
17:40:29.132 (1632052313)|SYSTEM_METHOD_ENTRY|[78]|System.assertEquals(ANY, ANY, ANY)
17:40:29.132 (1632088154)|EXCEPTION_THROWN|[78]|System.AssertException: Assertion Failed: Incorrect number of group memberships created: Expected: 1, Actual: 0
17:40:29.132 (1632153009)|HEAP_ALLOCATE|[78]|Bytes:91
17:40:29.132 (1632160583)|SYSTEM_METHOD_EXIT|[78]|System.assertEquals(ANY, ANY, ANY)
17:40:29.132 (1632207258)|FATAL_ERROR|System.AssertException: Assertion Failed: Incorrect number of group memberships created: Expected: 1, Actual: 0
up vote 6 down vote accepted

This is a Known Issue that should be fixed in Spring '19. Until then, consider using a List<String> instead (as mentioned in the workaround), or use a Set<Id> instead, which should be more reliable.

The reason why it happens is usually because of different log levels depending on how you run the test/deploy. For example, a change set would probably fail, but an Ant deployment would probably succeed.

Either way, you really don't want this test to pass this code, because the bug could affect production users. Use another type of data type instead of List<Id>.

  • I would consider using Set<Id>, not only to avoid the bug but also to ensure you're dealing with unique Ids. – toadgeek Sep 21 at 6:56

Your Answer

By clicking "Post Your Answer", you acknowledge that you have read our updated terms of service, privacy policy and cookie policy, and that your continued use of the website is subject to these policies.

Not the answer you're looking for? Browse other questions tagged or ask your own question.