Select Query in Workbench

How to re-assign Salesforce object ownership in bulk

Here is a question I see frequently in the Trailhead Community: How do you re-assign the ownership of objects in bulk? I’m sure there is an app to make this easier, and I suggest you look in the AppExchange if the policy for your org is to use apps first. And I know there are other solutions, this is just one that I find quick and easy because I don’t have to give it too much thought.

Accounts before Owner Change

First: Always try it in a sandbox first and test the results before doing it in production.

Second first, locate the user id of the person who’s object owners ship you want to change from. From their user page (or just copying the link), grab the object ID from the URL.

Find Object Owner

Copy Object ID
Copy Object ID

Now open Salesforce Workbench in another tab, login and navigate to Queries > SOQL queries. If you are adept at SOQL, create a query to pull all of the object you want to re-assign based on the user id. If you are not comfortable writing your own SOQL or just feeling lazy, use Workbench to help create the query:

Select Query in Workbench

The key values you want are the object ID and the owner ID, though adding a Name field to check the values can be helpful. Be sure to select View as Bulk CSV then run the query. Save the resulting file. I recommend naming it something that is meaningful to you rather than accepting the long string produced by default. Open in your favorite CSV editor to see the object and owner ids.

Next, get the user ID of the new owner(s) the same way you did for the current owner. In the CSV file, change the OwnerId value as desired.

For safety reasons, delete all columns from the csv file except Id and OwnerId, then save it with a different name as a CSV file.

Object and Owner IDs only

Back in Workbench, go to Data > Update. Select the object type and click the Choose File button and select the file you just created with the new OwnerId(s), then click Next.

On the mapping screen the values should already be mapped. Check that only the ID and OwnerId are mapped and click the Map Fields button. If there are many records, check the “Process records asynchronously via Bulk API” option on the resulting page then Confirm Update. Note that if rules were changed since the records were created you may have errors that will require fixing the records before they can be updated.

Could happen if rules changed since created

And in list view:

After Owner Change

If you found this interesting, please share.
Virtual Box Disk Space

Managing VirtualBox VDI size for a Linux Guest

If you are just looking to save space on your operating drive, always remember to use the Description box for snapshots and delete those you no longer need.

And if the guest host is Ubuntu, see some good pre-wash steps at https://itsfoss.com/free-up-space-ubuntu-linux/.

Assuming you are using a dynamic disk you can perform the following steps below save more space:

Check for a dynamic disk VDI
Verify the VDI is a dynamic disk

From within the Linux guest, run the following in a terminal:

dd if=/dev/zero of=/var/tmp/bigemptyfile bs=4096k ; rm /var/tmp/bigemptyfile

It will take some time to complete. Depending on the size of the disk and the amount of empty space, it can be a long time, so be patient.

When the commands complete, shut down the guest.

The next step is to run VBoxManage.exe. First, locate where VirtualBox is installed. This is usually C:\Program Files\Oracle\VirtualBox, though you can also find it by checking the path of the VirtualBox launch icon:

Find the VirtualBox install location from the launch icon properties
Find the VirtualBox install location from the launch icon properties

Open a commend prompt (search for cmd.exe) and cd to where VirtualBox is installed:

cd "C:\Program Files\Oracle\VirtualBox"

Locate and copy the path to the VDI:

Locate and copy the path to the VDI
Then run VBoxManage as follows:
VBoxManage.exe modifymedium disk “[absolute path]” –compact
ex:

VBoxManage.exe modifymedium disk "T:\VirtualBoxes\Ubuntu_21.04_withVPN\Ubuntu_VPN_21.04-disk002.vdi " –compact

I also back mine up, which is why I need to reduce the size.

VirtualBox Export Appliance Menu

 

If you found this interesting, please share.

Random Data post at Logic20/20

Quick summary: Proven successful approaches to generating random test data in JMeter as part of a more complex API testing framework

Random data prevents optimized libraries from caching requests and displaying artificially high performance. It is also useful to test the range of accepted values to ensure that the full range is supported. In addition, random data can help with building negative test cases, which are important both for exercising functionality and for determining whether negative test cases result in performance impacts (which are also a security risk). There are many ways to create random data, and this article provides examples of some approaches I have used with consistently positive results as part of a more complex API testing framework.

Apache functions

There are several functions documented on the Apache site. I find that I need to look beyond the documentation for good examples, and you will need to look beyond this short article for more than one, though this is one I use often: ${__RandomString([length],[characters], [variableName])}:

${__RandomString(${__Random(3,20)},ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz,
              notes.saveSessionNotes.myOrderSessionApi)}

Using JSR223 Samplers

JSR223 Samplers are great for taking advantage of the efficiency of the Groovy language in JMeter. There are two types of random data that are well suited for JSR223 Sampler generation. One is generic data, such as numbers, dates, and alpha-numeric characters with an easily defined pattern. The other is a small sample of specific values that can be used randomly.

The static data stored in the JSR223 Sampler should be as realistic as possible. Extracting the data from a production database copy using a query such as

SELECT DISTINCT [FIELD_NAME] from [SCHEMA.TABLE]

is the best way to get realistic and valid values. In cases where an empty string as input will return null as output, consideration must be given to the impact of skipping the null inputs versus using assertions that need to be very complex in order to handle the nulls dynamically.

Random dates

The example below demonstrates an approach to extract the difference in days between the earliest and latest date, then randomly select a number in that range of days and deduct it from the latest date to create a random test value (in this case for a date of birth):

Date  todayDob  = new Date();
Date  bottomDate = Date.parse('yyyyMMdd', '19010101');
Int   diffDays  = todayDob.minus(bottomDate);
Int   rndDiff   = org.apache.commons.lang3.RandomUtils.nextInt(0, diffDays);
Date  randDob   = todayDob.minus(rndDiff);
vars.put('myApiPersist.dob',randDob.format( 'yyyy-MM-dd' ));

Random strings from list

An object array is easier to read and maintain for simple arrays.

String[] empStatuses  = ['Full time student', 'Unemployed', 'Retired',
                       'Employed','Part time student','Unspecified'];
int      empStatusIdx = org.apache.commons.lang3.RandomUtils.nextInt(0,
                        empStatuses.size());
vars.put(‘myApiPersist.employmentStatus', empStatuses[empStatusIdx]);

In the example above, note that org.apache.commons.lang3.RandomUtils is used instead of the Groovy Random class because of how Random is not actually random and can easily lead to clashes across threads. (There are other functions and approaches as well, and I tend to re-use previous code until a compelling reason to change occurs).

For sets of very small lists, using a random number and the modulus operator is more efficient if the random number is already being generated for another value, as in this example:

String[] patGender = ['M', 'F'];
vars.put(‘myApiPersist.gender', patGender[(int)todayDob.getTime() % 2]);

Two-dimensional arrays

2D arrays are necessary when values must be used in pairs to be valid. For those unfamiliar with working with multi-dimensional arrays, here is an example:

String[][] nearestLocation = [["Don't know","UNK"],["SoCal","42035005"],
                       ["None with 100 miles","OTH"],
                       ["Midwest","20430005"],
                          ["Virtual","ASKU"],
                          ["America South","38628009"]];
int      nearestLocationIdx = org.apache.commons.lang3.RandomUtils.nextInt(0,
                            nearestLocation.size());
vars.put(‘myApiPersist.sexualOrientation', nearestLocation[nearestLocationIdx][0]);
vars.put(‘myApiPersist.sexualOrientationCode', nearestLocation[nearestLocationIdx][1]);

Maps

Maps are an alternative to the 2D array. Here is an example from a file upload API test:

def fileSize = [1,5,10,20];
def extensionAndMimeType = [tif: 'image/tiff', pdf: 'application/pdf', jpg: 'image/jpeg', docx: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document'];
def extensions = extensionAndMimeType.collect{entry -> entry.key};
String filePrefix = fileSize.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(0, fileSize.size()));
String fileExtension = extensions.get(java.util.concurrent.ThreadLocalRandom.current().nextInt(0, extensions.size()));
vars.put('session_file.name', String.format('%sMB_File.%s', filePrefix, fileExtension));
vars.put('mime.type', extensionAndMimeType.get(fileExtension));

Random keys from maps

Sometimes you only need the key from a map at certain points in your test. Rather than maintain two samplers, you can access just the keys.

def fileTypes 		= 	[ 'FileAttachment': 1, 'FileAttachmentOpaqueId': 1, 'ClinicalNote': 3, 'ClinicalNoteTemplate': 4, 'ExternalDocument': 5, 'FaxDocument': 6, 'Multiple': 8, 'CCDABatch': 9 ];
def randomFileTypeKey = (fileTypes.keySet() as List).get(ThreadLocalRandom.current().nextInt(fileTypes.size())).toString();
OR:
def randomFileTypeValue = fileTypes.get((fileTypes.keySet() as List).get(ThreadLocalRandom.current().nextInt(fileTypes.size())).toString());
OR:
def randomFileTypeValue = fileTypes.get(randomFileTypeKey);

Lists

At a certain (arbitrary) level of complexity, a List implementation may be easier to maintain (or it may justify an exception to use a CSV file instead). Here is an example of a List of Lists being used to generate all possible combinations of three sets of health-related parameters:

List<List> testValues = [
  ["FEVER","COUGH","SORE_THROAT"], //v3SymptomsSet
  ["POSITIVE","NEGATIVE","PENDING"], //testResult
  ["YES","NO","INDICATED_BUT_UNAVAILABLE"]];//v2TestedStatus
List<List> patCOVID19ScreeningApiVars = [];//
List temp = [];
void generatePermutations(List<List> lists, List result, int depth, List current) {
    if (depth == lists.size()) {
       result.add(current);
        return;}
    for (int i = 0; i < lists.get(depth).size(); i++) {
        generatePermutations(lists, result, depth + 1, current + lists.get(depth).get(i));}
}
generatePermutations(testValues, patCOVID19ScreeningApiVars, 0, temp);
vars.putObject("patCOVID19ScreeningApiVars",patCOVID19ScreeningApiVars);
vars.put("patCOVID19ScreeningApiVars.Count", (patCOVID19ScreeningApiVars.size - 1).toString())
SampleResult.setIgnore();

Ctrl+C/Ctrl+V

There are some alternate ways to generate random values described in this Stack Overflow thread.

Some key considerations for options to generate a random number:

  1. java.util.Random does not generate true random values. A test in JMeter resulted in the same series of numbers every single run. This can increase the likelihood of clashes between threads.
  2. While org.apache.commons.lang3.RandomUtils is a wrapper around java.util.Random, it is (like most of the Apache Commons collection) a well-designed wrapper that results in values that are more random and tested to result in a different series of values on every test run.
  3. ThreadLocalRandom is recommended by some as more efficient. Given these efficiencies are measured in sub-milliseconds and that the Apache Commons is a more reliable collection than the java.util collection, the recommendation is to use RandomUtils.

Random conclusion

The failure of many API tests to catch defects prior to release is the limited inputs used to test them. Using random data in conjunction with iterative loops will help lower the amount of time spent patching production issues and leave more time for building business capabilities and value.


Originally published at https://www.logic2020.com/insight/tactical/generate-random-test-data-run-time-jmeter

If you found this interesting, please share.

What has more impact to Salesforce ROI than downtime, defects, or time to market?

It’s probably not what you were thinking (and kudos if it is):

The number one killer of Salesforce success is user adoption. The first part of planning must include a user adoption strategy, and the first App Exchange install should be the Salesforce Adoption Dashboards.

Recommended Trailheads:

If you found this interesting, please share.

Most Common Question about Salesforce Flows

This is the most common question I see about Salesforce Flows, and was one of my first questions, too. To save me looking it up all the time, I’m storing it here on my blog…

Q: How to have a flow go somewhere other than the page it was called from at completion?

A: See Customize a Flow URL to Control Finish Behavior

If you found this interesting, please share.