runnertest.py 25.4 KB
Newer Older
1
# -*- coding: utf-8 -*-
Marco Mariani's avatar
Marco Mariani committed
2
# vim: set et sts=2:
Marco Mariani's avatar
Marco Mariani committed
3
# pylint: disable-msg=W0311,C0301,C0103,C0111,R0904
Marco Mariani's avatar
Marco Mariani committed
4

5 6 7 8 9 10 11 12
#############################################
# !!! Attention !!!
# You now have to comment the last line
# in __init__py, wich starts the functiun
# run() in order to start the tests,
# or it will NOT work
#############################################

13
import argparse
14
import ConfigParser
Marco Mariani's avatar
Marco Mariani committed
15
import datetime
Marco Mariani's avatar
Marco Mariani committed
16
import hashlib
17
import json
Marco Mariani's avatar
Marco Mariani committed
18 19
import os
import shutil
20
import sup_process
21
import time
Marco Mariani's avatar
Marco Mariani committed
22 23
import unittest

Nicolas Wavrant's avatar
Nicolas Wavrant committed
24
from slapos.runner.utils import (getProfilePath,
25
                                 getSession, isInstanceRunning,
26
                                 isSoftwareRunning, startProxy,
27
                                 isSoftwareReleaseReady,
28
                                 runSlapgridUntilSuccess, runInstanceWithLock,
29
                                 getBuildAndRunParams, saveBuildAndRunParams)
Marco Mariani's avatar
Marco Mariani committed
30
from slapos.runner import views
Alain Takoudjou's avatar
Alain Takoudjou committed
31
import slapos.slap
32
from slapos.htpasswd import  HtpasswdFile
Marco Mariani's avatar
Marco Mariani committed
33

Marco Mariani's avatar
Marco Mariani committed
34

Marco Mariani's avatar
Marco Mariani committed
35 36 37 38
#Helpers
def loadJson(response):
  return json.loads(response.data)

39 40

class Config:
Marco Mariani's avatar
Marco Mariani committed
41 42 43 44 45 46
  def __init__(self):
    self.runner_workdir = None
    self.software_root = None
    self.instance_root = None
    self.configuration_file_path = None

47 48 49 50
  def setConfig(self):
    """
    Set options given by parameters.
    """
51
    self.configuration_file_path = os.path.abspath(os.environ.get('RUNNER_CONFIG'))
52 53 54 55 56 57 58

    # Load configuration file
    configuration_parser = ConfigParser.SafeConfigParser()
    configuration_parser.read(self.configuration_file_path)
    # Merges the arguments and configuration

    for section in ("slaprunner", "slapos", "slapproxy", "slapformat",
59
                    "sshkeys_authority", "gitclient"):
60 61 62 63 64
      configuration_dict = dict(configuration_parser.items(section))
      for key in configuration_dict:
        if not getattr(self, key, None):
          setattr(self, key, configuration_dict[key])

Marco Mariani's avatar
Marco Mariani committed
65

66 67 68 69 70 71 72
class SlaprunnerTestCase(unittest.TestCase):

  def setUp(self):
    """Initialize slapos webrunner here"""
    views.app.config['TESTING'] = True
    self.users = ["slapuser", "slappwd", "slaprunner@nexedi.com", "SlapOS web runner"]
    self.updateUser = ["newslapuser", "newslappwd", "slaprunner@nexedi.com", "SlapOS web runner"]
73
    self.repo = 'http://git.erp5.org/repos/slapos.git'
Marco Mariani's avatar
Marco Mariani committed
74 75
    self.software = "workspace/slapos/software/"  # relative directory fo SR
    self.project = 'slapos'  # Default project name
Alain Takoudjou's avatar
Alain Takoudjou committed
76 77
    self.template = 'template.cfg'
    self.partitionPrefix = 'slappart'
78 79 80 81
    #create slaprunner configuration
    config = Config()
    config.setConfig()
    workdir = os.path.join(config.runner_workdir, 'project')
82
    software_link = os.path.join(config.runner_workdir, 'softwareLink')
83 84
    views.app.config.update(**config.__dict__)
    #update or create all runner base directory to test_dir
85

86 87
    if not os.path.exists(workdir):
      os.mkdir(workdir)
Alain Takoudjou's avatar
Alain Takoudjou committed
88 89
    if not os.path.exists(software_link):
      os.mkdir(software_link)
90 91 92
    views.app.config.update(
      software_log=config.software_root.rstrip('/') + '.log',
      instance_log=config.instance_root.rstrip('/') + '.log',
Marco Mariani's avatar
Marco Mariani committed
93
      workspace=workdir,
94
      software_link=software_link,
95 96 97
      instance_profile='instance.cfg',
      software_profile='software.cfg',
      SECRET_KEY="123456",
Marco Mariani's avatar
Marco Mariani committed
98
      PERMANENT_SESSION_LIFETIME=datetime.timedelta(days=31),
99
      instance_monitoring_url = 'https://[' + config.ipv6_address + ']:9684',
100 101 102 103
    )
    self.app = views.app.test_client()
    self.app.config = views.app.config
    #Create password recover code
104 105 106
    parser = ConfigParser.ConfigParser()
    parser.read(self.app.config['knowledge0_cfg'])
    self.rcode = parser.get('public', 'recovery-code')
107 108
    #Create config.json
    json_file = os.path.join(views.app.config['etc_dir'], 'config.json')
109
    if not os.path.exists(json_file):
110 111 112 113 114 115 116
      params = {
        'run_instance' : True,
        'run_software' : True,
        'max_run_instance' : 3,
        'max_run_software' : 2
      }
      open(json_file, "w").write(json.dumps(params))
117 118 119 120 121

  def tearDown(self):
    """Remove all test data"""
    project = os.path.join(self.app.config['etc_dir'], '.project')
    users = os.path.join(self.app.config['etc_dir'], '.users')
Alain Takoudjou's avatar
Alain Takoudjou committed
122

123 124 125 126
    #reset tested parameters
    self.updateConfigParameter('autorun', False)
    self.updateConfigParameter('auto_deploy', True)

127 128 129 130 131 132 133 134 135 136
    if os.path.exists(users):
      os.unlink(users)
    if os.path.exists(project):
      os.unlink(project)
    if os.path.exists(self.app.config['workspace']):
      shutil.rmtree(self.app.config['workspace'])
    if os.path.exists(self.app.config['software_root']):
      shutil.rmtree(self.app.config['software_root'])
    if os.path.exists(self.app.config['instance_root']):
      shutil.rmtree(self.app.config['instance_root'])
Alain Takoudjou's avatar
Alain Takoudjou committed
137 138 139
    if os.path.exists(self.app.config['software_link']):
      shutil.rmtree(self.app.config['software_link'])
    #Stop process
140 141 142
    sup_process.killRunningProcess(self.app.config, 'slapproxy')
    sup_process.killRunningProcess(self.app.config, 'slapgrid-cp')
    sup_process.killRunningProcess(self.app.config, 'slapgrid-sr')
143

144 145 146 147 148 149 150 151 152
  def updateConfigParameter(self, parameter, value):
    config_parser = ConfigParser.SafeConfigParser()
    config_parser.read(os.getenv('RUNNER_CONFIG'))
    for section in config_parser.sections():
      if config_parser.has_option(section, parameter):
        config_parser.set(section, parameter, str(value))
    with open(os.getenv('RUNNER_CONFIG'), 'wb') as configfile:
      config_parser.write(configfile)

153
  def configAccount(self, username, password, email, name, rcode):
Marco Mariani's avatar
Marco Mariani committed
154
    """Helper for configAccount"""
Marco Mariani's avatar
Marco Mariani committed
155 156 157 158 159 160 161 162 163
    return self.app.post('/configAccount',
                         data=dict(
                           username=username,
                           password=password,
                           email=email,
                           name=name,
                           rcode=rcode
                         ),
                         follow_redirects=True)
164 165 166

  def setAccount(self):
    """Initialize user account and log user in"""
Marco Mariani's avatar
Marco Mariani committed
167
    response = loadJson(self.configAccount(self.users[0], self.users[1],
168 169 170 171 172
                  self.users[2], self.users[3], self.rcode))
    self.assertEqual(response['result'], "")

  def updateAccount(self, newaccount, rcode):
    """Helper for update user account data"""
Marco Mariani's avatar
Marco Mariani committed
173 174 175 176 177 178 179 180 181
    return self.app.post('/updateAccount',
                         data=dict(
                           username=newaccount[0],
                           password=newaccount[1],
                           email=newaccount[2],
                           name=newaccount[3],
                           rcode=rcode
                         ),
                         follow_redirects=True)
182

183 184 185
  def getCurrentSR(self):
   return getProfilePath(self.app.config['etc_dir'],
                              self.app.config['software_profile'])
186 187

  def proxyStatus(self, status=True, sleep_time=0):
188
    """Helper for testslapproxy status"""
189
    proxy = sup_process.isRunning(self.app.config, 'slapproxy')
190 191
    if proxy != status and sleep_time != 0:
      time.sleep(sleep_time)
192
      proxy = sup_process.isRunning(self.app.config, 'slapproxy')
193 194
    self.assertEqual(proxy, status)

Alain Takoudjou's avatar
Alain Takoudjou committed
195
  def setupProjectFolder(self, withSoftware=False):
Marco Mariani's avatar
Marco Mariani committed
196
    """Helper to create a project folder as for slapos.git"""
Alain Takoudjou's avatar
Alain Takoudjou committed
197 198 199 200 201 202 203 204 205 206 207
    base = os.path.join(self.app.config['workspace'], 'slapos')
    software = os.path.join(base, 'software')
    os.mkdir(base)
    os.mkdir(software)
    if withSoftware:
      testSoftware = os.path.join(software, 'slaprunner-test')
      sr = "[buildout]\n\n"
      sr += "parts = command\n\nunzip = true\nnetworkcache-section = networkcache\n\n"
      sr += "find-links += http://www.nexedi.org/static/packages/source/slapos.buildout/\n\n"
      sr += "[networkcache]\ndownload-cache-url = http://www.shacache.org/shacache"
      sr += "\ndownload-dir-url = http://www.shacache.org/shadir\n\n"
208
      sr += "[command]\nrecipe = zc.recipe.egg\neggs = plone.recipe.command\n  zc.buildout\n\n"
Alain Takoudjou's avatar
Alain Takoudjou committed
209 210 211 212 213
      os.mkdir(testSoftware)
      open(os.path.join(testSoftware, self.app.config['software_profile']),
                          'w').write(sr)

  def setupSoftwareFolder(self):
Marco Mariani's avatar
Marco Mariani committed
214
    """Helper to setup compiled software release dir"""
Alain Takoudjou's avatar
Alain Takoudjou committed
215 216
    self.setupProjectFolder(withSoftware=True)
    md5 = hashlib.md5(os.path.join(self.app.config['workspace'],
Marco Mariani's avatar
Marco Mariani committed
217 218 219
                                   "slapos/software/slaprunner-test",
                                   self.app.config['software_profile'])
                      ).hexdigest()
Alain Takoudjou's avatar
Alain Takoudjou committed
220 221 222 223 224
    base = os.path.join(self.app.config['software_root'], md5)
    template = os.path.join(base, self.template)
    content = "[buildout]\n"
    content += "parts = \n  create-file\n\n"
    content += "eggs-directory = %s\n" % os.path.join(base, 'eggs')
Marco Mariani's avatar
Marco Mariani committed
225
    content += "develop-eggs-directory = %s\n\n" % os.path.join(base, 'develop-eggs')
Alain Takoudjou's avatar
Alain Takoudjou committed
226 227 228 229 230 231 232
    content += "[create-file]\nrecipe = plone.recipe.command\n"
    content += "filename = ${buildout:directory}/etc\n"
    content += "command = mkdir ${:filename} && echo 'simple file' > ${:filename}/testfile\n"
    os.mkdir(self.app.config['software_root'])
    os.mkdir(base)
    open(template, "w").write(content)

233 234
  def stopSlapproxy(self):
    """Kill slapproxy process"""
235
    pass
Alain Takoudjou's avatar
Alain Takoudjou committed
236

237 238 239 240
  def test_configAccount(self):
    """For the first lauch of slaprunner user need do create first account"""
    result = self.configAccount(self.users[0], self.users[1], self.users[2],
                  self.users[3], self.rcode)
Marco Mariani's avatar
Marco Mariani committed
241
    response = loadJson(result)
242 243 244 245 246
    self.assertEqual(response['code'], 1)
    account = getSession(self.app.config)
    self.assertEqual(account, self.users)

  def test_updateAccount(self):
Marco Mariani's avatar
Marco Mariani committed
247
    """test Update accound, this needs the user to log in"""
248
    self.setAccount()
249 250
    htpasswd = os.path.join(self.app.config['etc_dir'], '.htpasswd')
    assert self.users[0] in open(htpasswd).read()
Marco Mariani's avatar
Marco Mariani committed
251
    response = loadJson(self.updateAccount(self.updateUser, self.rcode))
252
    self.assertEqual(response['code'], 1)
253 254 255
    encode = HtpasswdFile(htpasswd, False)
    encode.update(self.updateUser[0], self.updateUser[1])
    assert self.updateUser[0] in open(htpasswd).read()
256

257
  def test_startStopProxy(self):
258 259 260 261 262 263 264 265
    """Test slapproxy"""
    startProxy(self.app.config)
    self.proxyStatus(True)

  def test_cloneProject(self):
    """Start scenario 1 for deploying SR: Clone a project from git repository"""
    self.setAccount()
    folder = 'workspace/' + self.project
Marco Mariani's avatar
Marco Mariani committed
266 267 268 269 270 271
    data = {
      'repo': self.repo,
      'user': 'Slaprunner test',
      'email': 'slaprunner@nexedi.com',
      'name': folder
    }
Marco Mariani's avatar
Marco Mariani committed
272
    response = loadJson(self.app.post('/cloneRepository', data=data,
273 274
                    follow_redirects=True))
    self.assertEqual(response['result'], "")
Marco Mariani's avatar
Marco Mariani committed
275
    # Get realpath of create project
276
    path_data = dict(file=folder)
Marco Mariani's avatar
Marco Mariani committed
277
    response = loadJson(self.app.post('/getPath', data=path_data,
278 279 280 281
                    follow_redirects=True))
    self.assertEqual(response['code'], 1)
    realFolder = response['result'].split('#')[0]
    #Check git configuration
282
    config = open(os.path.join(realFolder, '.git/config')).read()
283
    assert "slaprunner@nexedi.com" in config and "Slaprunner test" in config
Marco Mariani's avatar
Marco Mariani committed
284 285

    # Checkout to slaprunner branch, this supposes that branch slaprunner exit
Marco Mariani's avatar
Marco Mariani committed
286 287 288 289 290 291 292
    response = loadJson(self.app.post('/newBranch',
                                      data=dict(
                                        project=folder,
                                        create='0',
                                        name='slaprunner'
                                      ),
                                      follow_redirects=True))
293 294 295 296
    self.assertEqual(response['result'], "")

  def test_createSR(self):
    """Scenario 2: Create a new software release"""
Alain Takoudjou's avatar
Alain Takoudjou committed
297 298 299
    self.setAccount()
    #setup project directory
    self.setupProjectFolder()
300
    newSoftware = os.path.join(self.software, 'slaprunner-test')
Marco Mariani's avatar
Marco Mariani committed
301
    response = loadJson(self.app.post('/createSoftware',
Marco Mariani's avatar
Marco Mariani committed
302 303
                                      data=dict(folder=newSoftware),
                                      follow_redirects=True))
304 305 306 307 308 309 310
    self.assertEqual(response['result'], "")
    currentSR = self.getCurrentSR()
    assert newSoftware in currentSR

  def test_openSR(self):
    """Scenario 3: Open software release"""
    self.test_cloneProject()
Marco Mariani's avatar
Marco Mariani committed
311
    software = os.path.join(self.software, 'drupal')  # Drupal SR must exist in SR folder
Marco Mariani's avatar
Marco Mariani committed
312
    response = loadJson(self.app.post('/setCurrentProject',
Marco Mariani's avatar
Marco Mariani committed
313 314
                                      data=dict(path=software),
                                      follow_redirects=True))
315 316 317 318 319
    self.assertEqual(response['result'], "")
    currentSR = self.getCurrentSR()
    assert software in currentSR
    self.assertFalse(isInstanceRunning(self.app.config))
    self.assertFalse(isSoftwareRunning(self.app.config))
Marco Mariani's avatar
Marco Mariani committed
320 321 322

    # Slapproxy process is supposed to be started
    # newSoftware = os.path.join(self.software, 'slaprunner-test')
Alain Takoudjou's avatar
Alain Takoudjou committed
323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339
    self.proxyStatus(True)
    self.stopSlapproxy()

  def test_runSoftware(self):
    """Scenario 4: CReate empty SR and save software.cfg file
      then run slapgrid-sr
    """
    #Call config account
    #call create software Release
    self.test_createSR()
    newSoftware = self.getCurrentSR()
    softwareRelease = "[buildout]\n\nparts =\n  test-application\n"
    softwareRelease += "#Test download git web repos éè@: utf-8 caracters\n"
    softwareRelease += "[test-application]\nrecipe = hexagonit.recipe.download\n"
    softwareRelease += "url = http://git.erp5.org/gitweb/slapos.git\n"
    softwareRelease += "filename = slapos.git\n"
    softwareRelease += "download-only = true\n"
Alain Takoudjou's avatar
Alain Takoudjou committed
340
    response = loadJson(self.app.post('/saveFileContent',
Marco Mariani's avatar
Marco Mariani committed
341 342 343
                                      data=dict(file=newSoftware,
                                                content=softwareRelease),
                                      follow_redirects=True))
Alain Takoudjou's avatar
Alain Takoudjou committed
344
    self.assertEqual(response['result'], "")
Marco Mariani's avatar
Marco Mariani committed
345 346 347

    # Compile software and wait until slapgrid ends
    # this is supposed to use current SR
348 349 350
    while self.app.get('/isSRReady').data == "2":
      time.sleep(2)
    self.assertEqual(self.app.get('/isSRReady').data, "1")
Alain Takoudjou's avatar
Alain Takoudjou committed
351 352
    self.assertTrue(os.path.exists(self.app.config['software_root']))
    self.assertTrue(os.path.exists(self.app.config['software_log']))
353
    assert "test-application" in open(self.app.config['software_log']).read()
Alain Takoudjou's avatar
Alain Takoudjou committed
354 355 356 357 358 359 360 361 362 363 364 365 366 367
    sr_dir = os.listdir(self.app.config['software_root'])
    self.assertEqual(len(sr_dir), 1)
    createdFile = os.path.join(self.app.config['software_root'], sr_dir[0],
                              'parts', 'test-application', 'slapos.git')
    self.assertTrue(os.path.exists(createdFile))
    self.proxyStatus(True)
    self.stopSlapproxy()

  def test_updateInstanceParameter(self):
    """Scenarion 5: Update parameters of current sofware profile"""
    self.setAccount()
    self.setupSoftwareFolder()
    #Set current projet and run Slapgrid-cp
    software = os.path.join(self.software, 'slaprunner-test')
Alain Takoudjou's avatar
Alain Takoudjou committed
368
    response = loadJson(self.app.post('/setCurrentProject',
Marco Mariani's avatar
Marco Mariani committed
369 370
                                      data=dict(path=software),
                                      follow_redirects=True))
Alain Takoudjou's avatar
Alain Takoudjou committed
371 372 373 374 375 376 377 378
    self.assertEqual(response['result'], "")
    self.proxyStatus(True)
    #Send paramters for the instance
    parameterDict = dict(appname='slaprunnerTest', cacountry='France')
    parameterXml = '<?xml version="1.0" encoding="utf-8"?>\n<instance>'
    parameterXml += '<parameter id="appname">slaprunnerTest</parameter>\n'
    parameterXml += '<parameter id="cacountry">France</parameter>\n</instance>'
    software_type = 'production'
Alain Takoudjou's avatar
Alain Takoudjou committed
379
    response = loadJson(self.app.post('/saveParameterXml',
Marco Mariani's avatar
Marco Mariani committed
380 381 382
                                      data=dict(parameter=parameterXml,
                                                software_type=software_type),
                                      follow_redirects=True))
Alain Takoudjou's avatar
Alain Takoudjou committed
383 384 385 386 387 388 389 390
    self.assertEqual(response['result'], "")
    slap = slapos.slap.slap()
    slap.initializeConnection(self.app.config['master_url'])
    computer = slap.registerComputer(self.app.config['computer_id'])
    partitionList = computer.getComputerPartitionList()
    self.assertNotEqual(partitionList, [])
    #Assume that the requested partition is partition 0
    slapParameterDict = partitionList[0].getInstanceParameterDict()
Marco Mariani's avatar
Marco Mariani committed
391 392
    self.assertTrue('appname' in slapParameterDict)
    self.assertTrue('cacountry' in slapParameterDict)
Alain Takoudjou's avatar
Alain Takoudjou committed
393 394 395 396 397
    self.assertEqual(slapParameterDict['appname'], 'slaprunnerTest')
    self.assertEqual(slapParameterDict['cacountry'], 'France')
    self.assertEqual(slapParameterDict['slap_software_type'], 'production')

    #test getParameterXml for webrunner UI
Alain Takoudjou's avatar
Alain Takoudjou committed
398
    response = loadJson(self.app.get('/getParameterXml/xml'))
Alain Takoudjou's avatar
Alain Takoudjou committed
399
    self.assertEqual(parameterXml, response['result'])
Alain Takoudjou's avatar
Alain Takoudjou committed
400
    response = loadJson(self.app.get('/getParameterXml/dict'))
Alain Takoudjou's avatar
Alain Takoudjou committed
401 402 403 404 405 406 407
    self.assertEqual(parameterDict, response['result']['instance'])
    self.stopSlapproxy()

  def test_requestInstance(self):
    """Scenarion 6: request software instance"""
    self.test_updateInstanceParameter()
    #run Software profile
Alain Takoudjou's avatar
Alain Takoudjou committed
408
    response = loadJson(self.app.post('/runSoftwareProfile',
Marco Mariani's avatar
Marco Mariani committed
409 410
                                      data=dict(),
                                      follow_redirects=True))
411 412 413
    while self.app.get('/isSRReady').data == "2":
      time.sleep(2)
    self.assertEqual(self.app.get('/isSRReady').data, "1")
Alain Takoudjou's avatar
Alain Takoudjou committed
414
    #run instance profile
Alain Takoudjou's avatar
Alain Takoudjou committed
415
    response = loadJson(self.app.post('/runInstanceProfile',
Marco Mariani's avatar
Marco Mariani committed
416 417
                                      data=dict(),
                                      follow_redirects=True))
Alain Takoudjou's avatar
Alain Takoudjou committed
418
    self.assertTrue(response['result'])
419 420
    # lets some time to the Instance to be deployed
    time.sleep(5)
Alain Takoudjou's avatar
Alain Takoudjou committed
421
    #Check that all partitions has been created
422
    assert "create-file" in open(self.app.config['instance_log']).read()
Alain Takoudjou's avatar
Alain Takoudjou committed
423 424 425 426 427 428 429 430 431 432 433 434
    instanceDir = os.listdir(self.app.config['instance_root'])
    for num in range(int(self.app.config['partition_amount'])):
      partition = os.path.join(self.app.config['instance_root'],
                    self.partitionPrefix + str(num))
      self.assertTrue(os.path.exists(partition))

    #Go to partition 0
    instancePath = os.path.join(self.app.config['instance_root'],
                         self.partitionPrefix + '0')
    createdFile = os.path.join(instancePath, 'etc', 'testfile')
    self.assertTrue(os.path.exists(createdFile))
    assert 'simple file' in open(createdFile).read()
435 436
    self.proxyStatus(True)
    self.stopSlapproxy()
437

438 439 440 441
  def test_safeAutoDeploy(self):
    """Scenario 7: isSRReady won't overwrite the existing
    Sofware Instance if it has been deployed yet"""
    # Test that SR won't be deployed with auto_deploy=False
442 443
    self.updateConfigParameter('auto_deploy', False)
    self.updateConfigParameter('autorun', False)
444 445
    project = open(os.path.join(self.app.config['etc_dir'],
                  '.project'), "w")
446
    project.write(self.software + 'slaprunner-test')
447 448 449 450
    project.close()
    response = isSoftwareReleaseReady(self.app.config)
    self.assertEqual(response, "0")
    # Test if auto_deploy parameter starts the deployment of SR
451
    self.updateConfigParameter('auto_deploy', True)
452 453 454 455 456
    self.setupSoftwareFolder()
    response = isSoftwareReleaseReady(self.app.config)
    self.assertEqual(response, "2")
    # Test that the new call to isSoftwareReleaseReady
    # doesn't overwrite the previous installed one
457
    sup_process.killRunningProcess(self.app.config, 'slapgrid-sr')
458
    completed_path = os.path.join(self.app.config['runner_workdir'],
459
        'softwareLink', 'slaprunner-test', '.completed')
460 461 462 463 464 465 466
    completed_text = ".completed file: test"
    completed = open(completed_path, "w")
    completed.write(completed_text)
    completed.close()
    response = isSoftwareReleaseReady(self.app.config)
    self.assertEqual(response, "1")
    assert completed_text in open(completed_path).read()
Marco Mariani's avatar
Marco Mariani committed
467

468 469 470 471 472 473 474
  def test_maximumRunOfSlapgrid(self):
    """Scenario 8: runSlapgridUntilSucces run until a defined maximum of time
    slapgrid-sr and slapgrid-cp if it fails. It can also run only one or both
    of them if it is defined so
    We directly calls runSlapgridUntilSuccess, because we want
    to test the return code of the function"""
    # Installs a wrong buildout which will fail
475 476
    MAX_RUN_SOFTWARE = getBuildAndRunParams(self.app.config)['max_run_software']
    MAX_RUN_INSTANCE = getBuildAndRunParams(self.app.config)['max_run_instance']
477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519
    self.test_createSR()
    newSoftware = self.getCurrentSR()
    softwareRelease = "[buildout]\n\nparts =\n  test-application\n"
    softwareRelease += "#Test download git web repos éè@: utf-8 caracters\n"
    softwareRelease += "[test-application]\nrecipe = slapos.cookbook:mkdirectory\n"
    softwareRelease += "test = /root/test\n"
    response = loadJson(self.app.post('/saveFileContent',
                                      data=dict(file=newSoftware,
                                                content=softwareRelease),
                                      follow_redirects=True))
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, MAX_RUN_SOFTWARE)
    # clean folders for other tests
    workdir = os.path.join(self.app.config['runner_workdir'], 'project')
    git_repo = os.path.join(workdir, 'slapos')
    if os.path.exists(git_repo):
      shutil.rmtree(git_repo)
    # Installs a software which deploys, but fails while instanciating
    # preparation
    base = os.path.join(self.app.config['workspace'], 'slapos')
    software = os.path.join(base, 'software')
    testSoftware = os.path.join(software, 'slaprunner-test')
    if not os.path.exists(testSoftware):
      os.makedirs(testSoftware)
    software_cfg = os.path.join(testSoftware, 'software.cfg')
    instance_cfg = os.path.join(testSoftware, 'instance.cfg')
    # software.cfg
    softwareRelease = "[buildout]\n\nparts =\n  failing-template\n\n"
    softwareRelease += "[failing-template]\nrecipe = hexagonit.recipe.download\n"
    softwareRelease += "url = %s\n" % (instance_cfg)
    softwareRelease += "destination = ${buildout:directory}\n"
    softwareRelease += "download-only = true\n"
    open(software_cfg, 'w+').write(softwareRelease)
    # instance.cfg
    content = "[buildout]\n\nparts =\n fail\n"
    content += "[fail]\nrecipe=plone.recipe.command\n"
    content += "command = exit 1"
    open(instance_cfg, 'w+').write(content)
    project = open(os.path.join(self.app.config['etc_dir'],
                  '.project'), "w")
    project.write(self.software + 'slaprunner-test')
    project.close()
    # Build and Run
520
    parameters = getBuildAndRunParams(self.app.config)
521
    parameters['run_instance'] = False
522
    saveBuildAndRunParams(self.app.config, parameters)
523 524 525
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, 1)
    parameters['run_instance'] = True
526
    saveBuildAndRunParams(self.app.config, parameters)
527 528 529
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, (1, MAX_RUN_INSTANCE))

530 531 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575
  def test_slaveInstanceDeployment(self):
    """
    In order to test both slapproxy and core features of
    slaprunner, will install special Software Release
    into the current webrunner and fetch its instance
    parameters once deployed.
    """
    # XXX: This test should NOT be a unit test but should be run
    # by a Test Agent running against a slapproxy.

    # Deploy "test-slave-instance-deployment" Software Release
    self.test_cloneProject()
    software = os.path.join(self.software, 'test-slave-instance-deployment')

    # Checkout to master branch
    response = loadJson(self.app.post('/newBranch',
                                      data=dict(
                                        project=self.software,
                                        create='0',
                                        name='master'
                                      ),
                                      follow_redirects=True)).get(u'code')
    self.assertEqual(response, 1)
    response = loadJson(self.app.post('/setCurrentProject',
                                      data=dict(path=software),
                                      follow_redirects=True)).get(u'code')
    self.assertEqual(response, 1)

    response = loadJson(self.app.post('/saveParameterXml',
                                      data=dict(parameter='<?xml version="1.0" encoding="utf-8"?>\n<instance/>',
                                                software_type='default'),
                                      follow_redirects=True))

    while self.app.get('/isSRReady').data == "2":
      time.sleep(2)
    self.assertEqual(self.app.get('/isSRReady').data, "1")

    # Run instance deployment 3 times
    runInstanceWithLock(self.app.config)
    runInstanceWithLock(self.app.config)
    result = runInstanceWithLock(self.app.config)
    # result is True if returncode is 0 (i.e "deployed and promise passed")
    self.assertTrue(result)

    self.proxyStatus(True)
    self.stopSlapproxy()
576

577 578 579 580 581
  def test_dynamicParametersReading(self):
    """Test if the value of a parameter can change in the flask application
    only by changing the value of slapos.cfg config file. This can happen when
    slapgrid processes the webrunner's partition.
    """
582
    config_file = os.path.join(self.app.config['etc_dir'], 'slapos-test.cfg')
583 584 585 586 587 588 589 590 591 592 593
    runner_config_old = os.environ['RUNNER_CONFIG']
    os.environ['RUNNER_CONFIG'] = config_file
    open(config_file, 'w').write("[section]\nvar=value")
    config = self.app.config
    self.assertEqual(config['var'], "value")
    open(config_file, 'w').write("[section]\nvar=value_changed")
    self.assertEqual(config['var'], "value_changed")
    # cleanup
    os.environ['RUNNER_CONFIG'] = runner_config_old


594
def main():
595 596 597
  # Empty parser for now - so that erp5testnode is happy when doing --help
  parser = argparse.ArgumentParser()
  parser.parse_args()
598
  unittest.main(module=__name__)
599 600

if __name__ == '__main__':
Marco Mariani's avatar
Marco Mariani committed
601
  main()