3

I have a class that finds the Contact record associated with the logged-in user, then pulls a list of related records (Contact => Account => Sublocal => SublocalStewards). The code I have pasted here was working fine a couple months ago (was successfully returning the list of Stewards and delivering them to the VF page to render), and then stopped working at some point.

While I was trying to figure out why it stopped working, I added a step in the test class that essentially duplicates the SOQL in the main class so I could system.debug the resulting list. This test list (stewListTest in the test class) logs the right data, but the class itself always returns zero records.

Apex Class

public with sharing class UserStewardListController {
    
    private final User user;
    private final Contact userContact;
    public final Account userAccount;
    private final CVRSOS__Local__c sublocal;
    private final Id sublocalId;
    private final Id accountId;

    public UserStewardListController(ApexPages.StandardController stdController) {
        System.debug(LoggingLevel.INFO, '>>> UserStewardListController');
        this.user = [SELECT Id, ContactId FROM User WHERE Id = :UserInfo.getUSerId()];
         System.debug(LoggingLevel.INFO, '>>> USER' + user);
        this.userContact = [SELECT Id, Name, AccountId from Contact WHERE Id = :user.ContactId];
       System.debug(LoggingLevel.INFO, '>>> USER CONTACT' + userContact);

            this.userAccount = [SELECT Id, Name, Sublocal__c, Organizer_Name__c, Organizer_Email__c, Organizer_Cell_Phone__c from Account WHERE Id = :userContact.AccountId];
            System.debug(LoggingLevel.INFO, '>>> USER ACCOUNT' + userAccount);
            this.accountId = userAccount.Id;

                this.sublocal = [SELECT Id from CVRSOS__Local__c where Id = :userAccount.Sublocal__c];
                this.sublocalId = sublocal.Id;
                System.debug(LoggingLevel.INFO, '>>> SUBLOCAL' + sublocal);
                System.debug(LoggingLevel.INFO, '>>> SUBLOCALID' + sublocalId);

    }

    public List<CVRSOS__LocalSteward__c> getStewards() {
        System.debug(LoggingLevel.INFO, '>>> getStewards');
        CVRSOS__LocalSteward__c[] stewardList = [
            SELECT  Id,
                CVRSOS__StewardName__c,
                Steward_Mobile_Phone__c,
                Steward_Preferred_Email__c,
                Steward_Worksite_Employer__c,
                Steward_Worksite__c,
                Active_Auto__c,
                CVRSOS__ContactId__r.Account.Id,
                CVRSOS__ContactId__r.Title 
            FROM    CVRSOS__LocalSteward__c
            WHERE   (Active_Auto__c = TRUE AND CVRSOS__ContactId__r.Account.Id = :this.accountId)
            ORDER BY CVRSOS__StewardName__c ASC
        ];
        if(stewardList.size() > 0) {
            System.debug(LoggingLevel.INFO, '>>> stewardList' + stewardList);
            return stewardList;
        } else {
            System.debug(LoggingLevel.INFO, '>>> stewardList.size === 0');
            return null;
        }
         
    }
}

Right now every time the getStewards() method is called in this class, I get the stewardList.size === 0 log, although when I first deployed this a few months ago it was working fine.

Test

@isTest
private class UserStewardListControllerTest {

    static testMethod void testMethod1(){
            //Insert SubLocal Record 
            CVRSOS__Local__c s = new CVRSOS__Local__c(Division__c='Care Providers');
            list<CVRSOS__Local__c> sublocalList = new list<CVRSOS__Local__c>();
            sublocalList.add(s);
            insert sublocalList;

            Id sublocalId = sublocalList[0].Id;
        
           //Insert Contacts
           Account a = new Account(Name = 'Test Account', Sublocal__c = sublocalId);
           Insert a;

           Contact c1 = New Contact(AccountId = a.Id, FirstName='FirstName1', LastName='LastName1', Is_Steward__c = 'C');
           Contact c2 = New Contact(AccountId = a.Id, FirstName='FirstName2', LastName='LastName2', Is_Steward__c = 'S');
           Contact c3 = New Contact(AccountId = a.Id, FirstName='UserFirst', LastName='UserLast');
           Insert c1;
           Insert c2;
           Insert c3;
        
           //Insert User
         
            Profile p = [select Id,name from Profile where Name = 'my503Live Community User' limit 1];
            System.debug(LoggingLevel.INFO, '>>> p');
            System.debug(LoggingLevel.INFO, '>>>' + p);
            
            User u = new User(
                profileId = p.id,
                username = 'testuser@testuser.com',
                email = 'testuser@testuser.com',
                emailencodingkey = 'UTF-8',
                localesidkey = 'en_US',
                languagelocalekey = 'en_US',
                timezonesidkey = 'America/Los_Angeles',
                alias='testuser',
                lastname='UserLast',
                contactId = c3.id
            );
            insert u;
            System.debug(LoggingLevel.INFO, '>>> u');
            System.debug(LoggingLevel.INFO, '>>>' + u);
            System.debug(LoggingLevel.INFO, '>>> c3.AccountId');
            System.debug(LoggingLevel.INFO, '>>>' + c3.AccountId); 
            System.debug(LoggingLevel.INFO, '>>> a.Id');
            System.debug(LoggingLevel.INFO, '>>>' + a.Id); 

            // Insert Stewards

            CVRSOS__LocalSteward__c st1 = new CVRSOS__LocalSteward__c(  CVRSOS__ContactId__c = c1.Id, CVRSOS__LocalId__c = sublocalId);
            CVRSOS__LocalSteward__c st2 = new CVRSOS__LocalSteward__c(  CVRSOS__ContactId__c = c2.Id, CVRSOS__LocalId__c = sublocalId);
            list<CVRSOS__LocalSteward__c> stewardList = new list<CVRSOS__LocalSteward__c>();
            stewardList.add(st1);
            stewardList.add(st2);
            insert stewardList;

            list<CVRSOS__LocalSteward__c> stewListTest = [
                SELECT  Id,
                    CVRSOS__StewardName__c,
                    Steward_Mobile_Phone__c,
                    Steward_Preferred_Email__c,
                    Steward_Worksite_Employer__c,
                    Steward_Worksite__c,
                    Active_Auto__c,
                    C_S__c,
                    CVRSOS__ContactId__r.Account.Id,
                    CVRSOS__ContactId__r.Title 
                FROM    CVRSOS__LocalSteward__c
                WHERE   (Active_Auto__c = TRUE AND CVRSOS__ContactId__r.Account.Id = :a.Id)
                // WHERE   Active_Auto__c = TRUE
                // WHERE   (CVRSOS__ContactId__r.Account.Id = :a.Id)
            ];
            System.debug(LoggingLevel.INFO, '>>> stewListTest');
            System.debug(LoggingLevel.INFO, '>>>' + stewListTest);

            Test.startTest();

            System.runAs(u) { 
                PageReference pageRef = Page.UserContactSublocalStewardList; 
                pageRef.getParameters().put('id', String.valueOf(sublocalId));
                Test.setCurrentPage(pageRef);

                ApexPages.StandardController sc = new ApexPages.StandardController(u);
                UserStewardListController ext = new UserStewardListController(sc);

                //Test that Stewards are Inserted
                list<CVRSOS__LocalSteward__c> stewList = ext.getStewards();
                list<CVRSOS__LocalSteward__c> chiefStewList = ext.getChiefStewards();
                System.assertEquals(stewList.size(),2);
                System.assertEquals(chiefStewList.size(),1);

            }
            Test.StopTest();


            try {

                Delete stewardList;
                Delete stewListTest;
                Delete c1;
                Delete c2;
                Delete c3;
                Delete a;

            } catch (DmlException e) {

                System.debug(LoggingLevel.INFO, '>>> deleteExceptions' + e);

            }
            
        }     

}

The log for stewListTest shows exactly the data I expect it to -- the test records inserted for the test. But when it tries to atually run getStewards() from the class it returns nothing. The only difference I can see between the test list and the main class is the way the account ID is being defined. In the test class, the query uses CVRSOS__ContactId__r.Account.Id = :a.Id -- where a is the new account created for the test. In the main class, it's CVRSOS__ContactId__r.Account.Id = :this.accountId, where acccountId is defined in the constructor as the account ID of the contact associated with the logged-in user. When I log this.accountId to the console it always has the correct value, but it still returns zero records from the query, even though the records exist.

I am not sure how to troubleshoot this. Any ideas?

Edited to add

As suggested by a user in the comments, I changed the class to without sharing instead of with sharing; this allowed the test class to successfully call getStewards() and return records, but the VF page still returns nothing for logged in users with the community profile. So this seems to be a sharing issue but I can't figure out what it is.

I have confirmed that the community user profile has read access to every object mentioned in this class (Sublocal, LocalSteward, Contact, Account) and every field returned in the SOQL query. Confirmed the profile has access to the Apex class and the VF page. The sharing setting for LocalSteward is 'Controlled by parent' and the two master/detail relationships on this object are Sublocal and Contact, both of which are set to 'Public Read/Write' for Internal and External users. Is there anywhere else that I might be missing a permission or sharing setting?

I'm noticing now that the same issue is happening with another similar Apex controller (returns a list of custom event records that are related to the logged-in user's contact record) -- exact same issue where the test (running as SysAdmin profile) will return the records but the class itself and the VF page always return null.

I can't figure out where else to check for sharing or permissions issues -- everywhere I've looked this user and profile do have access to the objects, fields, classes, and pages I'm trying to display.

  • the running user in the test is a community user; by any chance is access to the LocalStewards object granted to the community user via Criteria-Based sharing? Apex testmethods won't honor those rules; or, does the community user profile not have access to the LocalStewards object? see also Community User Apocalypse – cropredy Aug 21 at 22:54
  • @cropredy the user in the test is using a profile cloned from the standard customer community user profile with other permissions added. the profile has read access to LocalStewards. i looked up the sharing settings for LocalStewards and it just says 'controlled by parent' so i assume that's not criteria-based sharing? i'm still wondering if this is the right direction to look in though since this seems to be a change that affected community permissions in the past month and i can't think of what else might have changed to make this stop working. any other ideas where i could look? – Sarah Aug 21 at 23:44
  • 2
    this has to be a permissions issue because your testmethod executes the query as sysad and finds the records. Do existing community users successfully find the recs? If code was working recently, it may have been affected by an auto-applied critical update – cropredy Aug 22 at 0:13
  • 3
    I would ask you to change the class to without sharing. This will at least rule out any sharing or record access issues. If it still doesn't works then you know it's not because of any sharing issue. – manjit5190 Aug 22 at 17:22
  • 4
    @manjit5190 it turns out that with sharing without sharing was the solution and the reason i didn't see it the first time is i had forgotten to bring over some records in my partial copy sandbox... so if you want to post that as an answer i'll accept it – Sarah Aug 25 at 19:30

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Browse other questions tagged or ask your own question.