December 25, 2010

Invoking “Apex WSDL” Web Services from Apex Code

Because of Tolerado, I came to know about “Apex Programming WSDL” given by Salesforce. Apex WSDL on a high level gives web service APIs for

  • running apex tests
  • executeAnonymous code
  • compiling classes and triggers.

How to download this WSDL ?

Apex programming WSDL can be downloaded from “Setup” area of your Salesforce org. Just land on “App Setup > Develop > API” page. Instructions to download are shown below.

Integrating with “Apex Programming WSDL” !

One can compile/consume this WSDL in various programming languages like Java/PHP/.NET/etc.  Post compilation, one can easily create mashup applications to behave like mini Cruise Control for Apex, those that can run nightly tests for your Salesforce Org etc. Only problem is those application needs to be hosted and maintained by one, not really on CLOUD unless one is developing one Smile

Compiling “Apex WSDL” to generate Apex code stubs (WSDL > Apex)

Fortunately, one can also generate Apex code stubs for a given WSDL i.e. force.com platform gives you an option to do “WSDL > Apex”  compilation.

Using this feature, we can bring the who bunch of web service exposed by “Apex WSDL” to Apex code directly.

So, lets hit the button showed in above screenshot i.e. “Generate from WSDL” and specify the downloaded “apex.wsdl” file, here, as shown below.

In next step, you will be asked to give a good name to the generated Apex class, by default it will come with something like “soapSforceCom200608Apex”. Detailed instructions shown below.

Next, you should see screen like following, giving you the link to the newly generated/compiled Apex class from “Apex WSDL”

Next, we will see how to invoke Apex WSDL web services from Apex code directly.

Invoke Apex WSDL web services from Apex Code

In this section I am assuming you have already generated “ApexStub” class by compiling Apex WSDL, as described above.

Step 1 – Know your web service end point !

As we are going to make web service calls from Apex code, we need to whitelist the web service endpoints first. To know your web service endpoint, there are two ways i.e.

1. Check location attribute of <soap:address location=”https://….”> in Apex WSDL file, it should have something like this. So for my org the web service endpoint to white list is “https://ap1-api.salesforce.com/services/Soap/s/20.0

<soap:address location="https://ap1-api.salesforce.com/services/Soap/s/20.0"/>

2. You can also check your endpoint directly in the ApexStub class. “ApexStub.Apex.endpoint_x” property points to the web service endpoint.

Step 2 – Whitelist the web service end point

To white list, goto “Setup > Administration Setup > Security Controls > Remote Site Settings” and create a “New Remote Site” using the domain details from endpoint captured in steps above. Make sure remote site url is as per your SFDC org, my org is on node “ap1”, yours can be different i.e. on NA1 etc. My security settings are shown below.

Step 3 – Coding time, make the web service call !

Out of all web service calls given by Apex WSDL, most interesting for me is runTests(). This allows one to run tests on either a single, bunch or all apex classes in sfdc org.

Run All Tests Sample

Here is the sample code that uses the “ApexStub” class generated above to run all tests in the org.

ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
// This is important, give session id, to let the call work.
ap.SessionHeader.sessionId = UserInfo.getSessionId();
ApexStub.RunTestsRequest  rtr = new ApexStub.RunTestsRequest();
// Run All Tests
rtr.allTests = true;
rtr.Namespace = '';
// Execute the Tests
ApexStub.RunTestsResult testResults = ap.runTests(rtr);
System.debug("Failures >" + testResults.numFailures);
Running test on Single or bunch of classes
// You can also specify single class in this array
String[] classNames = new String [] {'TestFeature1', 'TestFeature2'};
// or specify package or org wide 
// namespace here
String namespace = ''; 
ApexStub.Apex ap = new ApexStub.Apex();
ap.SessionHeader = new ApexStub.SessionHeader_element ();
ap.SessionHeader.sessionId = UserInfo.getSessionId();

ApexStub.RunTestsRequest  rtr = new ApexStub.RunTestsRequest();
rtr.classes = classNames;
rtr.allTests = false;
rtr.Namespace = namespace;
ApexStub.RunTestsResult results = ap.runTests(rtr);

For more details on how to,

  • Create various RunTestsRequest, check this API Doc.
  • Parse RunTestsResult object, check this API Doc.

Making Apex WSDL calls from Apex – Limitations  !!

As we are making web service callouts from Apex, all the governor limits imposed on web service callouts are applicable here too. For ex.

  • Total request time for all callouts (HTTP requests or Web services calls) in a single unit of work is 120 secs
  • Maximum size of callout request or response (HTTP request or Web services call) is 3 MB

Out of these two only the first one limits us most from doing anything super creative from Apex. So you can’t run all/single/bunch tests, if they consume more than 120 secs to complete. This is pretty easily possible with an org with decent number of apex classes.

So one can’t go straight forward and do anything with Apex WSDL calls.

Creating a Junit like Test Suite using Apex WSDL.

Junit is a unit testing framework in Java. Many bits and pieces of Apex TestCase class are inspired from this framework itself.

A nice feature that’s given by Junit is ability to create TestSuites. A TestSuite is a Composite of Tests. It runs a collection of test cases. The beauty of test suites is you can create small suite of tests per feature or module of your org, this suite will have test classes for the feature/module only. So when you change something, its really not required to run all the tests, you can just run suite and see if everything for the feature is stable.

Apex Test Suites & ApexClass Sobject !

As of now, Apex doesn’t offers this feature. But we can run tests on single class as described above,  so why don’t we use this feature to create test suites in Apex. But for that we need access to Apex Classes available in the org.

Good news !!! Salesforce schema already has an Sobject called “ApexClass”, this sobject keeps information about all the classes in a SFDC org.  One can query this Sobject for details like ClassName, Namespace, Body and length etc.

So, to create Test Suite an rough idea could be to 

  • Create a “TestSuite” and “TestSuiteClass” custom Sobject. “TestSuiteClass” will keep apex class name and namespace, because we can’t lookup or master details to ApexClass object. Test Suite Class will master detail on “TestSuite”.
  • Create a Visualforce page/apex controller, that queries ApexClass sobject and presents a list of Apex classes to end user to select. These selected Apex classes then can be used to create a TestSuite/TestSuiteClass records.
  • Now having this TestSuite and ApexStub class we can execute it in many ways, a slight challenge will be to hack around the governor limits imposed. For ex. we can create another Visualforce/Apex page to run tests available in the TestSuite.
  • Also by using TestSuite and ApexStub class, we can also create applications that tells coverage etc. As RunTestsResult returned after running tests, have fine details about that too.
Test Suite as a Salesforce App - Your views

Let me know what do you feel about this TestSuite concept, if its really worth moving forward like this. If you have some ideas and good feeling about it, we can join our efforts to create an opensource project for this.

Getting Test Suite natively in Force.com Platform - Idea exchange !

I posting TestSuite as an idea on Salesforce Idea Exchange too, to get this feature natively in platform itself. Here is the link to that idea : https://sites.secure.force.com/success/ideaView?c=09a30000000D9xtAAC&id=08730000000KPkXAAW

Please promote it to make the platform better.