Blame view

slapos/runner/runnertest.py 27.1 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
#############################################

Bryton Lacquement committed
13 14
from __future__ import print_function

15
import argparse
Nicolas Wavrant committed
16
import base64
Bryton Lacquement committed
17
from six.moves.configparser import SafeConfigParser
Marco Mariani committed
18
import datetime
Marco Mariani committed
19
import hashlib
Alain Takoudjou committed
20
import json
Marco Mariani committed
21 22
import os
import shutil
Bryton Lacquement committed
23 24
from . import sup_process
from io import StringIO
Nicolas Wavrant committed
25
import ssl
Cédric Le Ninivin committed
26
import time
Marco Mariani committed
27
import unittest
Bryton Lacquement committed
28 29
from six.moves.urllib.request import Request, urlopen
import six
Marco Mariani committed
30

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

42 43
import erp5.util.taskdistribution as taskdistribution

Marco Mariani committed
44

Marco Mariani committed
45 46 47 48
#Helpers
def loadJson(response):
  return json.loads(response.data)

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

  # 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
77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97
  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
98 99 100 101
  parser.add_argument('--project_title',
                      metavar='PROJECT_TITLE',
                      help='The project title')

102 103 104 105 106 107 108 109 110
  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
111

Nicolas Wavrant committed
112
class SlaprunnerTestCase(unittest.TestCase):
Alain Takoudjou committed
113

Nicolas Wavrant committed
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130
  @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()
Bryton Lacquement committed
131
    for attribute, value in six.iteritems(cls.parameter_dict):
Nicolas Wavrant committed
132
      setattr(cls, attribute.replace('-', '_'), value)
Marco Mariani committed
133

Nicolas Wavrant committed
134 135 136 137 138 139 140
    #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
141

Nicolas Wavrant committed
142 143 144
    # Set up path (needed to find git binary)
    os.environ['PATH'] = config.path

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

Nicolas Wavrant committed
155 156 157
    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
158 159
    if not os.path.exists(workdir):
      os.mkdir(workdir)
Alain Takoudjou committed
160 161
    if not os.path.exists(software_link):
      os.mkdir(software_link)
Nicolas Wavrant committed
162

Nicolas Wavrant committed
163 164
    #Create config.json
    json_file = os.path.join(views.app.config['etc_dir'], 'config.json')
Nicolas Wavrant committed
165
    if not os.path.exists(json_file):
Nicolas Wavrant committed
166 167 168 169 170 171 172
      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
173 174 175 176

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

Nicolas Wavrant committed
178 179 180 181
    #reset tested parameters
    self.updateConfigParameter('autorun', False)
    self.updateConfigParameter('auto_deploy', True)

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

Nicolas Wavrant committed
193
  def updateConfigParameter(self, parameter, value):
Bryton Lacquement committed
194
    config_parser = SafeConfigParser()
Nicolas Wavrant committed
195 196 197 198 199 200 201
    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
202

Nicolas Wavrant committed
203
  def updateAccount(self, newaccount):
Alain Takoudjou committed
204
    """Helper for update user account data"""
Marco Mariani committed
205 206 207 208 209 210 211 212
    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
213

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

Cédric Le Ninivin committed
218
  def setupProjectFolder(self):
Marco Mariani committed
219
    """Helper to create a project folder as for slapos.git"""
Alain Takoudjou committed
220 221 222 223
    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
224 225 226 227 228 229 230 231 232 233 234 235 236

  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
237 238 239 240
    sr += """
[versions]
setuptools = 33.1.1
"""
Cédric Le Ninivin committed
241 242 243
    os.mkdir(testSoftware)
    open(os.path.join(testSoftware, self.app.config['software_profile']),
         'w').write(sr)
Alain Takoudjou committed
244
    md5 = hashlib.md5(os.path.join(self.app.config['workspace'],
Marco Mariani committed
245 246 247
                                   "slapos/software/slaprunner-test",
                                   self.app.config['software_profile'])
                      ).hexdigest()
Alain Takoudjou committed
248 249 250 251 252
    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
253
    content += "develop-eggs-directory = %s\n\n" % os.path.join(base, 'develop-eggs')
Alain Takoudjou committed
254 255 256 257 258 259 260
    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
261
  def assertCanLoginWith(self, username, password):
Bryton Lacquement committed
262
    request = Request(self.backend_url)
Nicolas Wavrant committed
263 264 265
    base64string = base64.encodestring('%s:%s' % (username, password))[:-1]
    request.add_header("Authorization", "Basic %s" % base64string)
    ssl_context = ssl._create_unverified_context()
Bryton Lacquement committed
266
    result = urlopen(request, context=ssl_context)
Nicolas Wavrant committed
267
    self.assertEqual(result.getcode(), 200)
Alain Takoudjou committed
268 269

  def test_updateAccount(self):
Marco Mariani committed
270
    """test Update accound, this needs the user to log in"""
Nicolas Wavrant committed
271 272 273 274 275
    # 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
276
    self.assertEqual(response['code'], 1)
Nicolas Wavrant committed
277
    self.assertCanLoginWith(new_user['username'], new_user['password'])
Alain Takoudjou committed
278

Alain Takoudjou committed
279 280 281 282

  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
283 284
    if os.path.exists(self.app.config['workspace'] + '/' + self.project):
      shutil.rmtree(self.app.config['workspace'] + '/' + self.project)
Marco Mariani committed
285 286 287 288 289 290
    data = {
      'repo': self.repo,
      'user': 'Slaprunner test',
      'email': 'slaprunner@nexedi.com',
      'name': folder
    }
Marco Mariani committed
291
    response = loadJson(self.app.post('/cloneRepository', data=data,
Alain Takoudjou committed
292 293
                    follow_redirects=True))
    self.assertEqual(response['result'], "")
Marco Mariani committed
294
    # Get realpath of create project
Alain Takoudjou committed
295
    path_data = dict(file=folder)
Marco Mariani committed
296
    response = loadJson(self.app.post('/getPath', data=path_data,
Alain Takoudjou committed
297 298 299 300
                    follow_redirects=True))
    self.assertEqual(response['code'], 1)
    realFolder = response['result'].split('#')[0]
    #Check git configuration
Marco Mariani committed
301
    config = open(os.path.join(realFolder, '.git/config')).read()
Alain Takoudjou committed
302
    assert "slaprunner@nexedi.com" in config and "Slaprunner test" in config
Marco Mariani committed
303 304

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

  def test_createSR(self):
    """Scenario 2: Create a new software release"""
Alain Takoudjou committed
316 317
    #setup project directory
    self.setupProjectFolder()
Alain Takoudjou committed
318
    newSoftware = os.path.join(self.software, 'slaprunner-test')
Marco Mariani committed
319
    response = loadJson(self.app.post('/createSoftware',
Marco Mariani committed
320 321
                                      data=dict(folder=newSoftware),
                                      follow_redirects=True))
Alain Takoudjou committed
322 323 324 325 326 327 328
    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
329
    software = os.path.join(self.software, 'helloworld')  # Drupal SR must exist in SR folder
Marco Mariani committed
330
    response = loadJson(self.app.post('/setCurrentProject',
Marco Mariani committed
331 332
                                      data=dict(path=software),
                                      follow_redirects=True))
Alain Takoudjou committed
333 334 335 336 337
    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
338

Alain Takoudjou committed
339 340 341 342 343 344 345 346 347 348 349 350

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

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

Alain Takoudjou committed
375 376

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

Alain Takoudjou committed
415 416

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

Alain Takoudjou committed
447

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

Nicolas Wavrant committed
478 479 480 481 482 483 484
  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
485 486
    MAX_RUN_SOFTWARE = getBuildAndRunParams(self.app.config)['max_run_software']
    MAX_RUN_INSTANCE = getBuildAndRunParams(self.app.config)['max_run_instance']
Nicolas Wavrant committed
487 488 489
    self.test_createSR()
    newSoftware = self.getCurrentSR()
    softwareRelease = "[buildout]\n\nparts =\n  test-application\n"
Rafael Monnerat committed
490 491 492
    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
493 494 495
    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
496 497 498 499
    softwareRelease += """
[versions]
setuptools = 33.1.1
"""
Nicolas Wavrant committed
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 534 535 536
    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
537
    parameters = getBuildAndRunParams(self.app.config)
Nicolas Wavrant committed
538
    parameters['run_instance'] = False
Nicolas Wavrant committed
539
    saveBuildAndRunParams(self.app.config, parameters)
Nicolas Wavrant committed
540 541 542
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, 1)
    parameters['run_instance'] = True
Nicolas Wavrant committed
543
    saveBuildAndRunParams(self.app.config, parameters)
Nicolas Wavrant committed
544 545 546
    response = runSlapgridUntilSuccess(self.app.config, 'software')
    self.assertEqual(response, (1, MAX_RUN_INSTANCE))

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

Nicolas Wavrant committed
592 593 594 595 596
  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
597
    config_file = os.path.join(self.app.config['etc_dir'], 'slapos-test.cfg')
Nicolas Wavrant committed
598 599 600 601 602 603 604 605 606 607 608
    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
609
class PrintStringIO(StringIO):
Rafael Monnerat committed
610 611
  def write(self, data):
    StringIO.write(self, data)
Bryton Lacquement committed
612
    print(data)
Rafael Monnerat committed
613

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

Nicolas Wavrant committed
623 624 625 626 627 628 629
  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)

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

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

  start_time = time.time()

Rafael Monnerat committed
641
  stderr = PrintStringIO()
642 643 644 645 646 647 648 649 650 651 652 653 654 655 656
  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."
  """
657
  unittest.main(module=__name__)