diff --git a/integration-tests/settings.py b/integration-tests/settings.py
new file mode 100644
index 0000000000000000000000000000000000000000..acff00acff90893dfe87a67b05f08e30ab2447da
--- /dev/null
+++ b/integration-tests/settings.py
@@ -0,0 +1,29 @@
+"""
+Setup infrastructure common for all tests.
+"""
+import sys
+import os.path
+import time
+
+# Base URL of the CI server which hosts the artifacts.
+CI_BASE_URL = 'http://bs-ci01.ethz.ch:8090'
+
+reuseRepository = False
+cmd = sys.argv[0]
+if len(sys.argv) > 1:
+    firstArgument = sys.argv[1]
+    if firstArgument == '-r':
+        reuseRepository = True
+    if firstArgument == '-h':
+        print "Usage: %s [-h|-r]\n-h: prints this help\n-r: reuses artifact repository" % os.path.basename(cmd)
+        exit(1)
+
+dirname = os.path.dirname(cmd)
+sys.path.append("%s/source" % dirname)
+sys.path.append("%s/sourceTest" % dirname)
+
+from systemtest.artifactrepository import JenkinsArtifactRepository 
+
+REPOSITORY = JenkinsArtifactRepository(CI_BASE_URL, "%s/targets/artifact-repository" % dirname)
+if not reuseRepository:
+    REPOSITORY.clear()
diff --git a/integration-tests/source/systemtest/artifactrepository.py b/integration-tests/source/systemtest/artifactrepository.py
index 72590b594a7bb7a8bfb4d6a10e0a5c19409bfe2a..1ad924d11d73d9a3c158d5cf98457fc115172032 100644
--- a/integration-tests/source/systemtest/artifactrepository.py
+++ b/integration-tests/source/systemtest/artifactrepository.py
@@ -17,6 +17,7 @@ class ArtifactRepository():
         self.localRepositoryFolder = localRepositoryFolder
         if not os.path.exists(localRepositoryFolder):
             os.makedirs(localRepositoryFolder)
+        print "Artifact repository: %s" % localRepositoryFolder
             
     def clear(self):
         """
@@ -26,6 +27,7 @@ class ArtifactRepository():
             path = "%s/%s" % (self.localRepositoryFolder, f)
             if os.path.isfile(path):
                 os.remove(path)
+        print "Artifact repository cleared."
         
     def getPathToArtifact(self, project, pattern='.*'):
         """
@@ -37,7 +39,7 @@ class ArtifactRepository():
         """
         files = [f for f in os.listdir(self.localRepositoryFolder) if re.match(pattern, f)]
         if len(files) > 1:
-            raise Exception("More than one artifact in '%s' matches the pattern '%': %s" 
+            raise Exception("More than one artifact in '%s' matches the pattern '%s': %s" 
                             % (self.localRepositoryFolder, pattern, files))
         if len(files) == 0:
             f = self.downloadArtifact(project, pattern)
diff --git a/integration-tests/source/systemtest/testcase.py b/integration-tests/source/systemtest/testcase.py
new file mode 100644
index 0000000000000000000000000000000000000000..19194238552806f1819f510060242359e230efcf
--- /dev/null
+++ b/integration-tests/source/systemtest/testcase.py
@@ -0,0 +1,94 @@
+import os
+import os.path
+import shutil
+import subprocess
+import time
+import traceback
+
+import util
+
+INSTALLER_PROJECT = 'gradle-installation'
+OPENBIS_STANDARD_TECHNOLOGIES_PROJECT = 'gradle-openbis-standard-technologies'
+PLAYGROUND = 'targets/playground'
+
+class TestCase():
+    def __init__(self, artifactRepository, filePath):
+        self.artifactRepository = artifactRepository
+        self.project = None
+        fileName = os.path.basename(filePath)
+        self.name = fileName[0:fileName.rfind('.')]
+        self.playgroundFolder = "%s/%s" % (PLAYGROUND, self.name)
+        if os.path.exists(self.playgroundFolder):
+            shutil.rmtree(self.playgroundFolder)
+        os.makedirs(self.playgroundFolder)
+
+    def runTest(self):
+        """
+        Runs this test case. This is a final method. It should not be overwritten.
+        """
+        startTime = time.time()
+        print "\n/''''''''''''''''''' %s started at %s ''''''''''" % (self.name, time.strftime('%Y-%m-%d %H:%M:%S'))
+        try:
+            self.execute()
+            success = True
+        except:
+            traceback.print_exc()
+            success = False
+            raise Exception("%s failed" % self.name)
+        finally:
+            duration = time.time() - startTime
+            if success:
+                print "\...........SUCCESS: %s executed in %d seconds .........." % (self.name, duration)
+            else:
+                print "\............FAILED: %s executed in %d seconds .........." % (self.name, duration)
+        
+    def execute(self):
+        """
+        Executes this test case. This is an abstract method which has to be overwritten in subclasses.
+        """
+        pass
+    
+    def installOpenbis(self, instanceName = 'openbis', technologies = []):
+        """
+        Installs openBIS from the installer. The instanceName specifies the subfolder in the playground folder
+        where the instance will be installed. The technologies are an array of enabled technologies.
+        An instance of OpenbisController is returned.
+        """
+        installerPath = self.artifactRepository.getPathToArtifact(INSTALLER_PROJECT, 'openBIS-installation')
+        installerFileName = os.path.basename(installerPath).split('.')[0]
+        exitValue = subprocess.call(['tar', '-zxf', installerPath, '-C', self.playgroundFolder])
+        if exitValue > 0: raise Exception("Couldn't untar openBIS installer.")
+        consolePropertiesFile = "%s/%s/console.properties" % (self.playgroundFolder, installerFileName)
+        consoleProperties = util.readProperties(consolePropertiesFile)
+        installPath = os.path.abspath("%s/%s" % (self.playgroundFolder, instanceName))
+        consoleProperties['INSTALL_PATH'] = installPath
+        consoleProperties['DSS_ROOT_DIR'] = "%s/data" % installPath
+        for technology in technologies:
+            consoleProperties[technology.upper()] = True
+        util.writeProperties(consolePropertiesFile, consoleProperties)
+        p = subprocess.Popen("%s/%s/run-console.sh" % (self.playgroundFolder, installerFileName), stdin = subprocess.PIPE)
+        p.communicate('admin\nadmin')
+        exitValue = p.wait()
+        if exitValue > 0: raise Exception("Couldn't install openBIS.")
+        return OpenbisController(installPath)
+        
+    def _getAndCreateFolder(self, folderPath):
+        """
+        Creates a folder inside the playground. The argument is a relative path to the playground.
+        The returned path is relative to the working directory.
+        """
+        path = "%s/%s" % (self.playgroundFolder, folderPath)
+        os.makedirs(path)
+        return path
+    
+class OpenbisController():
+    """
+    Class to control AS and DSS of an installed openBIS instance.
+    """
+    def __init__(self, installPath):
+        self.installPath = installPath
+        self.asServicePropertiesFile = "%s/servers/openBIS-server/jetty/etc/service.properties" % installPath
+        self.asProperties = util.readProperties(self.asServicePropertiesFile)
+        self.dssServicePropertiesFile = "%s/servers/datastore_server/etc/service.properties" % installPath
+        self.dssProperties = util.readProperties(self.dssServicePropertiesFile)
+    
diff --git a/integration-tests/source/systemtest/util.py b/integration-tests/source/systemtest/util.py
new file mode 100644
index 0000000000000000000000000000000000000000..18d1acb012de9c744c6d40f8a092b4465a95ba3e
--- /dev/null
+++ b/integration-tests/source/systemtest/util.py
@@ -0,0 +1,22 @@
+def readProperties(propertiesFile):
+    """
+    Reads a Java properties file and returns the key-value pairs as a dictionary.
+    """
+    with open(propertiesFile, "r") as f:
+        result = {}
+        for line in f.readlines():
+            trimmedLine = line.lstrip().rstrip()
+            if len(trimmedLine) > 0 and not trimmedLine.startswith('#'):
+                splittedLine = line.split('=', 1)
+                key = splittedLine[0].lstrip().rstrip()
+                value = splittedLine[1].lstrip().rstrip()
+                result[key] = value
+        return result
+    
+def writeProperties(propertiesFile, dictionary):
+    """
+    Saves the specified dictionary as a Java dictionary file.
+    """
+    with open(propertiesFile, "w") as f:
+        for key, value in dictionary.iteritems():
+            f.write("%s=%s\n" % (key, value))
diff --git a/integration-tests/sourceTest/systemtest/__init__.py b/integration-tests/sourceTest/systemtest/__init__.py
new file mode 100644
index 0000000000000000000000000000000000000000..e69de29bb2d1d6434b8b29ae775ad8c2e48c5391
diff --git a/integration-tests/sourceTest/systemtest/artifactrepository_test.py b/integration-tests/sourceTest/systemtest/artifactrepository_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..7ca09aef3adfb43c5a4d638dd990cb94fc9cc978
--- /dev/null
+++ b/integration-tests/sourceTest/systemtest/artifactrepository_test.py
@@ -0,0 +1,15 @@
+import unittest
+
+from systemtest.artifactrepository import ArtifactRepository
+from testcasewithfiles import TestCaseWithFiles
+
+
+class ArtifactRepositoryTest(TestCaseWithFiles):
+    def setUp(self):
+        self.testRepository = ArtifactRepository(self.createPath("test-repository"))
+    
+    def test_clear(self):
+        self.testRepository.clear()
+        
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/integration-tests/sourceTest/systemtest/testcasewithfiles.py b/integration-tests/sourceTest/systemtest/testcasewithfiles.py
new file mode 100644
index 0000000000000000000000000000000000000000..c75a5d5ca061ea30e27cbfb43ab6950181f785ba
--- /dev/null
+++ b/integration-tests/sourceTest/systemtest/testcasewithfiles.py
@@ -0,0 +1,17 @@
+import os
+import os.path
+import shutil
+import unittest
+
+class TestCaseWithFiles(unittest.TestCase):
+    workspace = 'targets/python-test-workspace'
+    
+    def setUp(self):
+        shutil.rmtree("%s/%s" % (self.workspace, self.__class__.__name__))
+    
+    def createPath(self, relativePath):
+        path = "%s/%s/%s" % (self.workspace, self.__class__.__name__, relativePath)
+        parent = os.path.dirname(path)
+        if not os.path.exists(parent):
+            os.makedirs(parent)
+        return path
diff --git a/integration-tests/sourceTest/systemtest/util_test.py b/integration-tests/sourceTest/systemtest/util_test.py
new file mode 100644
index 0000000000000000000000000000000000000000..43b9d248ab455168b44d1e9cac9b39cce0bc508c
--- /dev/null
+++ b/integration-tests/sourceTest/systemtest/util_test.py
@@ -0,0 +1,31 @@
+import unittest
+
+import systemtest.util as util
+from testcasewithfiles import TestCaseWithFiles
+
+
+class UtilTest(TestCaseWithFiles):
+    def test_readProperties(self):
+        example = self.createPath("my.properties")
+        with open(example, "w") as out:
+            out.write("# a comment\n\n")
+            out.write("      \n")
+            out.write(" alpha = beta  \n")
+            out.write("  non=\n")
+            
+        keyValuePairs = util.readProperties(example)
+        
+        self.assertEqual('beta', keyValuePairs['alpha'])
+        self.assertEqual('', keyValuePairs['non'])
+        self.assertEqual(2, len(keyValuePairs))
+        
+    def test_writeProperties(self):
+        example = self.createPath("my.props")
+        
+        util.writeProperties(example, {'alpha': 4711, 'beta': 'hello'})
+        
+        with open(example, "r") as f:
+            self.assertEqual(['alpha=4711\n', 'beta=hello\n'], sorted(f.readlines()))
+        
+if __name__ == '__main__':
+    unittest.main()
\ No newline at end of file
diff --git a/integration-tests/test.py b/integration-tests/test.py
new file mode 100755
index 0000000000000000000000000000000000000000..e16000437bebdb5f5f1ebacbd8d0be977d453944
--- /dev/null
+++ b/integration-tests/test.py
@@ -0,0 +1,36 @@
+#!/usr/bin/python
+"""
+Runs all test cases in alphabetical order. A test case is a file of type '.py' and starts with 'test-'.
+Exit value will 0 if all test cases succeeded otherwise it will be 1.
+"""
+import os
+import os.path
+import sys
+import time
+
+import settings
+
+startTime = time.time() 
+numberOfTestCases = 0
+numberOfFailedTestCases = 0
+for f in sorted(os.listdir(os.path.dirname(__file__))):
+    splittedFileName = f.rsplit('.', 1)
+    if len(splittedFileName) > 1:
+        moduleName = splittedFileName[0]
+        fileType = splittedFileName[1]
+        if moduleName.startswith('test_') and fileType == 'py':
+            numberOfTestCases += 1
+            try:
+                __import__(moduleName)
+            except:
+                numberOfFailedTestCases += 1
+print '====================================='
+print "%d test cases executed in %d seconds" % (numberOfTestCases, time.time() - startTime)
+if numberOfFailedTestCases == 0:
+    print "no test case failed"
+    exit(0)
+if numberOfFailedTestCases == 1:
+    print "1 test case failed"
+else:
+    print "%d test cases failed" % numberOfFailedTestCases
+exit(1)
diff --git a/integration-tests/test_screening.py b/integration-tests/test_screening.py
new file mode 100755
index 0000000000000000000000000000000000000000..0640a034f59a3687a6e8bd208f3449ea0be24268
--- /dev/null
+++ b/integration-tests/test_screening.py
@@ -0,0 +1,11 @@
+#!/usr/bin/python
+import settings
+import systemtest.testcase
+
+class TestCase(systemtest.testcase.TestCase):
+    def execute(self):
+        openbisController = self.installOpenbis(technologies = ['screening'])
+        print openbisController.asProperties
+        
+TestCase(settings.REPOSITORY, __file__).runTest()
+
diff --git a/integration-tests/test_yeastx.py b/integration-tests/test_yeastx.py
new file mode 100755
index 0000000000000000000000000000000000000000..592c6c9a2401113bafe38fa5e664da3f78b9d370
--- /dev/null
+++ b/integration-tests/test_yeastx.py
@@ -0,0 +1,10 @@
+#!/usr/bin/python
+import settings
+import systemtest.testcase
+
+class TestCase(systemtest.testcase.TestCase):
+    def execute(self):
+        self.installOpenbis()
+        
+TestCase(settings.REPOSITORY, __file__).runTest()
+