Take the 2-minute tour ×
Salesforce Stack Exchange is a question and answer site for Salesforce administrators, implementation experts, developers and anybody in-between. It's 100% free, no registration required.

I'm doing something in a visualforce controller for every attachment and chatter contentpost that is related to a particular case. Hoping to open-source it (pending employer ok), but for now I'll just post a few snippets from it.

    for( CaseFeed fi : [
        SELECT
            ContentFileName,
            ContentType,
            ContentSize,
            RelatedRecordId,
            CreatedDate
        FROM CaseFeed
        WHERE ParentId =: ctrl.getId()
        AND Type =: 'ContentPost'
        LIMIT 500
        ]
    ){
        //Do something with it
    }

Parentid is set to the id of the case in question. This query works well with "with sharing" set on the controller. Changing the query from looking at CaseFeed to FeedItem requires "without sharing" to be set on the controller which is not cool.

The problem I'm facing is in unit testing this, you can't apparently insert a CaseFeed record directly, you're supposed to insert a FeedItem like so:

        FeedItem chatterCrap = new FeedItem(
            ParentId=caze.Id,
            ContentFileName='kittens.jpg',
            ContentData=EncodingUtil.base64Decode('fluffykittens')
        );
        insert chatterCrap;

The problem with this is that the query in the controller that's supposed to pick out all the ContentPosts (chatter with files on them) doesn't see any CaseFeed when only the FeedItem has been inserted. If the controller looks at FeedItems it works, but that's not acceptable due to violating sharing-control.

In the actual SF use, i.e. not test cases, inserting a FeedItem seems to automatically create a CaseFeed record, and the visualforce controller works flawlessly for what I want it to do - just not it's test cases.

My experience with chatter is limited so I'm hoping someone can point out where I'm perhaps doing something wrong, the documentation is utterly useless (much like chatter itself, but that's just my personal opinion).

Edit (addition of a minimal test case that fails in our org):

@isTest(seeAllData=false)
static void test(){
    Profile p = [SELECT Id FROM Profile WHERE Name = 'Standard User' limit 1];
    User u = new User(
        Username='firstname.lastname@some.org',
        Email='firstname.lastname@some.org',
        Lastname='Lastname',
        Alias='fl',
        LanguageLocaleKey='en_US',
        LocaleSidKey='en_US',
        TimezoneSidKey='America/Los_Angeles',
        EmailEncodingKey='UTF-8',
        ProfileId=p.Id
        );
    insert u;
    Case caze = new Case();
    insert caze;

    System.runAs(u){
        //Chatter post on case
        FeedItem chatterCrap = new FeedItem(
            ParentId=caze.Id,
            ContentFileName='kittens.jpg',
            ContentData=EncodingUtil.base64Decode('fluffykittens')
        );
        insert chatterCrap;

        Integer howManyAreThere=0;
        for( CaseFeed fi : [
            SELECT
                ContentFileName,
                ContentType,
                ContentSize,
                RelatedRecordId,
                CreatedDate
            FROM CaseFeed
            WHERE ParentId =: caze.Id
            AND Type =: 'ContentPost'
            LIMIT 500
            ]
        ){
            howManyAreThere++;
        }
        System.assertEquals(1,howManyAreThere);
    }
}
share|improve this question
add comment

1 Answer 1

up vote 1 down vote accepted

First, for the Chatter feed, you can only insert from FeedItem object. CaseFeed, AccountFeed,... is just like a interface of FeedItem. The real data is save in the FeedItem object. see the Chatter data model here,

http://www.salesforce.com/us/developer/docs/api/Content/RelationshipsOfChatterObjects.htm

Therefore, use your code to insert a feed on a Case record through FeedItem object, you can query on CaseFeed object to confirm it,

CaseFeed cf = [Select Id, Type from CaseFeed Order by CreatedDate Desc limit 1]; system.debug(cf);

You can confirm this through Execute Anonymous.

In your case, after insert a Feed on Case record, you retrieve this feed through the Controller with sharing. If the running user without the permission to access this specific Case record with feed posted, he can't see this feed too. As in this situation, the Feed is a child of the parent record(the Case).

share|improve this answer
    
Well, that's not really the problem. I insert a feeditem, just like you propose. I can assert that the FeedItem has been created just fine in my testcase, but it does not actually create the "interface" CaseFeed which is kind of the whole issue. In execute anonymous, yes it works, but in testcase - no. –  Martin Peters Jan 23 '13 at 15:02
    
I wrote a Test class for myself. After inserted a Feed on the Case record, I can just retrieve it from CaseFeed object with no problem. By the way, do you have any Trigger on the FeedItem object, it may effect some way. –  Jia Hu Jan 23 '13 at 15:30
    
Thanks for the effort. I've got no triggers on anything chatter-related, we hardly use it in our org except for what the new case feed layout on cases forces us to. –  Martin Peters Jan 23 '13 at 15:37
    
I've added a test-case to my question that fails in our org. –  Martin Peters Jan 23 '13 at 15:46
    
Yeah, just tested it. Set seeAllData=true and no other revision, then your code will work. –  Jia Hu Jan 23 '13 at 15:55
show 1 more comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

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