+ Start a Discussion
EchoEchoEchoEcho 

Unit Testing Content

Hi,

 

I'm trying to write unit tests for Content. It seems that it is impossible to create a Workspace record in Apex, so I guess we have to use an existing one in the org?

 

Bigger question: If I create a Content record, relate it to an existing workspace using FirstPublishLocationId, and insert it, and then try to make an update to that Content record, I get this error:

 

Document with ID: 06930000000YPbp already has an owning Workspace

 

I get the same error whether or not this is in a test class. If I do it outside of a test class, and just use the record Id a few seconds later to do my update, it will work. So, it seems to be time-based... Is it not possible to update a newly created Content record from within a test class?

 

Thanks,

Tom

OldDeadBugOldDeadBug

I'm getting the same error. I'm attempting to run a test method on a Content record update that contains a ContentURL - essentially trying to update the Content URL.

 

I have inserted two different ContentVersion records, one using a FIle and PAthOnclient, the other using a COntentURL. Both records insert correctly, and the FIle CV is able to refresh its content in APEX by inserting a new CV record using the COntentDOcument ID.

 

However, attempting to update the COntentURL on that CV is causing the same error - from the debug log:

 

02:05:50.859|DML_BEGIN|[254]|Op:Update|Type:ContentVersion|Rows:1
02:05:50.898|DML_END|[254]
02:05:50.898|EXCEPTION_THROWN|[254]|System.DmlException: Update failed. First exception on row 0 with id 068S00000009CyZIAU; first error: FIELD_INTEGRITY_EXCEPTION, Document with ID: 069S00000000p2v already has an owning Workspace: []

 

Now I know the Document has an owning workspace, and whereas I did publish the document to a workspace on insert for both CV records, only the COntentURL CV is complaining about already having an owning Workspace, as if I'm trying to move it to a new Workspace - which I am not. Both records are following the same update procedure.

 

ALSO, I physically added a third ContentURL CV and queried this record into the test method, and it updated with no problem, so it doesn't appear to be assiciated with COntentURL-type CVs (and no, I'm not using ContentTypes at all)

 

I realize that Content isn't really much of a big deal to the Salesforce folks these days, what with Chatter, Database,com, VMWare all ramping up- Content seems like a bit of an afterthought - no one I spoke to at Dreamforce knew anything about Content or any roadmap as to its improvement. But this is a weird glitch, and the error message isn't telling me enough to figure out how to resolve it so it would be really cool if someone could provide some guidance to what could be happening here given that nothing in the code is attempting to update or add a new ContentWorkspaceDoc record, or delete the old one and change it, or anything else having to do with the workspaces.

 

Just want to update the ContentURL and maybe a couple of custom fields. That's it!

 

Thanks

Ron-LONRon-LON

Have either of you guys found a solution to this? 

 

I want to move owning workspaces using code and I'm getting this error.  I can change nonowning workspaces using code just fine.

 

I think there's just not a lot of people trying to do anything with Content in APEX and that's why no responses. 

EchoEchoEchoEcho

Unfortunately, I never found a solution. We had to pick a random existing Content record in the org (that met a few criterai) for the unit tests. It's a horrible test, but I can't figure any way around it.

OldDeadBugOldDeadBug

I have found a solution!!

 

Here's the deal: Any content record inserted in a test method using the standard API insertion process will throw this error when you try to update that same test record. It has to do with the FirstPublishLocationID being set during the insert somehow not being released in memory for some reason such that when you update that same record, the system thinks you're still trying to assign that value.

 

The only way around this is to insert a test record you plan to update using a process that mimics the UI insertion. Here;s how you do that:

 

First  insert the Test Content record with just the VersionData/PathOnClient combination or a ContentURL, the Title, and if appropriate, the Record TypeID (as this can't be set with an update).

 

Once that is inserted, query the ContentDocumentId for that new record, as well as the id of the ContentWorkspace you want to initially publish it to, Using those ids, create a ContentWorkspaceDoc record (as opposed to using the FirstPublishLocationId). Then query your new Test Content record for any custom fields, add values for those fields and update the Test Content record.

 

At that point, you have the same Content Record you would have had had you used the standard API insertion, except you never actually had to assign the FirstPublishLocationId, which is the source of the error.

 

At that point you should be able to use that recordfor any subsequent update tests.

 

In my case, I have a web service adding content provided by outside systems. I am using the standard API insert method in that web service due to a really bad Salesforce bug that occurs if you use the UI-mimic method in practice - the Storage Usage limits are increased 3-FOLD!!!! That;s both the number of bytes and the number of records - EVEN THOUGH ONLY ONE ACTUAL RECORD IS INSERTED. Deleting the record is successful, but only updates the Storage Usage numbers by the value of that one record.

 

In other words: Using an APEX process to mimic the UI insertion as described above on a 1 Mb file will cause the Storage USage to thisnk you have just loaded 3 files adding up to 3Mb in your storage Usage capacity. Deleting that file only removes the 1 file and 1Mb, leaving the 2 files and  2Mb counting against your Storage capacity, even though there are no files. This has been confirmed several times by a Tier 3 Support rep.

 

However, in a test method the Storage Usage limits aren't impacted so you can use the UI-mimiv method to add Test Files to a test method, and thus allow for the ability to update in the Test method.

 

Good luck getting your tests to work.

Ron-LONRon-LON

Thanks for the responses to this.  It has helped immensely, but it's shown some glaring shortcomings in Salesforce Content that Salesforce themselves have refused to include in documentation.

 

I've got one last question on this.  I'm using different content workspaces to enforce permissions on content.  When I load content, I don't have the luxury of not putting a FirstPublishLocationId because if I don't, I can't add in values in the custom fields on the Content record or add tags to it.

 

I can share content with workspaces in code by adding rows to ContentWorkspaceDoc and I can unshare by deleting rows from ContentWorkspaceDoc.  But I can only do this where IsOwner = false . 

 

But for permissions to work properly, I need to move the workspace, or in database parlance, I need to change the WorkspaceId for the record where IsOwner = true. I get the FIELD_INTEGRITY_EXCEPTION, Document already has an owning Workspace error. 

 

I try inserting a record, I get the error.  As you'd expect.  I try updating the record that's already there to change the WorkspaceId.  I still get the error.   So if it doesn't allow inserts and it doesn't allow updates, just how do you change the Owning Workspace in APEX code?

 

I'm in deep trouble with this with a client's project and I may have to tell them that Salesforce.com has really let them down.

OldDeadBugOldDeadBug

 


Ron-LON wrote:

Thanks for the responses to this.  It has helped immensely, but it's shown some glaring shortcomings in Salesforce Content that Salesforce themselves have refused to include in documentation.

 

I've got one last question on this.  I'm using different content workspaces to enforce permissions on content.  When I load content, I don't have the luxury of not putting a FirstPublishLocationId because if I don't, I can't add in values in the custom fields on the Content record or add tags to it.

 

I can share content with workspaces in code by adding rows to ContentWorkspaceDoc and I can unshare by deleting rows from ContentWorkspaceDoc.  But I can only do this where IsOwner = false . 

 

But for permissions to work properly, I need to move the workspace, or in database parlance, I need to change the WorkspaceId for the record where IsOwner = true. I get the FIELD_INTEGRITY_EXCEPTION, Document already has an owning Workspace error. 

 

I try inserting a record, I get the error.  As you'd expect.  I try updating the record that's already there to change the WorkspaceId.  I still get the error.   So if it doesn't allow inserts and it doesn't allow updates, just how do you change the Owning Workspace in APEX code?

 

I'm in deep trouble with this with a client's project and I may have to tell them that Salesforce.com has really let them down.


If I understand your question, it sounds like you're trying to change the FirstPublishLocationId to anolther value after its been set during the insert. Once the FirstPublishLocationId is set, that's it - it then becomes a read-only field. THis is documented in the API guide. You can create additional ContentWorkspaceDoc records to link them to other workspaces (I've been able to do this) and you may be able to delete the first ContentWorkspaceDoc record if the Content has been linked to another workspace through another CWD record (haven't tried this), but you can't mess with the FirstPublishLocationId once it has ben cast.
If you are attempting to insert and update the same document in the same process, you won't be able to do this if your insert uses the standard API insertion where you use the FirstPublishLocatonId due to some freaky bug that keeps this value around during the course of the operation - an update to the same document is currently interpreted as an attmept to change the owning workspace, even if you are not attempting to update. 
Using the UI-emulation method of inserting content avoids the update glitch, but if you use the UI-emulation method as part of your main APEX class, it will generate Storage Usage errors and you'll haver to wait about a week for your case to get escalated to a Tier 3 support rep to reset your Storage Usage numbers. This is a lot of fun if you are testing the import of large files in the sandbox as its generally limited to 10Mb. However using the UI-emulation method will work to add test content records into your test methods that can then be updated as the FirstPublishLocationId was added behind the scenes when you create the record's first ContentWorkspaceDoc. Test Inserts won't count against the Storage Usage limits at all.

Otherwise, I fully agree with you about the lack of adequate documentation about working with Content in APEX. Content is a bolt-on application which Salesforce bought to supplement their rather limited Documents object which had very little in the way of flexible permissions and no versioning. Content was designed to fill that hole, nothing more, It is not designed to compete with Documentum or similar CMS companies. But that being said, it really blew me away at how meager was the understanding of this piece by anyone at Salesforce Support. Your typical Tier 1 and Tier 2 support rep will tell you they 'get it', but they don't have a clue. You can practically hear their ears glazing over as you describe the problem- even the Tier 3 support rep I spoke to was flummoxed.
The lack of Salesforce responding to this or other threads over the same problem is pretty indicative of their own lack of understanding, or in the light of all the hype around Chatter, how little they care about it. Content is on nobody's mind there. At Dreamforce, I couldn't find anyone to ask about issues working with Content at the Developer's section or the Campground. I may be wrong but I don't recall there being any breakout sessions for Content either.
Can you believe they actually used to charge extra for this?

 

Prady01Prady01

hello OldDeadBug could you plz elobrate your post... About how to insert a content object and set the custom fileds with values so that i could make my test class based on content object to have much more coverage...

EchoEchoEchoEcho

Hey Pradeep@cloud, 

 

If you're working with custom fields on a Content record, you'll have to associate it to a Workspace, and you'll get the same error whether or not this is in a test class. If you do this outside of a test class, and just use the record Id a few seconds later to do my update, it will work. So, it seems to be time-based... FirstPublishLocationId seems to kick off an asynchronous process to create the ContentDocument and ContentWorkspaceDoc records from your ContentVersion record.

The solution seems to be to insert a ContentVersion record, select an Id from your chosen Workspace, and select the ContentDocumentId from your newly created ContentVersion. You can then create your own ContentWorkspaceDoc record to relate the ContentDocument to the ContentWorkspace, and update your custom field on the ContentVersion record.

 

public ID setupContent()
{
RecordType ContentRT = [select Id FROM RecordType WHERE Name = 'Category'];

ContentVersion testContentInsert = new ContentVersion();
testContentInsert.ContentURL='http://www.google.com/';
testContentInsert.Title = 'Google.com';
testContentInsert.RecordTypeId = ContentRT.Id;

insert testContentInsert;

ContentVersion testContent = [SELECT ContentDocumentId FROM ContentVersion where Id = :testContentInsert.Id];

ContentWorkspace testWorkspace = [SELECT Id FROM ContentWorkspace WHERE Name = 'My Library'];

ContentWorkspaceDoc newWorkspaceDoc = new ContentWorkspaceDoc();

newWorkspaceDoc.ContentWorkspaceId = testWorkspace.Id;
newWorkspaceDoc.ContentDocumentId = testContent.ContentDocumentId;

insert newWorkspaceDoc;

testContent.iPad_Content_Views__c = 0;

update testContent;

return testContentInsert.Id;
}

Prady01Prady01

Thanks a lot Echo, Your post really helped me solve my issues, Thanks a lot :)...... I have been sitting on this from past few days and had lost all the interest anyhow thanks for your help i was able to solve it....

EchoEchoEchoEcho

Happy to help!

Rahul_sgRahul_sg
Thanks EchoEcho.... !!