Monday, November 12, 2012

Load Testing with JMeter Plugins

JMeter has come a long way since I first used it about 10 years ago.  At that point I mainly used it to test JMS messages.  Now with the ability to record interactions with web pages and the plethora of samplers, timers, processors, etc it can perform some decent load testing of web applications with the help of some plugins.

The Google Code project JMeter Plugins adds a couple thread groups to allow creation of threads at various points during the test.  It can be found at http://code.google.com/p/jmeter-plugins/.With the basic thread groups in JMeter this was not possible or at least not easy.  Other handy features such as a parameterized controller allow you to create modules and re-use them by passing in different parameters to modify their input and behavior.

There are some limitations I've found which are possible to work around, but can be a little frustrating.  For example, the Ultimate Thread Group shows a nice graph of the number of threads and the durations after you plugin the parameters into the thread group setup.  However, if you intend to dynamically fill those values with user defined variables, then you are out of luck and there won't be a graph displayed to show you what you have just setup.  It will still work however and you can just create another thread group and plugin your actual numbers to see the graph in order to verify your assumptions, but obviously it's not as nice as if it were able to resolve the values and show the graph in the first place.  This may not be a limitation of the plugin itself, but rather a trade-off you'll have to make for re-usability sake.  The Stepping Thread Group doesn't appear to support user defined variables in the setup of the thread group.  So with that one you'll get your pretty graph, but you won't have much flexibility when it comes to being able to swap user defined variables for different tests in and out.

There are also various listeners to be able to view response over time, throughput vs threads, etc.  They give you the type of information you would be looking for when load testing.

If you want to be able to simulate a stepped stress test or load test the JMeter Plugins have very useful features to get the test up and running.

Tuesday, February 14, 2012

Mobile Device Detection Without JavaScript

With the explosion of mobile devices in the form of phones, tablets, readers, etc there has been an increasing need to be able to detect if a user is on a mobile device and to format web content appropriately for them.  There are several methods for detection such as using JavaScript or CSS.  The following article does a good job summarizing the various techniques.

http://webdesign.about.com/od/mobile/a/detect-mobile-devices.htm

The one that seemed the most flexible and future proof is a project called wurfl.  Essentially what it is is a user community maintained list of devices and their capabilities that is continuously updated.  The list is in the form of an xml file that is read by the underlying platform at runtime.  The only downside to this file is that it must be downloaded on a regular basis to maintain a listing of the current devices.  However, this is much preferable to having to write out a long list of things in JavaScript in order to do the detection.

The wurfl project is at http://wurfl.sourceforge.net/

It's pretty simple to use as well, for example to detect if a device is a mobile device or not from a JSP you would execute the following code:

    WURFLHolder wurflHolder = (WURFLHolder) getServletConfig().getServletContext()
            .getAttribute("net.sourceforge.wurfl.core.WURFLHolder");

    WURFLManager wurfl = wurflHolder.getWURFLManager();

    Device device = wurfl.getDeviceForRequest(request);

    Boolean result = new Boolean(device.getCapability("is_wireless_device"));

    if ( result ) {
        System.out.println("This is a mobile device!");
    }
    else {
        System.out.println("This is not a mobile device!");
    }


Tuesday, December 20, 2011

Flash Pivot Table for Web Applications

Pivot tables are extremely useful for summarizing and analyzing large amounts of data in different ways.  They are most commonly seen in spreadsheet applications such as Excel, but require you to open a file on your computer or share the file via email or a shared drive in order for someone else to see the same reports.  In researching a way to visualize a large set of data with hierarchies of data while at the same time being able to organize the hierarchies in several different ways, I came across a product from flexmonster.com.  They have built a pivot table component using Flex, but not only is it a fully functional pivot table, it also allows you to generate pivot charts instantly.  You can even change the parameters of the pivot table on the fly and load new data if desired.  The component is highly customizable to be able to fit the look and feel of an existing web application.  The documentation is somewhat sparse, but is complete enough when used in conjunction with their trial or demo code to figure out how to get most of what you need from it.

Thursday, October 13, 2011

Using Kiwi with UI Components on iOS

Trying to get unit testing with Kiwi while being able to use UIKit components was beginning to get frustrating.  The issue is that the tests would crash whenever trying to initialize any UIView components such as UILabel, UITextField, etc.  Well, to some the answer may be obvious, but to relative newbies to iOS like myself it was not.  In order to create instances of UI components you need an actual application running(duh?).  When setting up a unit test bundle in Xcode you can either set it up with or without an app that hosts the tests.  Logic tests are done in test bundles that don't have a host app and application tests are done in test bundles that have a host app.  So for those struggling to create tests that rely on UI components, here's how you do it.


Thanks to Allen Ding the creator of Kiwi for his help and pointing me in the right direction.  Happy testing!

Tuesday, October 11, 2011

Creating a Universal Framework from a 3rd Party Framework Project

One of the things I find irritating about development for iOS is when projects are included directly inside of another project or workspace.  Or even the case where they only provide a static library that you must then separately copy the headers into one of your project folders.  Framework packages seem much cleaner.  So I decided to modify the UISpec base project and create targets to output a universal framework that can be included in any other project.  One drawback of this approach though is that whenever the UISpec projects are updated we either have to figure out which files changed and update our own custom UISpec project or re-create the targets to create the universal framework.  In any case, here is how you create a universal framework from the UISpec project in Xcode 4.2 built for iOS 5.

Edit: The content below was modified to be more generic and calls out UISpec specific steps where necessary.

Cleanup Source Control Files (Optional)
--------------------------------------------------
- (optional) Remove all svn or git directories by running 'find . -name ".svn" -exec rm -rf {} \;' or 'find . -name ".git*" -exec rm -rf {} \;' from the base project directory.

Create New Bundle Target for Framework
---------------------------------------------------
- Open the framework project.
- (UISpec specific) Modify specs/main.m.  Remove "@implementation main" and "@end" from the file.
- Rename the static library target to "<Framework Name> Static Library".  ex. rename "UISpec" target to "UISpec Static Library".  This is to allow creation of a bundle target with the name of the framework so that the framework is built as <Framework Name>.framework.
- (UISpec specific) Go to the project level "Build Settings" and change the compiler to "LLVM GCC 4.2".
- Add a new target of type "Bundle" named <Framework Name>.  ex. "UISpec" This will be the framework target.
- Go to the "Build Settings" for the newly created target.
- Change the Base SDK to "iOS 5.0" or whichever version is appropriate for your framework.
- Change "Build Active Architecture Only" to "No".
- Change "Architectures" to "$(ARCHS_STANDARD_32_BIT)".
- Change "Valid Architectures" to "$(ARCHS_STANDARD_32_BIT)".
- (UISpec specific) Change the "Compiler for C/C++/Objective-C" to "LLVM GCC 4.2"
- Change "Dead Code Stripping" to "No".
- Change "Link With Standard Libraries" to "No".
- Change "Mach-O Type" to "Relocatable Object File".
- Change "Wrapper Extension" to "framework".
- Change "Generate Debugger Symbols" to "No".  (project may not always contain this option)
- Go to the "Build Phases" tab.
- Click "Add Phase" and then select "Add Copy Headers".
- In the "Copy Headers" section add the headers from the project as public/private/project headers as appropriate.  Click the "+" button and search for "*.h".  Select all(or appropriate subset because there may be example or other unnecessary files that don't need to be added) then click "Add".  Move the headers up to the appropriate section.
- In the "Compile Sources" section add the source files.  Click the "+" button and search for "*.m".  Select all(or appropriate subset because there may be some example files in the framework project that are not needed) then click "Add".
- Under the "Link Binary With Libraries" section and "Copy Bundle Resources" section, remove all entries.
- Add any necessary imports required by the framework classes to the <Framework Name>-Prefix.pch file.
- (UISpec specific)Under UISpec/SupportingFiles/UISpec-Prefix.pch remove the Cocoa.h entry and add the following entries:
    #import <Foundation/Foundation.h>
    #import <UIKit/UIKit.h>

Create Target for Universal Framework
-------------------------------------------------
- Create an "Aggregate" target named "<Framework Name> Universal Framework".
- Update the "Build Settings" by changing "SDKROOT" to "iphoneos".
- Click "Add Build Phase" and then "Add Run Script".  Copy the script below into the script area in "Run Script".  Be sure to update the "FMK_NAME" property to the name of your framework.

# Sets the target folders and the final framework product.
FMK_NAME=UISpec
FMK_VERSION=A

# Install dir will be the final output to the framework.
# The following line create it in the root folder of the current project.
INSTALL_DIR=${SRCROOT}/Products/${FMK_NAME}.framework

# Working dir will be deleted after the framework creation.
WRK_DIR=build
DEVICE_DIR=${WRK_DIR}/Release-iphoneos/${FMK_NAME}.framework
SIMULATOR_DIR=${WRK_DIR}/Release-iphonesimulator/${FMK_NAME}.framework

# Building both architectures.
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphoneos
xcodebuild -configuration "Release" -target "${FMK_NAME}" -sdk iphonesimulator

# Cleaning the oldest.
if [ -d "${INSTALL_DIR}" ]
then
rm -rf "${INSTALL_DIR}"
fi

# Creates and renews the final product folder.
mkdir -p "${INSTALL_DIR}"
mkdir -p "${INSTALL_DIR}/Versions"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources"
mkdir -p "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers"

# Creates the internal links.
# It MUST uses relative path, otherwise will not work when the folder is copied/moved.
ln -s "${FMK_VERSION}" "${INSTALL_DIR}/Versions/Current"
ln -s "Versions/Current/Headers" "${INSTALL_DIR}/Headers"
ln -s "Versions/Current/Resources" "${INSTALL_DIR}/Resources"
ln -s "Versions/Current/${FMK_NAME}" "${INSTALL_DIR}/${FMK_NAME}"

# Copies the headers and resources files to the final product folder.
cp -R "${DEVICE_DIR}/Headers/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Headers/"
cp -R "${DEVICE_DIR}/" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/"

# Removes the binary and header from the resources folder.
rm -r "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/Headers" "${INSTALL_DIR}/Versions/${FMK_VERSION}/Resources/${FMK_NAME}"

# Uses the Lipo Tool to merge both binary files (i386 + armv6/armv7) into one Universal final product.
lipo -create "${DEVICE_DIR}/${FMK_NAME}" "${SIMULATOR_DIR}/${FMK_NAME}" -output "${INSTALL_DIR}/Versions/${FMK_VERSION}/${FMK_NAME}"

rm -r "${WRK_DIR}"

Xcode Scheme cleanup
-----------------------------
Since you had renamed the <Framework Name> target and created a new one, you'll probably see <Framework Name> and <Framework Name> 2 as schemes in your project.  Manage your schemes and delete those two schemes.  Then click the "Autocreate" button.  The schemes should now have the updated names.

That's it!  You should be able to build the framework using the new "<Framework Name> Universal Framework" target.  The framework output should be in the base project folder under a directory named "Products".

Wednesday, August 17, 2011

Setting Up WebDAV on Mac OSX Snow Leopard

After trying out several how-to's at various blogs, I finally was able to find one that "almost" worked.  I probably should mention that the first few tutorials I went through would have worked had I not misspelled a directory in the configuration file causing it not to be accessible.  The post below worked except the configuration for the httpd-dav.conf was slightly incorrect.  It shows "Dav On" outside of the <Directory> block, but should be inside the block.  After that everything worked.

http://geekfactor.charrington.com/2009/12/run-a-webdav-server-on-your-mac-to-sync-voodoopad-for-free

The setup that I was trying to achieve is for any user to be able to have read-only access to the WebDAV folders, but requires a valid user(one that is configured in the password file) in order to modify or delete anything.  To accomplish this a couple updates were required in the httpd-dav.conf in /etc/apache2/extras.

1. Add a LimitExcept block in the top level WebDAV directory.
    <LimitExcept GET OPTIONS PROPFIND>
        Require valid-user
    </LimitExcept>

What the above block will do is only allow guests to view the files and directories via a web browser and also connect to the WebDAV directory as a drive/folder.  The LimitExcept block disallows all HTTP command except the ones listed unless the user is valid and authenticated.

2. Add Options for Index

    Options +Indexes
    IndexIgnore ..
    IndexOptions -IconsAreLinks NameWidth=* FancyIndexing SuppressLastModified FoldersFirst
    IndexOrderDefault Ascending Name

The options above allow the files/directories to be seen via a web browser.

Update: WebDAV does not seem to work correctly in Windows 7.  A WebDAV client such as BitKinex is required.