Blame view

slapos/runner/runnertest.py 27 KB
Alain Takoudjou committed
1
# -*- coding: utf-8 -*-
Marco Mariani committed
2
# vim: set et sts=2:
Marco Mariani committed
3
# pylint: disable-msg=W0311,C0301,C0103,C0111,R0904
Marco Mariani committed
4

Nicolas Wavrant committed
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
Nicolas Wavrant committed
14
import base64
Alain Takoudjou committed
15
import ConfigParser
Marco Mariani committed
16
import datetime
Marco Mariani committed
17
import hashlib
Alain Takoudjou committed
18
import json
Marco Mariani committed
19 20
import os
import shutil
Nicolas Wavrant committed
21
import sup_process
Rafael Monnerat committed
22
from StringIO import StringIO
Nicolas Wavrant committed
23
import ssl
Cédric Le Ninivin committed
24
import time
Marco Mariani committed
25
import unittest
Nicolas Wavrant committed
26
import urllib2
Marco Mariani committed
27

Nicolas Wavrant committed
28
from slapos.runner.utils import (getProfilePath,
Nicolas Wavrant committed
29
                                 getSession, isInstanceRunning,
Nicolas Wavrant committed
30
                                 isSoftwareRunning, startProxy,
Nicolas Wavrant committed
31
                                 isSoftwareReleaseReady,
Cédric de Saint Martin committed
32
                                 runSlapgridUntilSuccess, runInstanceWithLock,
Nicolas Wavrant committed
33
                                 getBuildAndRunParams, saveBuildAndRunParams)
Marco Mariani committed
34
from slapos.runner import views
Alain Takoudjou committed
35
import slapos.slap
Nicolas Wavrant committed
36
from slapos.htpasswd import  HtpasswdFile
Nicolas Wavrant committed
37
from .run import Config
Marco Mariani committed
38

39 40
import erp5.util.taskdistribution as taskdistribution

Marco Mariani committed
41

Marco Mariani committed
42 43 44 45
#Helpers
def loadJson(response):
  return json.loads(response.data)

46 47 48 49 50
def parseArguments():
  """
  Parse arguments for erp5testnode-backed test.
  """
  parser = argparse.ArgumentParser()
Nicolas Wavrant committed
51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73

  # runnertest mandatory arguments
  parser.add_argument('--key_file',
                      metavar='KEY_FILE',
                      help='Path to the key file used to communicate with slapOS-master')

  parser.add_argument('--cert_file',
                      metavar='CERT_FILE',
                      help='Path to the cert file used to communicate with slapOS-master')

  parser.add_argument('--server_url',
                      metavar='SERVER_URL',
                      help='URL of the local slapproxy')

  parser.add_argument('--computer_id',
                      metavar='COMPUTER_ID',
                      help='ID of the COMP where the slaprunner is running')

  parser.add_argument('--partition_id',
                      metavar='PARTITION_ID',
                      help='ID of the partition where the slaprunner is depoyed')

  # Test Node arguments
74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94
  parser.add_argument('--test_result_path',
                      metavar='ERP5_TEST_RESULT_PATH',
                      help='ERP5 relative path of the test result')

  parser.add_argument('--revision',
                      metavar='REVISION',
                      help='Revision of the test_suite')

  parser.add_argument('--test_suite',
                      metavar='TEST_SUITE',
                      help='Name of the test suite')

  parser.add_argument('--test_suite_title',
                      metavar='TEST_SUITE',
                      help='The test suite title')

  parser.add_argument('--test_node_title',
                      metavar='NODE_TITLE',
                      help='Title of the testnode which is running this'
                            'launcher')

Nicolas Wavrant committed
95 96 97 98
  parser.add_argument('--project_title',
                      metavar='PROJECT_TITLE',
                      help='The project title')

99 100 101 102 103 104 105 106 107
  parser.add_argument('--node_quantity', help='Number of parallel tests to run',
                      default=1, type=int)

  parser.add_argument('--master_url',
                      metavar='TEST_SUITE_MASTER_URL',
                      help='Url to connect to the ERP5 Master testsuite taskditributor')

  return parser.parse_args()

Alain Takoudjou committed
108

Nicolas Wavrant committed
109
class SlaprunnerTestCase(unittest.TestCase):
Alain Takoudjou committed
110

Nicolas Wavrant committed
111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
  @classmethod
  def setUpClass(cls, **kw):
    if len(kw) == 0:
      return
    cls.server_url = kw['server_url']
    cls.key_file = kw['key_file']
    cls.cert_file = kw['cert_file']
    cls.computer_id = kw['computer_id']
    cls.partition_id = kw['partition_id']
    # Get parameters returned by slapos master
    slap = slapos.slap.slap()
    slap.initializeConnection(cls.server_url, cls.key_file, cls.cert_file)
    cls.partition = slap.registerComputerPartition(
      computer_guid=cls.computer_id,
      partition_id=cls.partition_id
    )
    cls.parameter_dict = cls.partition.getConnectionParameterDict()
    for attribute, value in cls.parameter_dict.iteritems():
      setattr(cls, attribute.replace('-', '_'), value)
Marco Mariani committed
130

Nicolas Wavrant committed
131 132 133 134 135 136 137
    #create slaprunner configuration
    views.app.config['TESTING'] = True
    config = Config()
    config.setConfig()
    views.app.config.update(**config.__dict__)
    cls.app = views.app.test_client()
    cls.app.config = views.app.config
Alain Takoudjou committed
138

Nicolas Wavrant committed
139 140 141
    # Set up path (needed to find git binary)
    os.environ['PATH'] = config.path

Alain Takoudjou committed
142 143
  def setUp(self):
    """Initialize slapos webrunner here"""
Nicolas Wavrant committed
144
    self.users = [self.init_user, self.init_password, "slaprunner@nexedi.com", "SlapOS web runner"]
Alain Takoudjou committed
145
    self.updateUser = ["newslapuser", "newslappwd", "slaprunner@nexedi.com", "SlapOS web runner"]
Rafael Monnerat committed
146
    self.repo = 'https://lab.nexedi.com/rafael/slapos-workarround.git'
Marco Mariani committed
147 148
    self.software = "workspace/slapos/software/"  # relative directory fo SR
    self.project = 'slapos'  # Default project name
Alain Takoudjou committed
149 150
    self.template = 'template.cfg'
    self.partitionPrefix = 'slappart'
Alain Takoudjou committed
151

Nicolas Wavrant committed
152 153 154
    self.workdir = workdir = os.path.join(self.app.config['runner_workdir'], 'project')
    software_link = os.path.join(self.app.config['runner_workdir'], 'softwareLink')
    #update or create all runner base directory to test_dir
Alain Takoudjou committed
155 156
    if not os.path.exists(workdir):
      os.mkdir(workdir)
Alain Takoudjou committed
157 158
    if not os.path.exists(software_link):
      os.mkdir(software_link)
Nicolas Wavrant committed
159

Nicolas Wavrant committed
160 161
    #Create config.json
    json_file = os.path.join(views.app.config['etc_dir'], 'config.json')
Nicolas Wavrant committed
162
    if not os.path.exists(json_file):
Nicolas Wavrant committed
163 164 165 166 167 168 169
      params = {
        'run_instance' : True,
        'run_software' : True,
        'max_run_instance' : 3,
        'max_run_software' : 2
      }
      open(json_file, "w").write(json.dumps(params))
Alain Takoudjou committed
170 171 172 173

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

Nicolas Wavrant committed
175 176 177 178
    #reset tested parameters
    self.updateConfigParameter('autorun', False)
    self.updateConfigParameter('auto_deploy', True)

Alain Takoudjou committed
179 180 181 182 183 184 185 186
    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 committed
187 188
    if os.path.exists(self.app.config['software_link']):
      shutil.rmtree(self.app.config['software_link'])
Alain Takoudjou committed
189

Nicolas Wavrant committed
190 191 192 193 194 195 196 197 198
  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)

Alain Takoudjou committed
199

Nicolas Wavrant committed
200
  def updateAccount(self, newaccount):
Alain Takoudjou committed
201
    """Helper for update user account data"""
Marco Mariani committed
202 203 204 205 206 207 208 209
    return self.app.post('/updateAccount',
                         data=dict(
                           username=newaccount[0],
                           password=newaccount[1],
                           email=newaccount[2],
                           name=newaccount[3],
                         ),
                         follow_redirects=True)
Alain Takoudjou committed
210

Alain Takoudjou committed
211 212 213
  def getCurrentSR(self):
   return getProfilePath(self.app.config['etc_dir'],
                              self.app.config['software_profile'])
Cédric Le Ninivin committed
214

Cédric Le Ninivin committed
215
  def setupProjectFolder(self):
Marco Mariani committed
216
    """Helper to create a project folder as for slapos.git"""
Alain Takoudjou committed
217 218 219 220
    base = os.path.join(self.app.config['workspace'], 'slapos')
    software = os.path.join(base, 'software')
    os.mkdir(base)
    os.mkdir(software)
Cédric Le Ninivin committed
221 222 223 224 225 226 227 228 229 230 231 232 233

  def setupTestSoftware(self):
    """Helper to setup Basic SR for testing purposes"""
    self.setupProjectFolder()
    base = os.path.join(self.app.config['workspace'], 'slapos')
    software = os.path.join(base, 'software')
    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"
    sr += "[command]\nrecipe = zc.recipe.egg\neggs = plone.recipe.command\n  zc.buildout\n\n"
Rafael Monnerat committed
234 235 236 237
    sr += """
[versions]
setuptools = 33.1.1
"""
Cédric Le Ninivin committed
238 239 240
    os.mkdir(testSoftware)
    open(os.path.join(testSoftware, self.app.config['software_profile']),
         'w').write(sr)
Alain Takoudjou committed
241
    md5 = hashlib.md5(os.path.join(self.app.config['workspace'],
Marco Mariani committed
242 243 244
                                   "slapos/software/slaprunner-test",
                                   self.app.config['software_profile'])
                      ).hexdigest()
Alain Takoudjou committed
245 246 247 248 249
    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 committed
250
    content += "develop-eggs-directory = %s\n\n" % os.path.join(base, 'develop-eggs')
Alain Takoudjou committed
251 252 253 254 255 256 257
    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)

Nicolas Wavrant committed
258 259 260 261 262 263 264
  def assertCanLoginWith(self, username, password):
    request = urllib2.Request(self.backend_url)
    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
    request.add_header("Authorization", "Basic %s" % base64string)
    ssl_context = ssl._create_unverified_context()
    result = urllib2.urlopen(request, context=ssl_context)
    self.assertEqual(result.getcode(), 200)
Alain Takoudjou committed
265 266

  def test_updateAccount(self):
Marco Mariani committed
267
    """test Update accound, this needs the user to log in"""
Nicolas Wavrant committed
268 269 270 271 272
    # Check that given user can log in
    self.assertCanLoginWith(self.users[0], self.users[1])
    # Adds a user
    new_user = {'username': 'vice-president', 'password': '123456'}
    response = loadJson(self.app.post('/addUser', data=new_user))
Alain Takoudjou committed
273
    self.assertEqual(response['code'], 1)
Nicolas Wavrant committed
274
    self.assertCanLoginWith(new_user['username'], new_user['password'])
Alain Takoudjou committed
275

Alain Takoudjou committed
276 277 278 279

  def test_cloneProject(self):
    """Start scenario 1 for deploying SR: Clone a project from git repository"""
    folder = 'workspace/' + self.project
Cédric Le Ninivin committed
280 281
    if os.path.exists(self.app.config['workspace'] + '/' + self.project):
      shutil.rmtree(self.app.config['workspace'] + '/' + self.project)
Marco Mariani committed
282 283 284 285 286 287
    data = {
      'repo': self.repo,
      'user': 'Slaprunner test',
      'email': 'slaprunner@nexedi.com',
      'name': folder
    }
Marco Mariani committed
288
    response = loadJson(self.app.post('/cloneRepository', data=data,
Alain Takoudjou committed
289 290
                    follow_redirects=True))
    self.assertEqual(response['result'], "")
Marco Mariani committed
291
    # Get realpath of create project
Alain Takoudjou committed
292
    path_data = dict(file=folder)
Marco Mariani committed
293
    response = loadJson(self.app.post('/getPath', data=path_data,
Alain Takoudjou committed
294 295 296 297
                    follow_redirects=True))
    self.assertEqual(response['code'], 1)
    realFolder = response['result'].split('#')[0]
    #Check git configuration
Marco Mariani committed
298
    config = open(os.path.join(realFolder, '.git/config')).read()
Alain Takoudjou committed
299
    assert "slaprunner@nexedi.com" in config and "Slaprunner test" in config
Marco Mariani committed
300 301

    # Checkout to slaprunner branch, this supposes that branch slaprunner exit
Marco Mariani committed
302 303 304 305
    response = loadJson(self.app.post('/newBranch',
                                      data=dict(
                                        project=folder,
                                        create='0',
Nicolas Wavrant committed
306
                                        name='erp5'
Marco Mariani committed
307 308
                                      ),
                                      follow_redirects=True))
Alain Takoudjou committed
309 310 311 312
    self.assertEqual(response['result'], "")

  def test_createSR(self):
    """Scenario 2: Create a new software release"""
Alain Takoudjou committed
313 314
    #setup project directory
    self.setupProjectFolder()
Alain Takoudjou committed
315
    newSoftware = os.path.join(self.software, 'slaprunner-test')
Marco Mariani committed
316
    response = loadJson(self.app.post('/createSoftware',
Marco Mariani committed
317 318
                                      data=dict(folder=newSoftware),
                                      follow_redirects=True))
Alain Takoudjou committed
319 320 321 322 323 324 325
    self.assertEqual(response['result'], "")
    currentSR = self.getCurrentSR()
    assert newSoftware in currentSR

  def test_openSR(self):
    """Scenario 3: Open software release"""
    self.test_cloneProject()
Cédric Le Ninivin committed
326
    software = os.path.join(self.software, 'helloworld')  # Drupal SR must exist in SR folder
Marco Mariani committed
327
    response = loadJson(self.app.post('/setCurrentProject',
Marco Mariani committed
328 329
                                      data=dict(path=software),
                                      follow_redirects=True))
Alain Takoudjou committed
330 331 332 333 334
    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 committed
335

Alain Takoudjou committed
336 337 338 339 340 341 342 343 344 345 346 347

  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"
Rafael Monnerat committed
348
    softwareRelease += "url = https://lab.nexedi.com/rafael/slapos-workarround.git\n" 
Alain Takoudjou committed
349 350
    softwareRelease += "filename = slapos.git\n"
    softwareRelease += "download-only = true\n"
Rafael Monnerat committed
351
    softwareRelease += "[versions]\nsetuptools = 33.1.1"
Alain Takoudjou committed
352
    response = loadJson(self.app.post('/saveFileContent',
Marco Mariani committed
353 354 355
                                      data=dict(file=newSoftware,
                                                content=softwareRelease),
                                      follow_redirects=True))
Alain Takoudjou committed
356
    self.assertEqual(response['result'], "")
Marco Mariani committed
357 358 359

    # Compile software and wait until slapgrid ends
    # this is supposed to use current SR
Nicolas Wavrant committed
360 361 362
    while self.app.get('/isSRReady').data == "2":
      time.sleep(2)
    self.assertEqual(self.app.get('/isSRReady').data, "1")
Alain Takoudjou committed
363 364
    self.assertTrue(os.path.exists(self.app.config['software_root']))
    self.assertTrue(os.path.exists(self.app.config['software_log']))
Marco Mariani committed
365
    assert "test-application" in open(self.app.config['software_log']).read()
Alain Takoudjou committed
366 367 368 369 370
    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))
Nicolas Wavrant committed
371

Alain Takoudjou committed
372 373

  def test_updateInstanceParameter(self):
Nicolas Wavrant committed
374
    """Scenario 5: Update parameters of current sofware profile"""
Cédric Le Ninivin committed
375
    self.setupTestSoftware()
Alain Takoudjou committed
376
    #Set current projet and run Slapgrid-cp
Nicolas Wavrant committed
377
    software = self.software + 'slaprunner-test/'
Alain Takoudjou committed
378
    response = loadJson(self.app.post('/setCurrentProject',
Marco Mariani committed
379 380
                                      data=dict(path=software),
                                      follow_redirects=True))
Alain Takoudjou committed
381 382 383 384 385 386 387
    self.assertEqual(response['result'], "")
    #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 committed
388
    response = loadJson(self.app.post('/saveParameterXml',
Marco Mariani committed
389 390 391
                                      data=dict(parameter=parameterXml,
                                                software_type=software_type),
                                      follow_redirects=True))
Alain Takoudjou committed
392 393 394 395 396 397 398 399
    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 committed
400 401
    self.assertTrue('appname' in slapParameterDict)
    self.assertTrue('cacountry' in slapParameterDict)
Alain Takoudjou committed
402 403 404 405 406
    self.assertEqual(slapParameterDict['appname'], 'slaprunnerTest')
    self.assertEqual(slapParameterDict['cacountry'], 'France')
    self.assertEqual(slapParameterDict['slap_software_type'], 'production')

    #test getParameterXml for webrunner UI
Alain Takoudjou committed
407
    response = loadJson(self.app.get('/getParameterXml/xml'))
Alain Takoudjou committed
408
    self.assertEqual(parameterXml, response['result'])
Alain Takoudjou committed
409
    response = loadJson(self.app.get('/getParameterXml/dict'))
Alain Takoudjou committed
410
    self.assertEqual(parameterDict, response['result']['instance'])
Nicolas Wavrant committed
411

Alain Takoudjou committed
412 413

  def test_requestInstance(self):
Rafael Monnerat committed
414
    """Scenario 6: request software instance"""
Alain Takoudjou committed
415 416
    self.test_updateInstanceParameter()
    #run Software profile
Alain Takoudjou committed
417
    response = loadJson(self.app.post('/runSoftwareProfile',
Marco Mariani committed
418 419
                                      data=dict(),
                                      follow_redirects=True))
Nicolas Wavrant committed
420 421 422
    while self.app.get('/isSRReady').data == "2":
      time.sleep(2)
    self.assertEqual(self.app.get('/isSRReady').data, "1")
Alain Takoudjou committed
423
    #run instance profile
Alain Takoudjou committed
424
    response = loadJson(self.app.post('/runInstanceProfile',
Marco Mariani committed
425 426
                                      data=dict(),
                                      follow_redirects=True))
Alain Takoudjou committed
427
    self.assertTrue(response['result'])
Nicolas Wavrant committed
428 429
    # lets some time to the Instance to be deployed
    time.sleep(5)
Alain Takoudjou committed
430
    #Check that all partitions has been created
Marco Mariani committed
431
    assert "create-file" in open(self.app.config['instance_log']).read()
Alain Takoudjou committed
432 433 434 435 436 437 438 439 440 441 442
    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()
Nicolas Wavrant committed
443

Alain Takoudjou committed
444

Nicolas Wavrant committed
445 446 447 448
  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
Nicolas Wavrant committed
449 450
    self.updateConfigParameter('auto_deploy', False)
    self.updateConfigParameter('autorun', False)
Nicolas Wavrant committed
451 452
    project = open(os.path.join(self.app.config['etc_dir'],
                  '.project'), "w")
Nicolas Wavrant committed
453
    project.write(self.software + 'slaprunner-test/')
Nicolas Wavrant committed
454 455 456 457
    project.close()
    response = isSoftwareReleaseReady(self.app.config)
    self.assertEqual(response, "0")
    # Test if auto_deploy parameter starts the deployment of SR
Nicolas Wavrant committed
458
    self.updateConfigParameter('auto_deploy', True)
Cédric Le Ninivin committed
459
    self.setupTestSoftware()
Nicolas Wavrant committed
460 461 462 463
    response = isSoftwareReleaseReady(self.app.config)
    self.assertEqual(response, "2")
    # Test that the new call to isSoftwareReleaseReady
    # doesn't overwrite the previous installed one
Nicolas Wavrant committed
464
    sup_process.killRunningProcess(self.app.config, 'slapgrid-sr')
Nicolas Wavrant committed
465
    completed_path = os.path.join(self.app.config['runner_workdir'],
Nicolas Wavrant committed
466
        'softwareLink', 'slaprunner-test', '.completed')
Nicolas Wavrant committed
467 468 469 470 471 472 473
    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 committed
474

Nicolas Wavrant committed
475 476 477 478 479 480 481
  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
Nicolas Wavrant committed
482 483
    MAX_RUN_SOFTWARE = getBuildAndRunParams(self.app.config)['max_run_software']
    MAX_RUN_INSTANCE = getBuildAndRunParams(self.app.config)['max_run_instance']
Nicolas Wavrant committed
484 485 486
    self.test_createSR()
    newSoftware = self.getCurrentSR()
    softwareRelease = "[buildout]\n\nparts =\n  test-application\n"
Rafael Monnerat committed
487 488 489
    softwareRelease += "find-links += http://www.nexedi.org/static/packages/source/slapos.buildout/\n\n"
    softwareRelease += "[networkcache]\ndownload-cache-url = http://www.shacache.org/shacache"
    softwareRelease += "\ndownload-dir-url = http://www.shacache.org/shadir\n\n"
Nicolas Wavrant committed
490 491 492
    softwareRelease += "#Test download git web repos éè@: utf-8 caracters\n"
    softwareRelease += "[test-application]\nrecipe = slapos.cookbook:mkdirectory\n"
    softwareRelease += "test = /root/test\n"
Rafael Monnerat committed
493 494 495 496
    softwareRelease += """
[versions]
setuptools = 33.1.1
"""
Nicolas Wavrant committed
497 498 499 500 501 502 503 504 505 506 507 508 509 510 511 512 513 514 515 516 517 518 519 520 521 522 523 524 525 526 527 528 529 530 531 532 533
    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
Nicolas Wavrant committed
534
    parameters = getBuildAndRunParams(self.app.config)
Nicolas Wavrant committed
535
    parameters['run_instance'] = False
Nicolas Wavrant committed
536
    saveBuildAndRunParams(self.app.config, parameters)
Nicolas Wavrant committed
537 538 539
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, 1)
    parameters['run_instance'] = True
Nicolas Wavrant committed
540
    saveBuildAndRunParams(self.app.config, parameters)
Nicolas Wavrant committed
541 542 543
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, (1, MAX_RUN_INSTANCE))

Cédric de Saint Martin committed
544 545 546 547 548 549 550 551 552 553 554 555 556 557 558 559 560
  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(
Nicolas Wavrant committed
561
                                        project=self.workdir+'/slapos',
Cédric de Saint Martin committed
562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584 585 586 587
                                        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)

Nicolas Wavrant committed
588

Nicolas Wavrant committed
589 590 591 592 593
  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.
    """
Nicolas Wavrant committed
594
    config_file = os.path.join(self.app.config['etc_dir'], 'slapos-test.cfg')
Nicolas Wavrant committed
595 596 597 598 599 600 601 602 603 604 605
    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


Rafael Monnerat committed
606
class PrintStringIO(StringIO):
Rafael Monnerat committed
607 608 609 610
  def write(self, data):
    StringIO.write(self, data)
    print data

Alain Takoudjou committed
611
def main():
612 613 614 615
  """
  Function meant to be run by erp5testnode.
  """
  args = parseArguments()
Rafael Monnerat committed
616
  master = taskdistribution.TaskDistributor(args.master_url)
617 618 619
  test_suite_title = args.test_suite_title or args.test_suite
  revision = args.revision

Nicolas Wavrant committed
620 621 622 623 624 625 626
  SlaprunnerTestCase.setUpClass(
    key_file=args.key_file,
    cert_file=args.cert_file,
    server_url=args.server_url,
    computer_id=args.computer_id,
    partition_id=args.partition_id)

627
  test_result = master.createTestResult(revision, [test_suite_title],
Nicolas Wavrant committed
628
    args.test_node_title, True, test_suite_title, args.project_title)
Rafael Monnerat committed
629 630 631 632 633

  if test_result is None:
    # Thereis nothing to run here, all tests are been running by
    # some other node.
    return
634 635 636 637
  test_line = test_result.start()

  start_time = time.time()

Rafael Monnerat committed
638
  stderr = PrintStringIO()
639 640 641 642 643 644 645 646 647 648 649 650 651 652 653
  suite = unittest.TestLoader().loadTestsFromTestCase(SlaprunnerTestCase)
  test_result = unittest.TextTestRunner(verbosity=2, stream=stderr).run(suite)

  test_duration = time.time() - start_time
  test_line.stop(stderr=stderr.getvalue(),
                  test_count=test_result.testsRun,
                  error_count=len(test_result.errors),
                  failure_count=len(test_result.failures) + len(test_result.unexpectedSuccesses),
                  skip_count=len(test_result.skipped),
                  duration=test_duration)

def runStandaloneUnitTest():
  """
  Run unit tests without erp5testnode."
  """
654
  unittest.main(module=__name__)