Technical Blog

5 Posts authored by: Daniel Wu

Performance testing is a task often left to the last stages of software development, after the code is checked in, passed QA for functional testing, and no longer fresh in the minds of developers who wrote it. With JUnitPerf, you can leverage your existing suite of JUnit tests to get performance measurements while you're developing. The framework provides easy to use decorator classes for creating:

 

  • Timed tests to measure execution time
  • Load tests for measuring how your code runs with multiple requests

 

Performance tuning should always be done with a performance goal in mind, and JUnitPerf shouldn't be the end all measurement tool for the performance your code. Instead it is more useful for

 

  • Getting a basic idea of where your execution bottlenecks may lay
  • Evaluating the performance difference between multiple technical solutions
  • Uncovering immediate concurrency issues

 

JUnitPerf uses decorator classes to wrap existing JUnit tests. This makes it possible to add performance measurements even to HttpUnit or DbUnit tests.

In our examples we will use the following unit test

public class SimpleUnitTest extends TestCase {
...
  public void test1() {
      ... //some operations
  }
...

 

A TimedTest can be used to provide a time limit for your running tests. Tests will fail if they take longer than the given time limit to execute. This is useful if you know you don't want to exceed a certain time constraint. Here we are running all tests within the SimpleUnitTest class as a suite with a time limit of 1 second.

public class SimplePerfTest {
  public static void main(String[] args) {
    int timeLimit = 1000;
    Test timedTest = new TimedTest(new TestSuite(SimpleUnitTest.class), timeLimit);
    junit.textui.TestRunner.run(timedTest);
  }
}

 

You can use LoadTest to create a load test with a specified number of threads(JVM will constrain the upper thread limit) running your test case either simultaneously or at randomly dispersed start times. We will do the simplest example of running a test suite with 100 threads concurrently.

public class SimplePerfTest {
  public static void main(String[] args) {
    int load = 100;
    Test loadTest = new LoadTest(new TestSuite(SimpleUnitTest.class), load);
    junit.textui.TestRunner.run(loadTest);
  }
}

 

In a more complex example of using LoadTest, we can simulate 100 threads running our test code, with a random delay before the addition of each concurrent thread. In addition to the RandomTimer class to specify a delay, there is also the ConstantTimer to specify a constant delay between thread addition.

public class SimplePerfTest {
  public static void main(String[] args) {
    int threads = 100;
    int delay = 10;
    int randomVariation = 20;
    Timer randomTimer = new RandomTimer(delay, randomVariation);
    Test loadTest = new LoadTest(new TestSuite(SimpleUnitTest.class), threads, randomTimer);
    junit.textui.TestRunner.run(loadTest);
  }
}

 

Lastly, we can combine both TimedTest, LoadTest, and RepeatedTest (part of JUnit) to string together a rather sophisticated concurrent performance test. Here's a test that concurrently runs your unit test in 100 threads, each repeating 10 times before ending, with a time limit of 2 seconds for the test to complete. Threads are being added after every 10ms by using the ConstantTimer.

public class SimplePerfTest {
  public static void main(String[] args) {
    int timeLimit = 2000;
    int threads = 100;
    int delay = 10;
    int repetitions = 10;
    Timer randomTimer = new ConstantTimer(delay);
    Test timedTest = new TimedTest(new TestSuite(SimpleUnitTest.class), timeLimit);
    Test repeatedTest = new RepeatedTest(timedTest, repetitions);
    Test loadTest = new LoadTest(repeatedTest, threads, randomTimer);
    junit.textui.TestRunner.run(loadTest);
  }
}

 

JUnitPerf tests are great for quickly spotting performance problems early in the development cycle, requiring very little extra work if your regular coding practice already includes JUnit, and extensions of JUnit such as HttpUnit and DbUnit. With multithreaded LoadTests, it can also be helpful in uncovering concurrency issues normally difficult to discover with code inspection or other forms of testing. There is unquestionable value in performing performance testing on a fully functional and integrated system, but you can cut down both cost and risk to your project by validating the performance of your designs early, especially architectural decisions that may be hard to change later on (though being Agilists, we always try to make change easy. But that's a topic for another day).

 

 

Resources:

http://clarkware.com/software/JUnitPerf.html

Home of JUnitPerf

 

http://junit.org

Home of JUnit

 

http://www.dbunit.org/

Home of DbUnit

 

http://httpunit.sourceforge.net/

Home of HttpUnit

 

http://www.ibm.com/developerworks/java/library/j-cq11296.html

Performance testing with JUnitPerf

0 Comments Permalink

       

When you want a perspective to include a snazzy new button that launches an editor or opens a dialog, you most likely want to add that action into the toolbar section along the top, as well as in the top drop down menu. All of the needed configuration to do this can be done in the plug-in's own plugin.xml by adding a few extensions. We'll use the Create Order action in the Fulfillment perspective as an example. The end result will have a Create Order item in both the toolbar and the top menu, along with the keyboard binding for power users.

 

First, you'd want to create an ActionSet in the perspective to help group your new items together:

  <extension

        point="org.eclipse.ui.perspectiveExtensions">

      <perspectiveExtension

          targetID="com.elasticpath.cmclient.fulfillment.perspective">

        <actionSet

              id="com.elasticpath.cmclient.fulfillment.workbenchActionSet">

        </actionSet>

      </perspectiveExtension>

  </extension>

  <extension

        point="org.eclipse.ui.actionSets">

      <actionSet

          id="com.elasticpath.cmclient.fulfillment.workbenchActionSet"

          label="Create Order ActionSet">

      </actionSet>

  </extension>

 

We then define the commands that will be actually performed when the items are selected. This requires your own handler java class (in this case CreateOrderHandler) which extend org.eclipse.core.commands.AbstractHandler and has its own execute() method to perform your intended action.

  <extension

        point="org.eclipse.ui.commands">

      <category

          description="Create Order Command"

          id="com.elasticpath.cmclient.fulfillment.commands"

          name="Create Order">

      </category>

      <command

          categoryId="com.elasticpath.cmclient.fulfillment.commands"

          defaultHandler="com.elasticpath.cmclient.fulfillment.editors.actions.handler.CreateOrderHandler"

          description="Create Order"

          id="com.elasticpath.cmclient.fulfillment.command.create.order"

            name="Create Order">

      </command>

  </extension>

 

Add the key bindings for the commands for quick keyboard access:

  <extension

        point="org.eclipse.ui.bindings">

      <key

          commandId="com.elasticpath.cmclient.fulfillment.command.create.order"

          contextId="com.elasticpath.cmclient.fulfillment.workbenchActionSet"

          schemeId="org.eclipse.ui.defaultAcceleratorConfiguration"

          sequence="M1+M2+O">

      </key>

  </extension>

Now we can add the menu item and toolbar item by extending the org.eclipse.ui.menus extension point. The visibleWhen attribute ensures that the items only show up when the ActionSet we defined earlier is activated.

  <menuContribution

            locationURI="menu:org.eclipse.ui.main.menu">

          <menu

              id="com.elasticpath.cmclient.fulfillment.workbenchMenu"

              label="%fulfillmentMenu.name"

              mnemonic="C">

          </menu>

      </menuContribution>

      <!-- toolbar -->

      <menuContribution

            locationURI="toolbar:org.eclipse.ui.main.toolbar">

          <toolbar

              id="com.elasticpath.cmclient.fulfillment.toolbar.createOrder">

            <command

                  commandId="com.elasticpath.cmclient.fulfillment.command.create.order"

                  icon="icons/order_create.png"

                  id="com.elasticpath.cmclient.fulfillment.toolbarMenus.createOrder"

                  label="%createOrder.label"

                  tooltip="%createOrder.toolTip">

              <visibleWhen>

                  <with

                        variable="activeContexts">

                      <iterate

                            operator="or">

                        <equals

                              value="com.elasticpath.cmclient.fulfillment.workbenchActionSet">

                        </equals>

                      </iterate>

                  </with>

              </visibleWhen>

            </command>

          </toolbar>

      </menuContribution>

      <!-- menu item -->

      <menuContribution

            locationURI="menu:com.elasticpath.cmclient.fulfillment.workbenchMenu">

          <menu

              id="com.elasticpath.cmclient.fulfillment.workbenchMenu"

              label="Create Order"

              mnemonic="O">

            <command

                  commandId="com.elasticpath.cmclient.fulfillment.command.create.order"

                  icon="icons/order_create.png"

                  id="com.elasticpath.cmclient.fulfillment.toolbarMenus.createOrderMenu"

                  label="%createOrder.label"

                  mnemonic="O"

                  tooltip="%createOrder.toolTip">

              <visibleWhen>

                  <with

                        variable="activeContexts">

                      <iterate

                            operator="or">

                        <equals

                              value="com.elasticpath.cmclient.fulfillment.workbenchActionSet">

                        </equals>

                    </iterate>

                  </with>

              </visibleWhen>

            </command>

          </menu>

      </menuContribution>

    </extension>

   

   

And the result:

danw-add-menu-01.jpg

0 Comments 0 References Permalink

Elastic Path 6.1 provides a new way to manage your application configuration. In the past, settings were stored in a variety of places throughout the system; some were in XML files, others were in properties files, and still others were stored in different tables in the database. Now, the most commonly used settings are stored in the database and can be configured using the Commerce Manager.

Custom settings can be migrated to use this framework with little code change and would be able to take advantage of Elastic Path 6.1 multi-store setting management features.

Setting Definitions

Setting definitions are stored in the database, in the TSETTINGDEFINITION table. A setting definition contains:

 

  • a path
  • a default value
  • a value type
  • the maximum number of overrides

 

The path is a unique identifier for the setting. For example COMMERCE/STORE/giftcertificatesEnabled path refers to the setting that sets whether gift certificates are enabled for a given store.

The default value is the fallback to use when a specific value hasn't been assigned to the setting.

 

The value type indicates the type of value stored in the setting (a string, a number, a URL, etc.).

 

The maximum number of overrides specifies the number of values that can be assigned to a setting. Some settings can have multiple values assigned to them. Others can only have one. For example, a store-specific setting would need to have different values for different stores, so the number of overrides would be very large or unlimited (-1). For a system-wide setting, there is generally only one override.

Setting Values

The TSETTINGVALUE table contains the values that have been assigned to settings. Each value has a context. For system settings, the context is empty. For store-specific values, the context contains a store code.

Setting Metadata

Setting metadata is stored in the TSETTINGMETADATA table. It can be used to store additional configuration information relating to the setting. A setting can have any number of metadata associated with it.

Setting metadata consists of a set of key/value pairs. In Elastic Path 6.1, there are two metadata key/value pairs that can be assigned to settings:

 

  • RefreshStrategy, which defines the setting's refresh strategy

 

  • availableToMarketing, which indicates whether the setting is displayed in the store Marketing tab.

 

Setting Refresh Strategies

The setting refresh strategies metadata provides fine-grained control over when setting changes are applied to the system. In the past, most setting changes required restarting the server. Now, when the setting change is applied depends on how you've configured its refresh strategy. Out of the box, Elastic Path 6.1 provides four refresh strategies:

 

  • application: settings that use the application refresh strategy are only applied after the application is restarted

 

  • session: settings that use the session refresh strategy do not change during the lifetime of the user's session. If an administrator changes the setting value, users will not see the change until their session cookie is removed or expires and a new session is created

 

  • interval: settings that use the interval refresh strategy are cached for a specified period of time. Users do not see changes until the cache expires

 

  • immediate: settings that use the immediate refresh strategy are updated immediately. As soon as the administrator changes a setting that uses this strategy, the change is applied everywhere

Creating a Setting Definition

New setting definitions can be added by executing SQL insert statements. For example, the following creates a definition identified by the path CUSTOM/WIDGETS/widgetType:

INSERT INTO TSETTINGDEFINITION(UIDPK, PATH, DEFAULT_VALUE, VALUE_TYPE, MAX_OVERRIDE_VALUES)
VALUES(10001, "CUSTOM/WIDGETS/widgetType", "flat", "String", 0, 1);

 

For your custom settings, you should use a naming convention, to avoid conflicts with other settings. Do not use the COMMERCE path prefix, which is reserved for Elastic Path settings.

Adding a Value for the Setting

Setting values can be added by using the Commerce Manager client application. For more information, see the Commerce Manager User Manual.

You can also use SQL insert statements. Remember that you don't need to create a setting value if there is a default value that comes from the setting definition.

Assuming you do want to override the setting definition for a specific context (store code for stores), you can create the value with the following SQL:

INSERT INTO TSETTINGVALUE(UIDPK, SETTING_DEFINITION_UID, CONTEXT, CONTEXT_VALUE)
 VALUES(1011, 10001, "SLRWORLD", "circle")

 

Note the value of SETTING_DEFINITION_UID should match the UIDPK for the related row in TSETTINGDEFINITION.

Note that multiple setting values can be defined on a setting definition if the setting definition's max_override_values field is set to -1.

 

Settings Framework Services

Elastic Path 6.1 provides a low level SettingsService class to manage and retrieve of setting definitions and values. To get a setting value for a system level setting with no context:

SettingsService settingsService = getElasticPath()
   getBean(ContextIdNames.SETTINGS_SERVICE);
final int numOfMinutes = Integer.valueOf(settingsService.getSettingValue(
   "COMMERCE/APPSPECIFIC/RCP/idleTimeForLock").getValue());

 

To get a setting value for a particular context:

settingsService.getSettingValue(path, store.getCode()).getValue();

 

If there is no setting value in TSETTINGVALUE for the specified context, the system will fall back to the default value in TSETTINGDEFINITION. For example, the default value of the COMMERCE/STORE/giftcertificatesEnabled setting is false, but a setting value for the context SNAPITUP is true, so the Snap It Up store has gift certificates enabled.

 

A SettingsReader service interface is provided for read only operations. Additionally, the CachedSettingsReader service wrapper provides caching for settings retrieval, and is the preferred method in the storefront to avoid frequent database calls.

 

In storefront controllers, the StoreConfig object (available through the RequestHelper) can be used to obtain setting values. If a store specific value is available, it will automatically be retrieved. Otherwise, the default value from the setting definition is returned.  For example:

String pagination = getRequestHelper().getStoreConfig()
 getSetting("COMMERCE/STORE/CATALOG/catalogViewPagination").getValue();
int paginationNumber = NumberUtils.toInt(pagination, DEFAULT_PAGINATION);

 

Elastic Path 6.1's settings framework should replace usage of configuration files for custom configuration settings, especially where multiple stores are being deployed. Previous code retrieving settings from the ElasticPathImpl object should be migrated to the settings framework and its suite of APIs.

0 Comments 0 References Permalink

     

Elastic Path Commerce 6.1 introduces a number of changes from version 6.0.x. Primary among these are a major change to the store asset directory structure; movement of store configuration information from the file system to the database; and a number of minor changes to the existing database tables. As a result, 6.0.4 deployments with existing data can be upgraded to the 6.1 codebase with relocation of store assets; migration of configuration files into the database; and database upgrade scripts.

 

Note that it's assumed that the codebase has already been upgraded to 6.1; it's up to you to decide how code merge is done. It's also assumed that the existing deployment was already at the latest service release (6.0.4) before upgrading to 6.1.


Store Assets Relocation

Along with the XML configuration files, store-specific visual presentation elements used in the Storefront and emails have been moved from the WAR files into a central assets directory.  These include all Velocity templates, message properties files, images, javascript, css and Power Reviews.

 

  • The simplest way to move storefront assets out of the WAR file is to copy the directories com.elasticpath.sf/template-resources and com.elasticpath.sf/WEB-INF/templates to the new assets directory under a theme folder of your choosing. The assets directory will have the structure:

 

assets/themes/<theme_name>/<store_code>/templates

assets/themes/<theme_name>/<store_code>/template-resources

 

  • Email templates previously located in com.elasticpath.cm/WEB-INF/templates also need to be moved to the assets folder. Email templates and property files that are not connected to any particular store will need to be moved to: assets/cmassets/templates/velocity

 

  • Storefront related emails will be located under their respective theme folders: assets/themes/<theme_name>/<store_code>/templates/velocity

Configuration File Migration

Much of the configuration data previously in XML files within Elastic Path WAR directories has been moved into the database to be managed through the Settings framework in the CM. This includes commerce-config.xml, search-config.xml, urlrewrite.xml, intelligent-browsing.xml. Please consult the settings framework documentation before migrating configuration settings.

 

  • With the exception of web.sf.context.url, all settings previously in commerce-config.xml have been moved to the Settings framework and are no longer required to be in the XML file. Values in these settings (e.g. VFS paths/login) should be updated in the Settings framework through the CM Settings configuration view as new Setting values or inserted into tables TSETTINGVALUE where appropriate. Additional custom settings in commerce-config.xml file should be moved to the Settings framework as new Setting definitions in TSETTINGDEFINITION. A table of where settings in the commerce-config.xml reside in the settings framework is provided in Appendix A.

 

  • Content in intelligent-browsing.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/STORE/FILTEREDNAVIGATION/filteredNavigationConfiguration

 

The content can also be copied into the CM Store Editor's Filtered Navigation section.

 

  • Content in urlrewrite.xml has been moved to the Settings framework and the file is no longer needed. Its contents should be inserted as a new Setting Value for the setting COMMERCE/SYSTEM/urlRewriteConfig

 

  • Content in search-config.xml has been moved to the Settings framework and the file is no longer needed. If any customization has been made, the Setting values under the paths COMMERCE/SEARCH/<setting> should be updated appropriately.

Database Upgrade

Upgrade SQL scripts are provided along with each release of Elastic Path to capture changes in the database schema between the new release and the latest service release.

Each supported database (MySQL, SQL Server, Oracle) will have its own upgrade script.

 

  • Upgrade scripts are provided in the 6.1 distribution for each database, and should be run by the tools provided by the database vendor.
  • Upgrade scripts will apply schema changes and insert necessary base data on an existing 6.0.x database, but does not change existing data.

 

After running the upgrade script, the steps can be done through the CM or directly through the database to get your deployment up and running:

 

  • Reassign supported currency and supported locales to existing stores in the CM, or insert entries in the TSTORESUPPORTEDCURRENCY and TSTORESUPPORTEDLOCALE respectively.
  • Change the display theme of existing stores appropriately by editing the COMMERCE/STORE/theme setting in either the System Configuration section of the CM or the Store Editor.
  • Set the correct value for the search server in the settings framework, under the path COMMERCE/SERVER/SEARCH/searchHost
  • Search indexes need to be rebuilt. This is an automatic step if old indexes are deleted.
  • Set the correct values for the asset VFS in the settings framework under COMMERCE/APPSPECIFIC/RCP/ASSETS/<setting>
  • Gift certificate themes need to be recreated through the CM, and assigned to stores in the CM Store Editor.
  • Be aware that stores can now only be accessed through the URL defined in the CM Store Editor (TSTORE table in the databse), and care should be taken when testing.

Caveats

  • The upgrade process cannot cover all possible database and code customizations to the 6.0.x codebase, and upgrade scripts should be reviewed before running on any schemas that you have customized.
  • Before moving existing storefront assets, be aware that there are changes in these files (Velocity templates, property files) that might not be picked up through a normal code merge due to the change in location.
  • New configuration settings introduced in 6.1 take on their default values after an upgrade, and should be reviewed for correctness.

 

Upgrading to 6.1 from 6.0.4 requires little database change. Configuration files and asset migration make up the bulk of the upgrading effort, and existing customizations to configuration and assets should be reviewed to take advantage of the new settings framework and asset repository.

0 Comments 0 References Permalink

In Elastic Path 6.1, we updated some of our library dependencies to more recent versions. This article outlines the changes, how they impact the application in terms of performance and behaviour, and how they might impact any custom Elastic Path development work you might be doing.

 

  • JUnit has been upgraded from version 3.8.1 to 4.4. Version 4.4 of the JUnit testing framework provides more powerful unit testing features, leveraging Java annotations. The upgrade is fully backwards compatible with tests written against older versions of JUnit. For more information on JUnit 4, go to http://junit.org/.
  • jMock has been upgraded from version 1.1 to 2.5. jMock 2.5 provides better management and creation of mock objects, but is not fully compatible with version 1.1, so both versions still exist as dependencies in Elastic Path 6.1. For more information on jMock 2.5, go to http://www.jmock.org/.
  • For an example of a test class in that uses the features of JUnit 4 together with jMock 2, see com.elasticpath.service.impl.GiftCertificateThemeServiceImplTest in the com.elasticpath.core product.#
  • The Spring framework was upgraded from 2.0.4 to 2.5.5. This upgrade brings improved performance, ease of configuration, and new features. For more information on the changes, see the Spring framework site (http://static.springframework.org/spring/docs/2.5.x/reference/new-in-2.html).  This upgrade is backwards compatible with previous versions of the Spring framework and customizations should not be affected.
  • Url Rewrite Filter was upgraded from 2.5.2 to 3.1. The newer version includes support for wildcard matching, mod_rewrite style configuration, and others new features.  This upgrade is backwards compatible with previous versions and customizations should not be affected. The complete changelog can be found at the Url Rewrite Filter site:http://urlrewritefilter.googlecode.com/svn/trunk/src/doc/manual/3.1/introduction.html#changelog
0 Comments 0 References Permalink