Archive

Archive for the ‘iRow’ Category

Continous Deployment for Apps via testflightapp

January 26, 2012 Leave a comment

The benefits of continous integration are widely known. By extending the ideas of continous integration to the full software lifecycle, continous delivery becomes an inevitable practice. Especially in the context of managing a beta program for mobile devices, to most of which I as a developer have no physical access, the ability to have fully automated deployments is crucial.

Testflightapp.com provides a great service to iOS developers by managing app provisioning and deployments. They do also provide easy to use instrumentation facilities.

Continous deployment with testflightapp.com is a breaze, all you need your build-server to do is interact with a straightforward web-api to upload your ipa packages.
Here’s the script I’m using for RowMotion:

#!/bin/bash
# 

# testflightapp.com tokens
API_TOKEN="YOUR_API_TOKEN"
TEAM_TOKEN="YOUR_TEAM_TOKEN"

PRODUCT_NAME="RowMotion"
ARTEFACTS="$PWD/Artefacts"

SIGNING_IDENTITY="iPhone Distribution"
PROVISIONING_PROFILE="$PWD/id/RowMotionAdHoc.mobileprovision"

# calculated vars
OUT_IPA="${ARTEFACTS}/${PRODUCT_NAME}.ipa"
OUT_DSYM="${ARTEFACTS}/${PRODUCT_NAME}.dSYM.zip"

# kill artefacts directory
rm -rf $ARTEFACTS
mkdir $ARTEFACTS

# compile
echo "##teamcity[compilationStarted compiler='xcodebuild']"
xcodebuild -workspace RowMotion.xcworkspace -scheme RowMotion -sdk iphoneos5.0 -configuration Release build archive
buildSucess=$?

if [[ $buildSucess != 0 ]] ; then
echo "##teamcity[message text='compiler error' status='ERROR']"
echo "##teamcity[compilationFinished compiler='xcodebuild']"
exit $buildSucess
fi

echo "##teamcity[compilationFinished compiler='xcodebuild']"

#ipa
echo "##teamcity[progressMessage 'Creating .ipa for ${PRODUCT_NAME}']"

DATE=$( /bin/date +"%Y-%m-%d" )
ARCHIVE=$( /bin/ls -t "${HOME}/Library/Developer/Xcode/Archives/${DATE}" | /usr/bin/grep xcarchive | /usr/bin/sed -n 1p )
DSYM="${HOME}/Library/Developer/Xcode/Archives/${DATE}/${ARCHIVE}/dSYMs/${PRODUCT_NAME}.app.dSYM"
APP="${HOME}/Library/Developer/Xcode/Archives/${DATE}/${ARCHIVE}/Products/Applications/${PRODUCT_NAME}.app"

/usr/bin/xcrun -sdk iphoneos PackageApplication -v "${APP}" -o "${OUT_IPA}" --sign "${SIGNING_IDENTITY}" --embed "${PROVISIONING_PROFILE}"

#symbols
echo "##teamcity[progressMessage 'Zipping .dSYM for ${PRODUCT_NAME}']"
/usr/bin/zip -r "${OUT_DSYM}" "${DSYM}"

# prepare build notes
NOTES=`hg tip`

#upload
echo "##teamcity[progressMessage 'Uploading ${PRODUCT_NAME} to TestFlight']"

/usr/bin/curl "http://testflightapp.com/api/builds.json" \
-F file=@"${OUT_IPA}" \
-F dsym=@"${OUT_DSYM}" \
-F api_token="${API_TOKEN}" \
-F team_token="${TEAM_TOKEN}" \
-F notes="${NOTES}" \
-F notify="True" \
-F distribution_lists="Private"

Make sure to adapt the script to your requirements. One trick I’m fond of is automatically providing SCM information in the build notes (the step with executing hg tip does just that).
For deployments I’m using two lists, a private one to which all builds will be published, and a public one to which I can selectively deploy. What’s so great about testflightapp.com is that it will automatically send emails to notify my testers about the new build and will then allow me to monitor installs.

GHUnit: Parallel test execution performance implications

October 23, 2009 Leave a comment

As my unit test suite for the iRow project starts to grow, I am running into issues regarding test execution speed. I have maintained a clear distinction between integration and unit tests, so there are no external (possibly slow) resources such as disc i/o (including nib’s) or Sqlite databases involved.

I usually run my unit test suite in the Simulator. Having set GHUnit to automatically run my tests on startup this makes it as simple as hitting cmd-r (Xcode Build&Run). It takes some time to update the app in the Simulator, usually around 1-3 secs but I haven’t found this to be an issue as I usually take the time to do some formatting on the code I am currently working on. GHUnit makes it also very convenient to select a subset of tests  that shall be run and persists these settings between builds, so I don’t have to browse through a hundred of tests if one was failing.

Even though only running a subset of tests, it clearly took to long for me (measured 4-5 secs with stopwatch from app startup). This number also had no coincidence with what GHUnit reported as test execution time (around 0.2 secs). Browsing the GHUnit code to see where the time is wasted, I noticed that GHTestCase default implementation of the

– (BOOL)shouldRunOnMainThread

method , which GHUnit uses to determine if the runner needs to spawn off a child thread for executing this testcase, always returns false. Creating a thread is a costly operation in terms of overhead, the necessary synchronization to retrieve test results another. That’s why I suggest deriving all your testcases from a baseclass (which inherits GHTestCase) to have a central point of control about unit test execution (via shouldRunOnMainThread). This yields another positive effect for integration testing. My integration tests often need to be run on the main thread because they require certain input dispatched to the main threads runLoop only.

This is how my implementation of the shouldRunOnMainThread method looks like:

– (BOOL)shouldRunOnMainThread

{

#ifdef IROW_INTEGRATION_TESTING

return TRUE;

#endif

#ifndef IROW_INTEGRATION_TESTING

return TRUE;

#endif

}

The IROW_INTEGRATION_TESTING symbol is defined in  the integration test project’s prefix header. I think it is a pretty simple but effective solution to control test execution.

Executing all tests on the main thread brought astonishing results: Test time is down to 0.1.secs (measured with stopwatch).  However, it might be interesting to run tests on different threads from time to time to detect possible unintended side effects regarding global state. If tests seem to fail randomly if run multiple times in a row, this is a good indicator for such problems.

Follow

Get every new post delivered to your Inbox.

%d bloggers like this: